Ident.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2019 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 "comm.h"
15 #include "comm/Connection.h"
16 #include "comm/ConnOpener.h"
17 #include "comm/Read.h"
18 #include "comm/Write.h"
19 #include "CommCalls.h"
20 #include "globals.h"
21 #include "ident/Config.h"
22 #include "ident/Ident.h"
23 #include "MemBuf.h"
24 
25 namespace Ident
26 {
27 
28 #define IDENT_PORT 113
29 #define IDENT_KEY_SZ 50
30 #define IDENT_BUFSIZE 4096
31 
32 typedef struct _IdentClient {
35 
36  struct _IdentClient *next;
37 } IdentClient;
38 
40 {
41 public:
42  hash_link hash; /* must be first */
43 private:
45 
46 public:
47  /* AsyncJob API emulated */
48  void deleteThis(const char *aReason);
49  void swanSong();
50 
52  void notify(const char *result);
53 
58 };
59 
61 
62 // TODO: make these all a series of Async job calls. They are self-contained callbacks now.
63 static IOCB ReadReply;
65 static CLCB Close;
66 static CTCB Timeout;
69 static void ClientAdd(IdentStateData * state, IDCB * callback, void *callback_data);
70 
71 } // namespace Ident
72 
74 
75 void
77 {
78  swanSong();
79  delete this;
80 }
81 
82 void
84 {
85  if (clients != NULL)
86  notify(NULL);
87 
88  if (Comm::IsConnOpen(conn)) {
90  conn->close();
91  }
92 
94  xfree(hash.key);
95 }
96 
97 void
98 Ident::IdentStateData::notify(const char *result)
99 {
100  while (IdentClient *client = clients) {
101  void *cbdata;
102  clients = client->next;
103 
104  if (cbdataReferenceValidDone(client->callback_data, &cbdata))
105  client->callback(result, cbdata);
106 
107  xfree(client);
108  }
109 }
110 
111 void
112 Ident::Close(const CommCloseCbParams &params)
113 {
114  IdentStateData *state = (IdentStateData *)params.data;
115  state->deleteThis("connection closed");
116 }
117 
118 void
120 {
121  debugs(30, 3, HERE << io.conn);
122  IdentStateData *state = (IdentStateData *)io.data;
123  state->deleteThis("timeout");
124 }
125 
126 void
127 Ident::ConnectDone(const Comm::ConnectionPointer &conn, Comm::Flag status, int, void *data)
128 {
129  IdentStateData *state = (IdentStateData *)data;
130 
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");
135  return;
136  }
137 
138  /*
139  * see if any of our clients still care
140  */
141  IdentClient *c;
142  for (c = state->clients; c; c = c->next) {
144  break;
145  }
146 
147  if (c == NULL) {
148  state->deleteThis("client(s) aborted");
149  return;
150  }
151 
152  assert(conn != NULL && conn == state->conn);
153  comm_add_close_handler(conn->fd, Ident::Close, state);
154 
155  AsyncCall::Pointer writeCall = commCbCall(5,4, "Ident::WriteFeedback",
157  Comm::Write(conn, &state->queryMsg, writeCall);
158  AsyncCall::Pointer readCall = commCbCall(5,4, "Ident::ReadReply",
160  comm_read(conn, state->buf, IDENT_BUFSIZE, readCall);
161  AsyncCall::Pointer timeoutCall = commCbCall(5,4, "Ident::Timeout",
163  commSetConnTimeout(conn, Ident::TheConfig.timeout, timeoutCall);
164 }
165 
166 void
167 Ident::WriteFeedback(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int xerrno, void *data)
168 {
169  debugs(30, 5, HERE << conn << ": Wrote IDENT request " << len << " bytes.");
170 
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");
176  }
177 }
178 
179 void
180 Ident::ReadReply(const Comm::ConnectionPointer &conn, char *buf, size_t len, Comm::Flag flag, int, void *data)
181 {
182  IdentStateData *state = (IdentStateData *)data;
183  char *ident = NULL;
184  char *t = NULL;
185 
186  assert(buf == state->buf);
187  assert(conn->fd == state->conn->fd);
188 
189  if (flag != Comm::OK || len <= 0) {
190  state->deleteThis("read error");
191  return;
192  }
193 
194  /*
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
198  */
199  buf[len] = '\0';
200 
201  if ((t = strchr(buf, '\r')))
202  *t = '\0';
203 
204  if ((t = strchr(buf, '\n')))
205  *t = '\0';
206 
207  debugs(30, 5, HERE << conn << ": Read '" << buf << "'");
208 
209  if (strstr(buf, "USERID")) {
210  if ((ident = strrchr(buf, ':'))) {
211  while (xisspace(*++ident));
212  if (ident && *ident == '\0')
213  ident = NULL;
214  state->notify(ident);
215  }
216  }
217 
218  state->deleteThis("completed");
219 }
220 
221 void
223 {
224  IdentClient *c = (IdentClient *)xcalloc(1, sizeof(*c));
225  IdentClient **C;
226  c->callback = callback;
227  c->callback_data = cbdataReference(callback_data);
228 
229  for (C = &state->clients; *C; C = &(*C)->next);
230  *C = c;
231 }
232 
233 /*
234  * start a TCP connection to the peer host on port 113
235  */
236 void
238 {
239  IdentStateData *state;
240  char key1[IDENT_KEY_SZ];
241  char key2[IDENT_KEY_SZ];
242  char key[IDENT_KEY_SZ*2+2]; // key1 + ',' + key2 + terminator
243 
244  conn->local.toUrl(key1, IDENT_KEY_SZ);
245  conn->remote.toUrl(key2, IDENT_KEY_SZ);
246  const auto res = snprintf(key, sizeof(key), "%s,%s", key1, key2);
247  assert(res > 0);
248  assert(static_cast<std::make_unsigned<decltype(res)>::type>(res) < sizeof(key));
249 
250  if (!ident_hash) {
251  Init();
252  }
253  if ((state = (IdentStateData *)hash_lookup(ident_hash, key)) != NULL) {
254  ClientAdd(state, callback, data);
255  return;
256  }
257 
258  state = new IdentStateData;
259  state->hash.key = xstrdup(key);
260 
261  // copy the conn details. We do not want the original FD to be re-used by IDENT.
262  state->conn = conn->copyDetails();
263  // NP: use random port for secure outbound to IDENT_PORT
264  state->conn->local.port(0);
265  state->conn->remote.port(IDENT_PORT);
266 
267  // build our query from the original connection details
268  state->queryMsg.init();
269  state->queryMsg.appendf("%d, %d\r\n", conn->remote.port(), conn->local.port());
270 
271  ClientAdd(state, callback, data);
272  hash_join(ident_hash, &state->hash);
273 
274  AsyncCall::Pointer call = commCbCall(30,3, "Ident::ConnectDone", CommConnectCbPtrFun(Ident::ConnectDone, state));
275  AsyncJob::Start(new Comm::ConnOpener(state->conn, call, Ident::TheConfig.timeout));
276 }
277 
278 void
280 {
281  if (ident_hash) {
282  debugs(30, DBG_CRITICAL, "WARNING: Ident already initialized.");
283  return;
284  }
285 
286  ident_hash = hash_create((HASHCMP *) strcmp,
287  hashPrime(Squid_MaxFD / 8),
288  hash4);
289 }
290 
291 #endif /* USE_IDENT */
292 
#define cbdataReferenceValidDone(var, ptr)
Definition: cbdata.h:256
IdentConfig TheConfig
Definition: Ident.cc:73
Ident Lookup API.
Definition: Config.h:16
void Init(void)
Definition: Ident.cc:279
unsigned short port() const
Definition: Address.cc:778
#define assert(EX)
Definition: assert.h:17
int Squid_MaxFD
Definition: cbdata.cc:60
IdentClient * clients
Definition: Ident.cc:56
void CTCB(const CommTimeoutCbParams &params)
Definition: CommCalls.h:39
static uint32 C
Definition: md4.c:43
int type
Definition: errorpage.cc:152
void notify(const char *result)
notify all waiting IdentClient callbacks
Definition: Ident.cc:98
#define xcalloc
Definition: membanger.c:57
time_t timeout
Definition: Config.h:23
#define xstrdup
#define IDENT_PORT
Definition: Ident.cc:28
Definition: Flag.h:16
SQUIDCEXTERN void hash_join(hash_table *, hash_link *)
Definition: hash.cc:132
#define xisspace(x)
Definition: xis.h:17
#define DBG_CRITICAL
Definition: Debug.h:45
static IOCB WriteFeedback
Definition: Ident.cc:64
struct _IdentClient * next
Definition: Ident.cc:36
static CNCB ConnectDone
Definition: Ident.cc:67
char * toUrl(char *buf, unsigned int len) const
Definition: Address.cc:884
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:96
static Pointer Start(AsyncJob *job)
starts a freshly created job (i.e., makes the job asynchronous)
Definition: AsyncJob.cc:23
static CLCB Close
Definition: Ident.cc:65
Comm::ConnectionPointer conn
Definition: CommCalls.h:85
const char * xstrerr(int error)
Definition: xstrerror.cc:83
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:24
void const char HLPCB void * data
Definition: stub_helper.cc:16
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
#define cbdataReference(var)
Definition: cbdata.h:341
MemBuf queryMsg
the lookup message sent to IDENT server
Definition: Ident.cc:55
static hash_table * hash
Definition: text_backend.cc:41
static hash_table * ident_hash
Definition: Ident.cc:68
SQUIDCEXTERN hash_link * hash_lookup(hash_table *, const void *)
Definition: hash.cc:147
ConnectionPointer copyDetails() const
Definition: Connection.cc:57
void comm_read(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer &callback)
Definition: Read.h:59
void * callback_data
Definition: Ident.cc:34
#define CBDATA_CLASS(type)
Definition: cbdata.h:302
SQUIDCEXTERN hash_table * hash_create(HASHCMP *, int, HASHHASH *)
Definition: hash.cc:109
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
#define IDENT_KEY_SZ
Definition: Ident.cc:29
void CLCB(const CommCloseCbParams &params)
Definition: CommCalls.h:42
CBDATA_CLASS_INIT(IdentStateData)
void const char * buf
Definition: stub_helper.cc:16
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:153
void IOCB(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag flag, int xerrno, void *data)
Definition: CommCalls.h:36
void deleteThis(const char *aReason)
Definition: Ident.cc:76
Flag
Definition: Flag.h:15
Ip::Address local
Definition: Connection.h:135
static CTCB Timeout
Definition: Ident.cc:66
SQUIDCEXTERN int hashPrime(int n)
Definition: hash.cc:297
Ip::Address remote
Definition: Connection.h:138
struct Ident::_IdentClient IdentClient
void IDCB(const char *ident, void *data)
Definition: Ident.h:17
#define IDENT_BUFSIZE
Definition: Ident.cc:30
char buf[IDENT_BUFSIZE]
Definition: Ident.cc:57
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
SQUIDCEXTERN void hash_remove_link(hash_table *, hash_link *)
Definition: hash.cc:224
Definition: MemBuf.h:23
void CNCB(const Comm::ConnectionPointer &conn, Comm::Flag status, int xerrno, void *data)
Definition: CommCalls.h:35
CommCbFunPtrCallT< Dialer > * commCbCall(int debugSection, int debugLevel, const char *callName, const Dialer &dialer)
Definition: CommCalls.h:342
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:412
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:961
static IOCB ReadReply
Definition: Ident.cc:63
SQUIDCEXTERN HASHHASH hash4
Definition: hash.h:46
hash_link hash
Definition: Ident.cc:42
static void ClientAdd(IdentStateData *state, IDCB *callback, void *callback_data)
Definition: Ident.cc:222
void comm_remove_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:988
#define xfree
int commSetConnTimeout(const Comm::ConnectionPointer &conn, int timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:552
IDCB * callback
Definition: Ident.cc:33
#define NULL
Definition: types.h:166
Comm::ConnectionPointer conn
Definition: Ident.cc:54
void Start(const Comm::ConnectionPointer &conn, IDCB *callback, void *cbdata)
Definition: Ident.cc:237
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition: Write.cc:35
int HASHCMP(const void *, const void *)
Definition: hash.h:13

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors