Ident.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3  *
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.
7  */
8 
9 /* DEBUG: section 30 Ident (RFC 931) */
10 
11 #include "squid.h"
12 
13 #if USE_IDENT
14 #include "base/JobWait.h"
15 #include "comm.h"
16 #include "comm/Connection.h"
17 #include "comm/ConnOpener.h"
18 #include "comm/Read.h"
19 #include "comm/Write.h"
20 #include "CommCalls.h"
21 #include "globals.h"
22 #include "ident/Config.h"
23 #include "ident/Ident.h"
24 #include "MemBuf.h"
25 
26 namespace Ident
27 {
28 
29 #define IDENT_PORT 113
30 #define IDENT_KEY_SZ 50
31 #define IDENT_BUFSIZE 4096
32 
33 typedef struct _IdentClient {
36 
37  struct _IdentClient *next;
39 
41 {
42 public:
43  hash_link hash; /* must be first */
44 private:
46 
47 public:
48  /* AsyncJob API emulated */
49  void deleteThis(const char *aReason);
50  void swanSong();
51 
53  void notify(const char *result);
54 
57  IdentClient *clients = nullptr;
59 
62 
63 private:
64  // use deleteThis() to destroy
66 };
67 
69 
70 // TODO: make these all a series of Async job calls. They are self-contained callbacks now.
71 static IOCB ReadReply;
73 static CLCB Close;
74 static CTCB Timeout;
77 static void ClientAdd(IdentStateData * state, IDCB * callback, void *callback_data);
78 
79 } // namespace Ident
80 
82 
83 void
85 {
86  debugs(30, 3, reason);
87  swanSong();
88  delete this;
89 }
90 
91 void
93 {
94  if (clients != NULL)
95  notify(NULL);
96 }
97 
99  assert(!clients);
100 
101  if (Comm::IsConnOpen(conn)) {
103  conn->close();
104  }
105 
107  xfree(hash.key);
108 }
109 
110 void
111 Ident::IdentStateData::notify(const char *result)
112 {
113  while (IdentClient *client = clients) {
114  void *cbdata;
115  clients = client->next;
116 
117  if (cbdataReferenceValidDone(client->callback_data, &cbdata))
118  client->callback(result, cbdata);
119 
120  xfree(client);
121  }
122 }
123 
124 void
125 Ident::Close(const CommCloseCbParams &params)
126 {
127  IdentStateData *state = (IdentStateData *)params.data;
128  if (state->conn) {
129  state->conn->noteClosure();
130  state->conn = nullptr;
131  }
132  state->deleteThis("connection closed");
133 }
134 
135 void
137 {
138  debugs(30, 3, HERE << io.conn);
139  IdentStateData *state = (IdentStateData *)io.data;
140  state->deleteThis("timeout");
141 }
142 
143 void
144 Ident::ConnectDone(const Comm::ConnectionPointer &conn, Comm::Flag status, int, void *data)
145 {
146  IdentStateData *state = (IdentStateData *)data;
147  state->connWait.finish();
148 
149  // Start owning the supplied connection (so that it is not orphaned if this
150  // function bails early). As a (tiny) optimization or perhaps just diff
151  // minimization, the close handler is added later, when we know we are not
152  // bailing. This delay is safe because comm_remove_close_handler() forgives
153  // missing handlers.
154  assert(conn); // but may be closed
155  assert(!state->conn);
156  state->conn = conn;
157 
158  if (status != Comm::OK) {
159  if (status == Comm::TIMEOUT)
160  debugs(30, 3, "IDENT connection timeout to " << state->conn->remote);
161  state->deleteThis(status == Comm::TIMEOUT ? "connect timeout" : "connect error");
162  return;
163  }
164 
165  /*
166  * see if any of our clients still care
167  */
168  IdentClient *c;
169  for (c = state->clients; c; c = c->next) {
170  if (cbdataReferenceValid(c->callback_data))
171  break;
172  }
173 
174  if (c == NULL) {
175  state->deleteThis("client(s) aborted");
176  return;
177  }
178 
179  assert(state->conn->isOpen());
180  comm_add_close_handler(state->conn->fd, Ident::Close, state);
181 
182  AsyncCall::Pointer writeCall = commCbCall(5,4, "Ident::WriteFeedback",
184  Comm::Write(conn, &state->queryMsg, writeCall);
185  AsyncCall::Pointer readCall = commCbCall(5,4, "Ident::ReadReply",
187  comm_read(conn, state->buf, IDENT_BUFSIZE, readCall);
188  AsyncCall::Pointer timeoutCall = commCbCall(5,4, "Ident::Timeout",
190  commSetConnTimeout(conn, Ident::TheConfig.timeout, timeoutCall);
191 }
192 
193 void
194 Ident::WriteFeedback(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int xerrno, void *data)
195 {
196  debugs(30, 5, HERE << conn << ": Wrote IDENT request " << len << " bytes.");
197 
198  // TODO handle write errors better. retry or abort?
199  if (flag != Comm::OK) {
200  debugs(30, 2, HERE << conn << " err-flags=" << flag << " IDENT write error: " << xstrerr(xerrno));
201  IdentStateData *state = (IdentStateData *)data;
202  state->deleteThis("write error");
203  }
204 }
205 
206 void
207 Ident::ReadReply(const Comm::ConnectionPointer &conn, char *buf, size_t len, Comm::Flag flag, int, void *data)
208 {
209  IdentStateData *state = (IdentStateData *)data;
210  char *ident = NULL;
211  char *t = NULL;
212 
213  assert(buf == state->buf);
214  assert(conn->fd == state->conn->fd);
215 
216  if (flag != Comm::OK || len <= 0) {
217  state->deleteThis("read error");
218  return;
219  }
220 
221  /*
222  * XXX This isn't really very tolerant. It should read until EOL
223  * or EOF and then decode the answer... If the reply is fragmented
224  * then this will fail
225  */
226  buf[len] = '\0';
227 
228  if ((t = strchr(buf, '\r')))
229  *t = '\0';
230 
231  if ((t = strchr(buf, '\n')))
232  *t = '\0';
233 
234  debugs(30, 5, HERE << conn << ": Read '" << buf << "'");
235 
236  if (strstr(buf, "USERID")) {
237  if ((ident = strrchr(buf, ':'))) {
238  while (xisspace(*++ident));
239  if (ident && *ident == '\0')
240  ident = NULL;
241  state->notify(ident);
242  }
243  }
244 
245  state->deleteThis("completed");
246 }
247 
248 void
249 Ident::ClientAdd(IdentStateData * state, IDCB * callback, void *callback_data)
250 {
251  IdentClient *c = (IdentClient *)xcalloc(1, sizeof(*c));
252  IdentClient **C;
253  c->callback = callback;
254  c->callback_data = cbdataReference(callback_data);
255 
256  for (C = &state->clients; *C; C = &(*C)->next);
257  *C = c;
258 }
259 
260 /*
261  * start a TCP connection to the peer host on port 113
262  */
263 void
264 Ident::Start(const Comm::ConnectionPointer &conn, IDCB * callback, void *data)
265 {
266  IdentStateData *state;
267  char key1[IDENT_KEY_SZ];
268  char key2[IDENT_KEY_SZ];
269  char key[IDENT_KEY_SZ*2+2]; // key1 + ',' + key2 + terminator
270 
271  conn->local.toUrl(key1, IDENT_KEY_SZ);
272  conn->remote.toUrl(key2, IDENT_KEY_SZ);
273  int res = snprintf(key, sizeof(key), "%s,%s", key1, key2);
274  assert(res > 0);
275  assert(static_cast<unsigned int>(res) < sizeof(key));
276 
277  if (!ident_hash) {
278  Init();
279  }
280  if ((state = (IdentStateData *)hash_lookup(ident_hash, key)) != NULL) {
281  ClientAdd(state, callback, data);
282  return;
283  }
284 
285  state = new IdentStateData;
286  state->hash.key = xstrdup(key);
287 
288  // copy the conn details. We do not want the original FD to be re-used by IDENT.
289  const auto identConn = conn->cloneProfile();
290  // NP: use random port for secure outbound to IDENT_PORT
291  identConn->local.port(0);
292  identConn->remote.port(IDENT_PORT);
293 
294  // build our query from the original connection details
295  state->queryMsg.init();
296  state->queryMsg.appendf("%d, %d\r\n", conn->remote.port(), conn->local.port());
297 
298  ClientAdd(state, callback, data);
299  hash_join(ident_hash, &state->hash);
300 
301  AsyncCall::Pointer call = commCbCall(30,3, "Ident::ConnectDone", CommConnectCbPtrFun(Ident::ConnectDone, state));
302  const auto connOpener = new Comm::ConnOpener(identConn, call, Ident::TheConfig.timeout);
303  state->connWait.start(connOpener, call);
304 }
305 
306 void
308 {
309  if (ident_hash) {
310  debugs(30, DBG_CRITICAL, "WARNING: Ident already initialized.");
311  return;
312  }
313 
314  ident_hash = hash_create((HASHCMP *) strcmp,
315  hashPrime(Squid_MaxFD / 8),
316  hash4);
317 }
318 
319 #endif /* USE_IDENT */
320 
const char * xstrerr(int error)
Definition: xstrerror.cc:83
struct _IdentClient * next
Definition: Ident.cc:37
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:922
SQUIDCEXTERN HASHHASH hash4
Definition: hash.h:46
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
IDCB * callback
Definition: Ident.cc:34
void deleteThis(const char *aReason)
Definition: Ident.cc:84
#define cbdataReferenceValidDone(var, ptr)
Definition: cbdata.h:256
void notify(const char *result)
notify all waiting IdentClient callbacks
Definition: Ident.cc:111
static CLCB Close
Definition: Ident.cc:73
void * callback_data
Definition: Ident.cc:35
SQUIDCEXTERN void hash_remove_link(hash_table *, hash_link *)
Definition: hash.cc:220
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:95
char buf[IDENT_BUFSIZE]
Definition: Ident.cc:58
int commSetConnTimeout(const Comm::ConnectionPointer &conn, int timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:564
#define xstrdup
@ TIMEOUT
Definition: Flag.h:19
Definition: cbdata.cc:60
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:398
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:27
@ OK
Definition: Flag.h:16
static CNCB ConnectDone
Definition: Ident.cc:75
int HASHCMP(const void *, const void *)
Definition: hash.h:13
#define DBG_CRITICAL
Definition: Debug.h:40
void CLCB(const CommCloseCbParams &params)
Definition: CommCalls.h:42
Ident Lookup API.
Definition: Config.h:17
SQUIDCEXTERN void hash_join(hash_table *, hash_link *)
Definition: hash.cc:131
#define cbdataReference(var)
Definition: cbdata.h:341
static CTCB Timeout
Definition: Ident.cc:74
#define IDENT_KEY_SZ
Definition: Ident.cc:30
IdentConfig TheConfig
Definition: Ident.cc:81
void CNCB(const Comm::ConnectionPointer &conn, Comm::Flag status, int xerrno, void *data)
Definition: CommCalls.h:35
void comm_read(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer &callback)
Definition: Read.h:59
MemBuf queryMsg
the lookup message sent to IDENT server
Definition: Ident.cc:56
void Init(void)
Definition: Ident.cc:307
#define NULL
Definition: types.h:166
void CTCB(const CommTimeoutCbParams &params)
Definition: CommCalls.h:39
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
static void ClientAdd(IdentStateData *state, IDCB *callback, void *callback_data)
Definition: Ident.cc:249
#define IDENT_PORT
Definition: Ident.cc:29
Definition: MemBuf.h:24
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:152
void IOCB(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag flag, int xerrno, void *data)
Definition: CommCalls.h:36
Comm::ConnectionPointer conn
Definition: CommCalls.h:85
CBDATA_CLASS(IdentStateData)
CommCbFunPtrCallT< Dialer > * commCbCall(int debugSection, int debugLevel, const char *callName, const Dialer &dialer)
Definition: CommCalls.h:342
int conn
the current server connection FD
Definition: Transport.cc:26
#define assert(EX)
Definition: assert.h:19
static IOCB WriteFeedback
Definition: Ident.cc:72
static uint32 C
Definition: md4.c:43
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition: Write.cc:34
static hash_table * hash
Definition: text_backend.cc:41
hash_link hash
Definition: Ident.cc:43
int Squid_MaxFD
#define xfree
CBDATA_CLASS_INIT(IdentStateData)
Flag
Definition: Flag.h:15
void IDCB(const char *ident, void *data)
Definition: Ident.h:17
void start(const JobPointer &aJob, const AsyncCall::Pointer &aCallback)
starts waiting for the given job to call the given callback
Definition: JobWait.h:69
struct Ident::_IdentClient IdentClient
Comm::ConnectionPointer conn
Definition: Ident.cc:55
IdentClient * clients
Definition: Ident.cc:57
static IOCB ReadReply
Definition: Ident.cc:71
JobWait< Comm::ConnOpener > connWait
waits for a connection to the IDENT server to be established/opened
Definition: Ident.cc:61
#define IDENT_BUFSIZE
Definition: Ident.cc:31
SQUIDCEXTERN hash_table * hash_create(HASHCMP *, int, HASHHASH *)
Definition: hash.cc:108
void Start(const Comm::ConnectionPointer &conn, IDCB *callback, void *cbdata)
Definition: Ident.cc:264
#define xisspace(x)
Definition: xis.h:17
SQUIDCEXTERN hash_link * hash_lookup(hash_table *, const void *)
Definition: hash.cc:146
SQUIDCEXTERN int hashPrime(int n)
Definition: hash.cc:293
static hash_table * ident_hash
Definition: Ident.cc:76
void comm_remove_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:949

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors