]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ident/Ident.cc
2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 30 Ident (RFC 931) */
15 #include "comm/Connection.h"
16 #include "comm/ConnOpener.h"
17 #include "comm/Read.h"
18 #include "comm/Write.h"
19 #include "CommCalls.h"
21 #include "ident/Config.h"
22 #include "ident/Ident.h"
28 #define IDENT_PORT 113
29 #define IDENT_KEY_SZ 50
30 #define IDENT_BUFSIZE 4096
32 typedef struct _IdentClient
{
36 struct _IdentClient
*next
;
42 hash_link hash
; /* must be first */
44 CBDATA_CLASS(IdentStateData
);
47 /* AsyncJob API emulated */
48 void deleteThis(const char *aReason
);
51 /// notify all waiting IdentClient callbacks
52 void notify(const char *result
);
54 Comm::ConnectionPointer conn
;
55 MemBuf queryMsg
; ///< the lookup message sent to IDENT server
57 char buf
[IDENT_BUFSIZE
];
60 CBDATA_CLASS_INIT(IdentStateData
);
62 // TODO: make these all a series of Async job calls. They are self-contained callbacks now.
63 static IOCB ReadReply
;
64 static IOCB WriteFeedback
;
67 static CNCB ConnectDone
;
68 static hash_table
*ident_hash
= NULL
;
69 static void ClientAdd(IdentStateData
* state
, IDCB
* callback
, void *callback_data
);
73 Ident::IdentConfig
Ident::TheConfig
;
76 Ident::IdentStateData::deleteThis(const char *aReason
)
83 Ident::IdentStateData::swanSong()
88 if (Comm::IsConnOpen(conn
)) {
89 comm_remove_close_handler(conn
->fd
, Ident::Close
, this);
93 hash_remove_link(ident_hash
, (hash_link
*) this);
98 Ident::IdentStateData::notify(const char *result
)
100 while (IdentClient
*client
= clients
) {
102 clients
= client
->next
;
104 if (cbdataReferenceValidDone(client
->callback_data
, &cbdata
))
105 client
->callback(result
, cbdata
);
112 Ident::Close(const CommCloseCbParams
¶ms
)
114 IdentStateData
*state
= (IdentStateData
*)params
.data
;
115 state
->deleteThis("connection closed");
119 Ident::Timeout(const CommTimeoutCbParams
&io
)
121 debugs(30, 3, HERE
<< io
.conn
);
122 IdentStateData
*state
= (IdentStateData
*)io
.data
;
123 state
->deleteThis("timeout");
127 Ident::ConnectDone(const Comm::ConnectionPointer
&conn
, Comm::Flag status
, int xerrno
, void *data
)
129 IdentStateData
*state
= (IdentStateData
*)data
;
131 if (status
!= Comm::OK
) {
132 if (status
== Comm::TIMEOUT
)
133 debugs(30, 3, "IDENT connection timeout to " << state
->conn
->remote
);
134 state
->deleteThis(status
== Comm::TIMEOUT
? "connect timeout" : "connect error");
139 * see if any of our clients still care
142 for (c
= state
->clients
; c
; c
= c
->next
) {
143 if (cbdataReferenceValid(c
->callback_data
))
148 state
->deleteThis("client(s) aborted");
152 assert(conn
!= NULL
&& conn
== state
->conn
);
153 comm_add_close_handler(conn
->fd
, Ident::Close
, state
);
155 AsyncCall::Pointer writeCall
= commCbCall(5,4, "Ident::WriteFeedback",
156 CommIoCbPtrFun(Ident::WriteFeedback
, state
));
157 Comm::Write(conn
, &state
->queryMsg
, writeCall
);
158 AsyncCall::Pointer readCall
= commCbCall(5,4, "Ident::ReadReply",
159 CommIoCbPtrFun(Ident::ReadReply
, state
));
160 comm_read(conn
, state
->buf
, IDENT_BUFSIZE
, readCall
);
161 AsyncCall::Pointer timeoutCall
= commCbCall(5,4, "Ident::Timeout",
162 CommTimeoutCbPtrFun(Ident::Timeout
, state
));
163 commSetConnTimeout(conn
, Ident::TheConfig
.timeout
, timeoutCall
);
167 Ident::WriteFeedback(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
169 debugs(30, 5, HERE
<< conn
<< ": Wrote IDENT request " << len
<< " bytes.");
171 // TODO handle write errors better. retry or abort?
172 if (flag
!= Comm::OK
) {
173 debugs(30, 2, HERE
<< conn
<< " err-flags=" << flag
<< " IDENT write error: " << xstrerr(xerrno
));
174 IdentStateData
*state
= (IdentStateData
*)data
;
175 state
->deleteThis("write error");
180 Ident::ReadReply(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
182 IdentStateData
*state
= (IdentStateData
*)data
;
186 assert(buf
== state
->buf
);
187 assert(conn
->fd
== state
->conn
->fd
);
189 if (flag
!= Comm::OK
|| len
<= 0) {
190 state
->deleteThis("read error");
195 * XXX This isn't really very tolerant. It should read until EOL
196 * or EOF and then decode the answer... If the reply is fragmented
197 * then this will fail
201 if ((t
= strchr(buf
, '\r')))
204 if ((t
= strchr(buf
, '\n')))
207 debugs(30, 5, HERE
<< conn
<< ": Read '" << buf
<< "'");
209 if (strstr(buf
, "USERID")) {
210 if ((ident
= strrchr(buf
, ':'))) {
211 while (xisspace(*++ident
));
212 if (ident
&& *ident
== '\0')
214 state
->notify(ident
);
218 state
->deleteThis("completed");
222 Ident::ClientAdd(IdentStateData
* state
, IDCB
* callback
, void *callback_data
)
224 IdentClient
*c
= (IdentClient
*)xcalloc(1, sizeof(*c
));
226 c
->callback
= callback
;
227 c
->callback_data
= cbdataReference(callback_data
);
229 for (C
= &state
->clients
; *C
; C
= &(*C
)->next
);
234 * start a TCP connection to the peer host on port 113
237 Ident::Start(const Comm::ConnectionPointer
&conn
, IDCB
* callback
, void *data
)
239 IdentStateData
*state
;
240 char key1
[IDENT_KEY_SZ
];
241 char key2
[IDENT_KEY_SZ
];
242 char key
[IDENT_KEY_SZ
];
244 conn
->local
.toUrl(key1
, IDENT_KEY_SZ
);
245 conn
->remote
.toUrl(key2
, IDENT_KEY_SZ
);
246 snprintf(key
, IDENT_KEY_SZ
, "%s,%s", key1
, key2
);
251 if ((state
= (IdentStateData
*)hash_lookup(ident_hash
, key
)) != NULL
) {
252 ClientAdd(state
, callback
, data
);
256 state
= new IdentStateData
;
257 state
->hash
.key
= xstrdup(key
);
259 // copy the conn details. We dont want the original FD to be re-used by IDENT.
260 state
->conn
= conn
->copyDetails();
261 // NP: use random port for secure outbound to IDENT_PORT
262 state
->conn
->local
.port(0);
263 state
->conn
->remote
.port(IDENT_PORT
);
265 // build our query from the original connection details
266 state
->queryMsg
.init();
267 state
->queryMsg
.Printf("%d, %d\r\n", conn
->remote
.port(), conn
->local
.port());
269 ClientAdd(state
, callback
, data
);
270 hash_join(ident_hash
, &state
->hash
);
272 AsyncCall::Pointer call
= commCbCall(30,3, "Ident::ConnectDone", CommConnectCbPtrFun(Ident::ConnectDone
, state
));
273 AsyncJob::Start(new Comm::ConnOpener(state
->conn
, call
, Ident::TheConfig
.timeout
));
280 debugs(30, DBG_CRITICAL
, "WARNING: Ident already initialized.");
284 ident_hash
= hash_create((HASHCMP
*) strcmp
,
285 hashPrime(Squid_MaxFD
/ 8),
289 #endif /* USE_IDENT */