]>
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
;
39 typedef struct _IdentStateData
{
40 hash_link hash
; /* must be first */
41 Comm::ConnectionPointer conn
;
42 MemBuf queryMsg
; ///< the lookup message sent to IDENT server
44 char buf
[IDENT_BUFSIZE
];
47 // TODO: make these all a series of Async job calls. They are self-contained callbacks now.
48 static IOCB ReadReply
;
49 static IOCB WriteFeedback
;
52 static CNCB ConnectDone
;
53 static hash_table
*ident_hash
= NULL
;
54 static void ClientAdd(IdentStateData
* state
, IDCB
* callback
, void *callback_data
);
55 static void identCallback(IdentStateData
* state
, char *result
);
59 Ident::IdentConfig
Ident::TheConfig
;
61 /**** PRIVATE FUNCTIONS ****/
64 Ident::identCallback(IdentStateData
* state
, char *result
)
68 if (result
&& *result
== '\0')
71 while ((client
= state
->clients
)) {
73 state
->clients
= client
->next
;
75 if (cbdataReferenceValidDone(client
->callback_data
, &cbdata
))
76 client
->callback(result
, cbdata
);
83 Ident::Close(const CommCloseCbParams
¶ms
)
85 IdentStateData
*state
= (IdentStateData
*)params
.data
;
86 identCallback(state
, NULL
);
88 hash_remove_link(ident_hash
, (hash_link
*) state
);
89 xfree(state
->hash
.key
);
94 Ident::Timeout(const CommTimeoutCbParams
&io
)
96 debugs(30, 3, HERE
<< io
.conn
);
101 Ident::ConnectDone(const Comm::ConnectionPointer
&conn
, Comm::Flag status
, int xerrno
, void *data
)
103 IdentStateData
*state
= (IdentStateData
*)data
;
105 if (status
!= Comm::OK
) {
106 if (status
== Comm::TIMEOUT
)
107 debugs(30, 3, "IDENT connection timeout to " << state
->conn
->remote
);
108 Ident::identCallback(state
, NULL
);
112 assert(conn
!= NULL
&& conn
== state
->conn
);
115 * see if any of our clients still care
118 for (c
= state
->clients
; c
; c
= c
->next
) {
119 if (cbdataReferenceValid(c
->callback_data
))
124 /* no clients care */
129 comm_add_close_handler(conn
->fd
, Ident::Close
, state
);
131 AsyncCall::Pointer writeCall
= commCbCall(5,4, "Ident::WriteFeedback",
132 CommIoCbPtrFun(Ident::WriteFeedback
, state
));
133 Comm::Write(conn
, &state
->queryMsg
, writeCall
);
134 AsyncCall::Pointer readCall
= commCbCall(5,4, "Ident::ReadReply",
135 CommIoCbPtrFun(Ident::ReadReply
, state
));
136 comm_read(conn
, state
->buf
, IDENT_BUFSIZE
, readCall
);
137 AsyncCall::Pointer timeoutCall
= commCbCall(5,4, "Ident::Timeout",
138 CommTimeoutCbPtrFun(Ident::Timeout
, state
));
139 commSetConnTimeout(conn
, Ident::TheConfig
.timeout
, timeoutCall
);
143 Ident::WriteFeedback(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
145 debugs(30, 5, HERE
<< conn
<< ": Wrote IDENT request " << len
<< " bytes.");
147 // TODO handle write errors better. retry or abort?
148 if (flag
!= Comm::OK
) {
149 debugs(30, 2, HERE
<< conn
<< " err-flags=" << flag
<< " IDENT write error: " << xstrerr(xerrno
));
155 Ident::ReadReply(const Comm::ConnectionPointer
&conn
, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
157 IdentStateData
*state
= (IdentStateData
*)data
;
161 assert(buf
== state
->buf
);
162 assert(conn
->fd
== state
->conn
->fd
);
164 if (flag
!= Comm::OK
|| len
<= 0) {
165 state
->conn
->close();
170 * XXX This isn't really very tolerant. It should read until EOL
171 * or EOF and then decode the answer... If the reply is fragmented
172 * then this will fail
176 if ((t
= strchr(buf
, '\r')))
179 if ((t
= strchr(buf
, '\n')))
182 debugs(30, 5, HERE
<< conn
<< ": Read '" << buf
<< "'");
184 if (strstr(buf
, "USERID")) {
185 if ((ident
= strrchr(buf
, ':'))) {
186 while (xisspace(*++ident
));
187 Ident::identCallback(state
, ident
);
191 state
->conn
->close();
195 Ident::ClientAdd(IdentStateData
* state
, IDCB
* callback
, void *callback_data
)
197 IdentClient
*c
= (IdentClient
*)xcalloc(1, sizeof(*c
));
199 c
->callback
= callback
;
200 c
->callback_data
= cbdataReference(callback_data
);
202 for (C
= &state
->clients
; *C
; C
= &(*C
)->next
);
206 CBDATA_TYPE(IdentStateData
);
208 /**** PUBLIC FUNCTIONS ****/
211 * start a TCP connection to the peer host on port 113
214 Ident::Start(const Comm::ConnectionPointer
&conn
, IDCB
* callback
, void *data
)
216 IdentStateData
*state
;
217 char key1
[IDENT_KEY_SZ
];
218 char key2
[IDENT_KEY_SZ
];
219 char key
[IDENT_KEY_SZ
];
221 conn
->local
.toUrl(key1
, IDENT_KEY_SZ
);
222 conn
->remote
.toUrl(key2
, IDENT_KEY_SZ
);
223 snprintf(key
, IDENT_KEY_SZ
, "%s,%s", key1
, key2
);
228 if ((state
= (IdentStateData
*)hash_lookup(ident_hash
, key
)) != NULL
) {
229 ClientAdd(state
, callback
, data
);
233 CBDATA_INIT_TYPE(IdentStateData
);
234 state
= cbdataAlloc(IdentStateData
);
235 state
->hash
.key
= xstrdup(key
);
237 // copy the conn details. We dont want the original FD to be re-used by IDENT.
238 state
->conn
= conn
->copyDetails();
239 // NP: use random port for secure outbound to IDENT_PORT
240 state
->conn
->local
.port(0);
241 state
->conn
->remote
.port(IDENT_PORT
);
243 // build our query from the original connection details
244 state
->queryMsg
.init();
245 state
->queryMsg
.Printf("%d, %d\r\n", conn
->remote
.port(), conn
->local
.port());
247 ClientAdd(state
, callback
, data
);
248 hash_join(ident_hash
, &state
->hash
);
250 AsyncCall::Pointer call
= commCbCall(30,3, "Ident::ConnectDone", CommConnectCbPtrFun(Ident::ConnectDone
, state
));
251 AsyncJob::Start(new Comm::ConnOpener(state
->conn
, call
, Ident::TheConfig
.timeout
));
258 debugs(30, DBG_CRITICAL
, "WARNING: Ident already initialized.");
262 ident_hash
= hash_create((HASHCMP
*) strcmp
,
263 hashPrime(Squid_MaxFD
/ 8),
267 #endif /* USE_IDENT */