ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/auth.c
(Generate patch)

Comparing:
ircd-hybrid-7.2/src/s_auth.c (file contents), Revision 650 by michael, Thu Jun 8 07:00:17 2006 UTC vs.
ircd-hybrid/trunk/src/auth.c (file contents), Revision 4859 by michael, Fri Nov 7 17:19:38 2014 UTC

# Line 1 | Line 1
1   /*
2 < *  ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 < *  s_auth.c: Functions for querying a users ident.
2 > *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3   *
4 < *  Copyright (C) 2002 by the past and present ircd coders, and others.
4 > *  Copyright (c) 1997-2014 ircd-hybrid development team
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 16 | Line 15
15   *
16   *  You should have received a copy of the GNU General Public License
17   *  along with this program; if not, write to the Free Software
18 < *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18 > *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19   *  USA
20 < *
21 < *  $Id$
20 > */
21 >
22 > /*! \file auth.c
23 > * \brief Functions for querying a users ident.
24 > * \version $Id$
25   */
26  
27   /*
# Line 32 | Line 34
34   *     any messages from it.
35   *     --Bleep  Thomas Helvey <tomh@inxpress.net>
36   */
37 +
38   #include "stdinc.h"
36 #include "tools.h"
39   #include "list.h"
40 < #include "s_auth.h"
41 < #include "s_conf.h"
40 > #include "ircd_defs.h"
41 > #include "fdlist.h"
42 > #include "auth.h"
43 > #include "conf.h"
44   #include "client.h"
41 #include "common.h"
45   #include "event.h"
43 #include "fdlist.h"              /* fdlist_add */
44 #include "hook.h"
46   #include "irc_string.h"
46 #include "sprintf_irc.h"
47   #include "ircd.h"
48 #include "numeric.h"
48   #include "packet.h"
49 < #include "irc_res.h"
49 > #include "res.h"
50   #include "s_bsd.h"
51 < #include "s_log.h"
53 < #include "s_stats.h"
51 > #include "log.h"
52   #include "send.h"
53 < #include "memory.h"
53 > #include "mempool.h"
54 >
55  
56 < static const char *HeaderMessages[] = {
57 <  ":%s NOTICE AUTH :*** Looking up your hostname...",
58 <  ":%s NOTICE AUTH :*** Found your hostname",
59 <  ":%s NOTICE AUTH :*** Couldn't look up your hostname",
60 <  ":%s NOTICE AUTH :*** Checking Ident",
61 <  ":%s NOTICE AUTH :*** Got Ident response",
62 <  ":%s NOTICE AUTH :*** No Ident response",
63 <  ":%s NOTICE AUTH :*** Your forward and reverse DNS do not match, ignoring hostname.",
64 <  ":%s NOTICE AUTH :*** Your hostname is too long, ignoring hostname"
56 > static const char *const HeaderMessages[] =
57 > {
58 >  ":*** Looking up your hostname",
59 >  ":*** Found your hostname",
60 >  ":*** Couldn't look up your hostname",
61 >  ":*** Checking Ident",
62 >  ":*** Got Ident response",
63 >  ":*** No Ident response",
64 >  ":*** Your forward and reverse DNS do not match, ignoring hostname",
65 >  ":*** Your hostname is too long, ignoring hostname"
66   };
67  
68 < enum {
68 > enum
69 > {
70    REPORT_DO_DNS,
71    REPORT_FIN_DNS,
72    REPORT_FAIL_DNS,
# Line 76 | Line 77 | enum {
77    REPORT_HOST_TOOLONG
78   };
79  
80 < #define sendheader(c, i) sendto_one((c), HeaderMessages[(i)], me.name)
80 <
81 < /*
82 < * Ok, the original was confusing.
83 < * Now there are two lists, an auth request can be on both at the same time
84 < * or only on one or the other.
85 < * - Dianora
86 < */
87 < static dlink_list auth_doing_dns_list   = { NULL, NULL, 0 };
88 < static dlink_list auth_doing_ident_list = { NULL, NULL, 0 };
80 > #define sendheader(c, i) sendto_one_notice((c), &me, HeaderMessages[(i)])
81  
82 < static EVH timeout_auth_queries_event;
82 > static dlink_list auth_pending_list;
83 > static void read_auth_reply(fde_t *, void *);
84 > static void auth_connect_callback(fde_t *, int, void *);
85  
92 static PF read_auth_reply;
93 static CNCB auth_connect_callback;
94 static CBFUNC start_auth;
95
96 struct Callback *auth_cb = NULL;
97
98 /* init_auth()
99 *
100 * Initialise the auth code
101 */
102 void
103 init_auth(void)
104 {
105  auth_cb = register_callback("start_auth", start_auth);
106  eventAddIsh("timeout_auth_queries_event", timeout_auth_queries_event, NULL, 1);
107 }
86  
87   /*
88   * make_auth_request - allocate a new auth request
# Line 112 | Line 90 | init_auth(void)
90   static struct AuthRequest *
91   make_auth_request(struct Client *client)
92   {
93 <  struct AuthRequest *request = MyMalloc(sizeof(struct AuthRequest));
93 >  struct AuthRequest *const request = &client->connection->auth;
94 >
95 >  memset(request, 0, sizeof(*request));
96  
97    request->client  = client;
98    request->timeout = CurrentTime + CONNECTTIMEOUT;
# Line 126 | Line 106 | make_auth_request(struct Client *client)
106   * the main io processing loop
107   */
108   void
109 < release_auth_client(struct Client *client)
109 > release_auth_client(struct AuthRequest *auth)
110   {
111 +  struct Client *const client = auth->client;
112 +
113 +  if (IsDoingAuth(auth) || IsDNSPending(auth))
114 +    return;
115 +
116 +  if (IsInAuth(auth))
117 +  {
118 +    dlinkDelete(&auth->node, &auth_pending_list);
119 +    ClearInAuth(auth);
120 +  }
121 +
122    /*
123     * When a client has auth'ed, we want to start reading what it sends
124     * us. This is what read_packet() does.
125     *     -- adrian
126     */
127 <  client->localClient->allow_read = MAX_FLOOD;
128 <  comm_setflush(&client->localClient->fd, 1000, flood_recalc, client);
138 <
139 <  if ((client->node.prev != NULL) || (client->node.next != NULL))
140 <  {
141 <    sendto_realops_flags(UMODE_ALL, L_OPER,
142 <                         "already linked %s at %s:%d", client->name,
143 <                         __FILE__, __LINE__);
144 <    ilog(L_ERROR, "already linked %s at %s:%d", client->name,
145 <         __FILE__, __LINE__);
146 <    assert(0==5);
147 <  }
148 <  else
149 <    dlinkAdd(client, &client->node, &global_client_list);
127 >  client->connection->allow_read = MAX_FLOOD;
128 >  comm_setflush(&client->connection->fd, 1000, flood_recalc, client);
129  
130 <  client_p->since  = client_p->lasttime = client_p->firsttime = CurrentTime;
131 <  client_p->flags |= FLAGS_FINISHED_AUTH;
130 >  client->connection->since     = CurrentTime;
131 >  client->connection->lasttime  = CurrentTime;
132 >  client->connection->firsttime = CurrentTime;
133 >  client->flags |= FLAGS_FINISHED_AUTH;
134  
135 <  read_packet(&client->localClient->fd, client);
135 >  read_packet(&client->connection->fd, client);
136   }
137 <
137 >
138   /*
139   * auth_dns_callback - called when resolver query finishes
140 < * if the query resulted in a successful search, hp will contain
141 < * a non-null pointer, otherwise hp will be null.
140 > * if the query resulted in a successful search, name will contain
141 > * a non-NULL pointer, otherwise name will be NULL.
142   * set the client on it's way to a connection completion, regardless
143   * of success of failure
144   */
145   static void
146 < auth_dns_callback(void *vptr, struct DNSReply *reply)
146 > auth_dns_callback(void *vptr, const struct irc_ssaddr *addr, const char *name, size_t namelength)
147   {
148 <  struct AuthRequest *auth = (struct AuthRequest *)vptr;
148 >  struct AuthRequest *const auth = vptr;
149  
169  dlinkDelete(&auth->dns_node, &auth_doing_dns_list);
150    ClearDNSPending(auth);
151  
152 <  if (reply != NULL)
152 >  if (!EmptyString(name))
153    {
154 <    struct sockaddr_in *v4, *v4dns;
175 < #ifdef IPV6
176 <    struct sockaddr_in6 *v6, *v6dns;
177 < #endif
178 <    int good = 1;
179 <
180 < #ifdef IPV6
181 <    if (auth->client->localClient->ip.ss.ss_family == AF_INET6)
154 >    if (auth->client->connection->ip.ss.ss_family == AF_INET6)
155      {
156 <      v6 = (struct sockaddr_in6 *)&auth->client->localClient->ip;
157 <      v6dns = (struct sockaddr_in6 *)&reply->addr;
156 >      const struct sockaddr_in6 *const v6 = (const struct sockaddr_in6 *)&auth->client->connection->ip;
157 >      const struct sockaddr_in6 *const v6dns = (const struct sockaddr_in6 *)addr;
158 >
159        if (memcmp(&v6->sin6_addr, &v6dns->sin6_addr, sizeof(struct in6_addr)) != 0)
160        {
161          sendheader(auth->client, REPORT_IP_MISMATCH);
162 <        good = 0;
162 >        release_auth_client(auth);
163 >        return;
164        }
165      }
166      else
192 #endif
167      {
168 <      v4 = (struct sockaddr_in *)&auth->client->localClient->ip;
169 <      v4dns = (struct sockaddr_in *)&reply->addr;
170 <      if(v4->sin_addr.s_addr != v4dns->sin_addr.s_addr)
168 >      const struct sockaddr_in *const v4 = (const struct sockaddr_in *)&auth->client->connection->ip;
169 >      const struct sockaddr_in *const v4dns = (const struct sockaddr_in *)addr;
170 >
171 >      if (v4->sin_addr.s_addr != v4dns->sin_addr.s_addr)
172        {
173          sendheader(auth->client, REPORT_IP_MISMATCH);
174 <        good = 0;
174 >        release_auth_client(auth);
175 >        return;
176        }
177      }
178 <    if (good && strlen(reply->h_name) <= HOSTLEN)
178 >
179 >    if (namelength > HOSTLEN)
180 >      sendheader(auth->client, REPORT_HOST_TOOLONG);
181 >    else
182      {
183 <      strlcpy(auth->client->host, reply->h_name,
205 <              sizeof(auth->client->host));
183 >      strlcpy(auth->client->host, name, sizeof(auth->client->host));
184        sendheader(auth->client, REPORT_FIN_DNS);
185      }
208    else if (strlen(reply->h_name) > HOSTLEN)
209      sendheader(auth->client, REPORT_HOST_TOOLONG);
186    }
187    else
188 <      sendheader(auth->client, REPORT_FAIL_DNS);
188 >    sendheader(auth->client, REPORT_FAIL_DNS);
189  
190 <  MyFree(auth->client->localClient->dns_query);
215 <  auth->client->localClient->dns_query = NULL;
216 <
217 <  if (!IsDoingAuth(auth))
218 <  {
219 <    struct Client *client_p = auth->client;
220 <    MyFree(auth);
221 <    release_auth_client(client_p);
222 <  }
190 >  release_auth_client(auth);
191   }
192  
193   /*
# Line 228 | Line 196 | auth_dns_callback(void *vptr, struct DNS
196   static void
197   auth_error(struct AuthRequest *auth)
198   {
199 <  ++ServerStats->is_abad;
199 >  ++ServerStats.is_abad;
200  
201    fd_close(&auth->fd);
202  
235  dlinkDelete(&auth->ident_node, &auth_doing_ident_list);
203    ClearAuth(auth);
204  
205    sendheader(auth->client, REPORT_FAIL_ID);
206  
207 <  if (!IsDNSPending(auth) && !IsCrit(auth))
241 <  {
242 <    release_auth_client(auth->client);
243 <    MyFree(auth);
244 <  }
207 >  release_auth_client(auth);
208   }
209  
210   /*
211 < * start_auth_query - Flag the client to show that an attempt to
211 > * start_auth_query - Flag the client to show that an attempt to
212   * contact the ident server on
213   * the client's host.  The connect and subsequently the socket are all put
214   * into 'non-blocking' mode.  Should the connect or any later phase of the
# Line 257 | Line 220 | start_auth_query(struct AuthRequest *aut
220   {
221    struct irc_ssaddr localaddr;
222    socklen_t locallen = sizeof(struct irc_ssaddr);
260 #ifdef IPV6
223    struct sockaddr_in6 *v6;
262 #else
263  struct sockaddr_in *v4;
264 #endif
224  
225    /* open a socket of the same type as the client socket */
226 <  if (comm_open(&auth->fd, auth->client->localClient->ip.ss.ss_family,
226 >  if (comm_open(&auth->fd, auth->client->connection->ip.ss.ss_family,
227                  SOCK_STREAM, 0, "ident") == -1)
228    {
229 <    report_error(L_ALL, "creating auth stream socket %s:%s",
230 <        get_client_name(auth->client, SHOW_IP), errno);
231 <    ilog(L_ERROR, "Unable to create auth socket for %s",
273 <        get_client_name(auth->client, SHOW_IP));
274 <    ++ServerStats->is_abad;
229 >    report_error(L_ALL, "creating auth stream socket %s:%s",
230 >                 get_client_name(auth->client, SHOW_IP), errno);
231 >    ++ServerStats.is_abad;
232      return 0;
233    }
234  
235    sendheader(auth->client, REPORT_DO_ID);
236  
237 <  /*
237 >  /*
238     * get the local address of the client and bind to that to
239     * make the auth request.  This used to be done only for
240     * ifdef VIRTUAL_HOST, but needs to be done for all clients
# Line 285 | Line 242 | start_auth_query(struct AuthRequest *aut
242     * and machines with multiple IP addresses are common now
243     */
244    memset(&localaddr, 0, locallen);
245 <  getsockname(auth->client->localClient->fd.fd, (struct sockaddr*)&localaddr,
245 >  getsockname(auth->client->connection->fd.fd, (struct sockaddr*)&localaddr,
246        &locallen);
247  
291 #ifdef IPV6
248    remove_ipv6_mapping(&localaddr);
249    v6 = (struct sockaddr_in6 *)&localaddr;
250    v6->sin6_port = htons(0);
295 #else
296  localaddr.ss_len = locallen;
297  v4 = (struct sockaddr_in *)&localaddr;
298  v4->sin_port = htons(0);
299 #endif
251    localaddr.ss_port = htons(0);
252  
253 <  SetDoingAuth(auth);
254 <  dlinkAdd(auth, &auth->ident_node, &auth_doing_ident_list);
255 <
305 <  comm_connect_tcp(&auth->fd, auth->client->sockhost, 113,
306 <      (struct sockaddr *)&localaddr, localaddr.ss_len, auth_connect_callback,
307 <      auth, auth->client->localClient->ip.ss.ss_family,
253 >  comm_connect_tcp(&auth->fd, auth->client->sockhost, RFC1413_PORT,
254 >      (struct sockaddr *)&localaddr, localaddr.ss_len, auth_connect_callback,
255 >      auth, auth->client->connection->ip.ss.ss_family,
256        GlobalSetOptions.ident_timeout);
257    return 1; /* We suceed here for now */
258   }
259  
260   /*
261 < * GetValidIdent - parse ident query reply from identd server
314 < *
315 < * Inputs        - pointer to ident buf
316 < * Output        - NULL if no valid ident found, otherwise pointer to name
317 < * Side effects  -
318 < */
319 < /*
320 < * A few questions have been asked about this mess, obviously
321 < * it should have been commented better the first time.
322 < * The original idea was to remove all references to libc from ircd-hybrid.
323 < * Instead of having to write a replacement for sscanf(), I did a
324 < * rather gruseome parser here so we could remove this function call.
325 < * Note, that I had also removed a few floating point printfs as well (though
326 < * now we are still stuck with a few...)
327 < * Remember, we have a replacement ircd sprintf, we have bleeps fputs lib
328 < * it would have been nice to remove some unneeded code.
329 < * Oh well. If we don't remove libc stuff totally, then it would be
330 < * far cleaner to use sscanf()
331 < *
332 < * - Dianora
333 < */
334 < static char *
335 < GetValidIdent(char *buf)
336 < {
337 <  int   remp = 0;
338 <  int   locp = 0;
339 <  char* colon1Ptr;
340 <  char* colon2Ptr;
341 <  char* colon3Ptr;
342 <  char* commaPtr;
343 <  char* remotePortString;
344 <
345 <  /* All this to get rid of a sscanf() fun. */
346 <  remotePortString = buf;
347 <  
348 <  if ((colon1Ptr = strchr(remotePortString,':')) == NULL)
349 <    return 0;
350 <  *colon1Ptr = '\0';
351 <  colon1Ptr++;
352 <
353 <  if ((colon2Ptr = strchr(colon1Ptr,':')) == NULL)
354 <    return 0;
355 <  *colon2Ptr = '\0';
356 <  colon2Ptr++;
357 <  
358 <  if ((commaPtr = strchr(remotePortString, ',')) == NULL)
359 <    return 0;
360 <  *commaPtr = '\0';
361 <  commaPtr++;
362 <
363 <  if ((remp = atoi(remotePortString)) == 0)
364 <    return 0;
365 <              
366 <  if ((locp = atoi(commaPtr)) == 0)
367 <    return 0;
368 <
369 <  /* look for USERID bordered by first pair of colons */
370 <  if (strstr(colon1Ptr, "USERID") == NULL)
371 <    return 0;
372 <
373 <  if ((colon3Ptr = strchr(colon2Ptr,':')) == NULL)
374 <    return 0;
375 <  *colon3Ptr = '\0';
376 <  colon3Ptr++;
377 <  return (colon3Ptr);
378 < }
379 <
380 < /*
381 < * start_auth
261 > * start_auth
262   *
263   * inputs       - pointer to client to auth
264   * output       - NONE
265   * side effects - starts auth (identd) and dns queries for a client
266   */
267 < static void *
268 < start_auth(va_list args)
267 > void
268 > start_auth(struct Client *client_p)
269   {
270 <  struct Client *client = va_arg(args, struct Client *);
391 <  struct AuthRequest *auth = NULL;
392 <
393 <  assert(client != NULL);
270 >  struct AuthRequest *const auth = make_auth_request(client_p);
271  
272 <  auth = make_auth_request(client);
273 <  SetCrit(auth);
272 >  SetInAuth(auth);
273 >  dlinkAddTail(auth, &auth->node, &auth_pending_list);
274  
275 <  client->localClient->dns_query = MyMalloc(sizeof(struct DNSQuery));
399 <  client->localClient->dns_query->ptr = auth;
400 <  client->localClient->dns_query->callback = auth_dns_callback;
275 >  sendheader(client_p, REPORT_DO_DNS);
276  
277 <  sendheader(client, REPORT_DO_DNS);
277 >  SetDNSPending(auth);
278  
279 <  if (ConfigFileEntry.disable_auth == 0)
279 >  if (ConfigGeneral.disable_auth == 0)
280 >  {
281 >    SetDoingAuth(auth);
282      start_auth_query(auth);
283 +  }
284  
285 <  /* auth order changed, before gethost_byaddr can immediately call
408 <   * dns callback under win32 when the lookup cannot be started.
409 <   * And that would do MyFree(auth) etc -adx */
410 <  SetDNSPending(auth);
411 <  dlinkAdd(auth, &auth->dns_node, &auth_doing_dns_list);
412 <  ClearCrit(auth);
413 <  gethost_byaddr(&client->localClient->ip, client->localClient->dns_query);
414 <
415 <  return NULL;
285 >  gethost_byaddr(auth_dns_callback, auth, &client_p->connection->ip);
286   }
287  
288   /*
# Line 422 | Line 292 | start_auth(va_list args)
292   static void
293   timeout_auth_queries_event(void *notused)
294   {
295 <  dlink_node *ptr;
426 <  dlink_node *next_ptr;
427 <  struct AuthRequest* auth;
295 >  dlink_node *node = NULL, *node_next = NULL;
296  
297 <  DLINK_FOREACH_SAFE(ptr, next_ptr, auth_doing_ident_list.head)
297 >  DLINK_FOREACH_SAFE(node, node_next, auth_pending_list.head)
298    {
299 <    auth = ptr->data;
299 >    struct AuthRequest *auth = node->data;
300  
301 <    if (auth->timeout <= CurrentTime)
301 >    if (auth->timeout > CurrentTime)
302 >      break;
303 >
304 >    if (IsDoingAuth(auth))
305      {
306 +      ++ServerStats.is_abad;
307        fd_close(&auth->fd);
308 <
437 <      ++ServerStats->is_abad;
308 >      ClearAuth(auth);
309        sendheader(auth->client, REPORT_FAIL_ID);
310 +    }
311  
312 <      if (IsDNSPending(auth))
313 <      {
314 <        struct Client *client_p = auth->client;
315 <
316 <        dlinkDelete(&auth->dns_node, &auth_doing_dns_list);
445 <        if (client_p->localClient->dns_query != NULL)
446 <        {
447 <          delete_resolver_queries(client_p->localClient->dns_query);
448 <          MyFree(client_p->localClient->dns_query);
449 <        }
450 <        auth->client->localClient->dns_query = NULL;
451 <        sendheader(client_p, REPORT_FAIL_DNS);
452 <      }
453 <
454 <      ilog(L_INFO, "DNS/AUTH timeout %s",
455 <           get_client_name(auth->client, SHOW_IP));
456 <
457 <      dlinkDelete(&auth->ident_node, &auth_doing_ident_list);
458 <      release_auth_client(auth->client);
459 <      MyFree(auth);
312 >    if (IsDNSPending(auth))
313 >    {
314 >      delete_resolver_queries(auth);
315 >      ClearDNSPending(auth);
316 >      sendheader(auth->client, REPORT_FAIL_DNS);
317      }
318 +
319 +    release_auth_client(auth);
320    }
321   }
322  
# Line 478 | Line 337 | auth_connect_callback(fde_t *fd, int err
337    struct AuthRequest *auth = data;
338    struct irc_ssaddr us;
339    struct irc_ssaddr them;
340 <  char authbuf[32];
340 >  char authbuf[16];
341    socklen_t ulen = sizeof(struct irc_ssaddr);
342    socklen_t tlen = sizeof(struct irc_ssaddr);
343 <  u_int16_t uport, tport;
485 < #ifdef IPV6
343 >  uint16_t uport, tport;
344    struct sockaddr_in6 *v6;
487 #else
488  struct sockaddr_in *v4;
489 #endif
345  
346    if (error != COMM_OK)
347    {
# Line 494 | Line 349 | auth_connect_callback(fde_t *fd, int err
349      return;
350    }
351  
352 <  if (getsockname(auth->client->localClient->fd.fd, (struct sockaddr *) &us,
353 <      (socklen_t *) &ulen) ||
499 <      getpeername(auth->client->localClient->fd.fd, (struct sockaddr *) &them,
500 <      (socklen_t *) &tlen))
352 >  if (getsockname(auth->client->connection->fd.fd, (struct sockaddr *)&us, &ulen) ||
353 >      getpeername(auth->client->connection->fd.fd, (struct sockaddr *)&them, &tlen))
354    {
355 <    ilog(L_INFO, "auth get{sock,peer}name error for %s",
356 <        get_client_name(auth->client, SHOW_IP));
355 >    ilog(LOG_TYPE_IRCD, "auth get{sock,peer}name error for %s",
356 >         get_client_name(auth->client, SHOW_IP));
357      auth_error(auth);
358      return;
359    }
360  
508 #ifdef IPV6
361    v6 = (struct sockaddr_in6 *)&us;
362    uport = ntohs(v6->sin6_port);
363    v6 = (struct sockaddr_in6 *)&them;
364    tport = ntohs(v6->sin6_port);
365    remove_ipv6_mapping(&us);
366    remove_ipv6_mapping(&them);
367 < #else
368 <  v4 = (struct sockaddr_in *)&us;
517 <  uport = ntohs(v4->sin_port);
518 <  v4 = (struct sockaddr_in *)&them;
519 <  tport = ntohs(v4->sin_port);
520 <  us.ss_len = ulen;
521 <  them.ss_len = tlen;
522 < #endif
523 <  
524 <  ircsprintf(authbuf, "%u , %u\r\n", tport, uport);
367 >
368 >  snprintf(authbuf, sizeof(authbuf), "%u, %u\r\n", tport, uport);
369  
370    if (send(fd->fd, authbuf, strlen(authbuf), 0) == -1)
371    {
372      auth_error(auth);
373      return;
374    }
375 <  read_auth_reply(&auth->fd, auth);
375 >
376 >  comm_setselect(fd, COMM_SELECT_READ, read_auth_reply, auth, 0);
377 > }
378 >
379 > /** Enum used to index ident reply fields in a human-readable way. */
380 > enum IdentReplyFields
381 > {
382 >  IDENT_PORT_NUMBERS,
383 >  IDENT_REPLY_TYPE,
384 >  IDENT_OS_TYPE,
385 >  IDENT_INFO,
386 >  USERID_TOKEN_COUNT
387 > };
388 >
389 > /** Parse an ident reply line and extract the userid from it.
390 > * \param reply The ident reply line.
391 > * \return The userid, or NULL on parse failure.
392 > */
393 > static const char *
394 > check_ident_reply(char *reply)
395 > {
396 >  char *token = NULL, *end = NULL;
397 >  char *vector[USERID_TOKEN_COUNT];
398 >  int count = token_vector(reply, ':', vector, USERID_TOKEN_COUNT);
399 >
400 >  if (USERID_TOKEN_COUNT != count)
401 >    return NULL;
402 >
403 >  /*
404 >   * Second token is the reply type
405 >   */
406 >  token = vector[IDENT_REPLY_TYPE];
407 >
408 >  if (EmptyString(token))
409 >    return NULL;
410 >
411 >  while (IsSpace(*token))
412 >    ++token;
413 >
414 >  if (strncmp(token, "USERID", 6))
415 >    return NULL;
416 >
417 >  /*
418 >   * Third token is the os type
419 >   */
420 >  token = vector[IDENT_OS_TYPE];
421 >
422 >  if (EmptyString(token))
423 >    return NULL;
424 >
425 >  while (IsSpace(*token))
426 >   ++token;
427 >
428 >  /*
429 >   * Unless "OTHER" is specified as the operating system type, the server
430 >   * is expected to return the "normal" user identification of the owner
431 >   * of this connection. "Normal" in this context may be taken to mean a
432 >   * string of characters which uniquely identifies the connection owner
433 >   * such as a user identifier assigned by the system administrator and
434 >   * used by such user as a mail identifier, or as the "user" part of a
435 >   * user/password pair used to gain access to system resources. When an
436 >   * operating system is specified (e.g., anything but "OTHER"), the user
437 >   * identifier is expected to be in a more or less immediately useful
438 >   * form - e.g., something that could be used as an argument to "finger"
439 >   * or as a mail address.
440 >   */
441 >  if (!strncmp(token, "OTHER", 5))
442 >    return NULL;
443 >
444 >  /*
445 >   * Fourth token is the username
446 >   */
447 >  token = vector[IDENT_INFO];
448 >
449 >  if (EmptyString(token))
450 >    return NULL;
451 >
452 >  while (IsSpace(*token))
453 >    ++token;
454 >
455 >  while (*token == '~' || *token == '^')
456 >    ++token;
457 >
458 >  /*
459 >   * Look for the end of the username, terminators are '\0, @, <SPACE>, :'
460 >   */
461 >  for (end = token; *end; ++end)
462 >    if (IsSpace(*end) || '@' == *end || ':' == *end)
463 >      break;
464 >  *end = '\0';
465 >
466 >  return token;
467   }
468  
469   /*
470 < * read_auth_reply - read the reply (if any) from the ident server
470 > * read_auth_reply - read the reply (if any) from the ident server
471   * we connected to.
472   * We only give it one shot, if the reply isn't good the first time
473   * fail the authentication entirely. --Bleep
474   */
540 #define AUTH_BUFSIZ 128
541
475   static void
476   read_auth_reply(fde_t *fd, void *data)
477   {
478 <  struct AuthRequest *auth = data;
479 <  char *s = NULL;
480 <  char *t = NULL;
481 <  int len;
549 <  int count;
550 <  char buf[AUTH_BUFSIZ + 1]; /* buffer to read auth reply into */
551 <
552 <  /* Why?
553 <   * Well, recv() on many POSIX systems is a per-packet operation,
554 <   * and we do not necessarily want this, because on lowspec machines,
555 <   * the ident response may come back fragmented, thus resulting in an
556 <   * invalid ident response, even if the ident response was really OK.
557 <   *
558 <   * So PLEASE do not change this code to recv without being aware of the
559 <   * consequences.
560 <   *
561 <   *    --nenolod
562 <   */
563 < #ifndef _WIN32
564 <  len = read(fd->fd, buf, AUTH_BUFSIZ);
565 < #else
566 <  len = recv(fd->fd, buf, AUTH_BUFSIZ, 0);
567 < #endif
568 <  
569 <  if (len < 0)
570 <  {
571 < #ifdef _WIN32
572 <    errno = WSAGetLastError();
573 < #endif
574 <    if (ignoreErrno(errno))
575 <      comm_setselect(fd, COMM_SELECT_READ, read_auth_reply, auth, 0);
576 <    else
577 <      auth_error(auth);
578 <    return;
579 <  }
478 >  struct AuthRequest *const auth = data;
479 >  const char *username = NULL;
480 >  ssize_t len = 0;
481 >  char buf[RFC1413_BUFSIZ + 1];
482  
483 <  if (len > 0)
483 >  if ((len = recv(fd->fd, buf, RFC1413_BUFSIZ, 0)) > 0)
484    {
485      buf[len] = '\0';
486 <
585 <    if ((s = GetValidIdent(buf)))
586 <    {
587 <      t = auth->client->username;
588 <
589 <      while (*s == '~' || *s == '^')
590 <        s++;
591 <
592 <      for (count = USERLEN; *s && count; s++)
593 <      {
594 <        if (*s == '@')
595 <          break;
596 <        if (!IsSpace(*s) && *s != ':' && *s != '[')
597 <        {
598 <          *t++ = *s;
599 <          count--;
600 <        }
601 <      }
602 <
603 <      *t = '\0';
604 <    }
486 >    username = check_ident_reply(buf);
487    }
488  
489    fd_close(fd);
490  
609  dlinkDelete(&auth->ident_node, &auth_doing_ident_list);  
491    ClearAuth(auth);
492  
493 <  if (s == NULL)
493 >  if (EmptyString(username))
494    {
495      sendheader(auth->client, REPORT_FAIL_ID);
496 <    ++ServerStats->is_abad;
496 >    ++ServerStats.is_abad;
497    }
498    else
499    {
500 +    strlcpy(auth->client->username, username, sizeof(auth->client->username));
501      sendheader(auth->client, REPORT_FIN_ID);
502 <    ++ServerStats->is_asuc;
502 >    ++ServerStats.is_asuc;
503      SetGotId(auth->client);
504    }
505  
506 <  if (!IsDNSPending(auth) && !IsCrit(auth))
625 <  {
626 <    release_auth_client(auth->client);
627 <    MyFree(auth);
628 <  }
506 >  release_auth_client(auth);
507   }
508  
509   /*
510   * delete_auth()
511   */
512 < void
513 < delete_auth(struct Client *target_p)
512 > void
513 > delete_auth(struct AuthRequest *auth)
514   {
515 <  dlink_node *ptr;
516 <  dlink_node *next_ptr;
639 <  struct AuthRequest *auth;
515 >  if (IsDNSPending(auth))
516 >    delete_resolver_queries(auth);
517  
518 <  if (!IsUnknown(target_p))
519 <    return;
518 >  if (IsDoingAuth(auth))
519 >    fd_close(&auth->fd);
520  
521 <  if (target_p->localClient->dns_query != NULL)
645 <    DLINK_FOREACH_SAFE(ptr, next_ptr, auth_doing_dns_list.head)
646 <    {
647 <      auth = ptr->data;
648 <
649 <      if (auth->client == target_p)
650 <      {
651 <        delete_resolver_queries(target_p->localClient->dns_query);
652 <
653 <        dlinkDelete(&auth->dns_node, &auth_doing_dns_list);
654 <        if (!IsDoingAuth(auth))
655 <        {
656 <          MyFree(auth);
657 <          return;
658 <        }
659 <      }
660 <    }
661 <
662 <  DLINK_FOREACH_SAFE(ptr, next_ptr, auth_doing_ident_list.head)
521 >  if (IsInAuth(auth))
522    {
523 <    auth = ptr->data;
523 >    dlinkDelete(&auth->node, &auth_pending_list);
524 >    ClearInAuth(auth);
525 >  }
526 > }
527  
528 <    if (auth->client == target_p)
529 <    {
530 <      fd_close(&auth->fd);
528 > /* auth_init
529 > *
530 > * Initialise the auth code
531 > */
532 > void
533 > auth_init(void)
534 > {
535 >  static struct event timeout_auth_queries =
536 >  {
537 >    .name = "timeout_auth_queries_event",
538 >    .handler = timeout_auth_queries_event,
539 >    .when = 1
540 >  };
541  
542 <      dlinkDelete(&auth->ident_node, &auth_doing_ident_list);
671 <      MyFree(auth);
672 <    }
673 <  }
542 >  event_add(&timeout_auth_queries, NULL);
543   }

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)