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/src/s_auth.c (file contents), Revision 32 by knight, Sun Oct 2 20:41:23 2005 UTC vs.
ircd-hybrid/trunk/src/auth.c (file contents), Revision 8895 by michael, Sun Apr 21 14:29:36 2019 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-2019 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 Implementation of DNS and ident lookups.
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"
54 + #include "misc.h"
55  
57 static const char *HeaderMessages[] = {
58  ":%s NOTICE AUTH :*** Looking up your hostname...",
59  ":%s NOTICE AUTH :*** Found your hostname",
60  ":%s NOTICE AUTH :*** Couldn't look up your hostname",
61  ":%s NOTICE AUTH :*** Checking Ident",
62  ":%s NOTICE AUTH :*** Got Ident response",
63  ":%s NOTICE AUTH :*** No Ident response",
64  ":%s NOTICE AUTH :*** Your forward and reverse DNS do not match, ignoring hostname.",
65  ":%s NOTICE AUTH :*** Your hostname is too long, ignoring hostname"
66 };
56  
57 < enum {
57 > enum
58 > {
59    REPORT_DO_DNS,
60    REPORT_FIN_DNS,
61    REPORT_FAIL_DNS,
# Line 73 | Line 63 | enum {
63    REPORT_FIN_ID,
64    REPORT_FAIL_ID,
65    REPORT_IP_MISMATCH,
66 <  REPORT_HOST_TOOLONG
66 >  REPORT_HOST_TOOLONG,
67 >  REPORT_HOST_INVALID
68   };
69  
70 < #define sendheader(c, i) sendto_one((c), HeaderMessages[(i)], me.name)
71 <
72 < /*
73 < * Ok, the original was confusing.
74 < * Now there are two lists, an auth request can be on both at the same time
75 < * or only on one or the other.
76 < * - Dianora
77 < */
78 < static dlink_list auth_doing_dns_list   = { NULL, NULL, 0 };
79 < static dlink_list auth_doing_ident_list = { NULL, NULL, 0 };
70 > static const char *const HeaderMessages[] =
71 > {
72 >  [REPORT_DO_DNS] = ":*** Looking up your hostname",
73 >  [REPORT_FIN_DNS] = ":*** Found your hostname",
74 >  [REPORT_FAIL_DNS] = ":*** Couldn't look up your hostname",
75 >  [REPORT_DO_ID] = ":*** Checking Ident",
76 >  [REPORT_FIN_ID] = ":*** Got Ident response",
77 >  [REPORT_FAIL_ID] = ":*** No Ident response",
78 >  [REPORT_IP_MISMATCH] = ":*** Your forward and reverse DNS do not match, ignoring hostname",
79 >  [REPORT_HOST_TOOLONG] = ":*** Your hostname is too long, ignoring hostname",
80 >  [REPORT_HOST_INVALID] = ":*** Your hostname contains illegal characters, ignoring hostname"
81 > };
82  
83 < static EVH timeout_auth_queries_event;
83 > #define auth_sendheader(c, i) sendto_one_notice((c), &me, "%s", HeaderMessages[(i)])
84  
92 static PF read_auth_reply;
93 static CNCB auth_connect_callback;
94 static CBFUNC start_auth;
85  
96 struct Callback *auth_cb = NULL;
86  
87 < /* init_auth()
88 < *
89 < * Initialise the auth code
87 > /*! \brief Allocate a new auth request.
88 > * \param client The client being looked up.
89 > * \return The newly allocated auth request.
90   */
91 < void
92 < init_auth(void)
91 > static struct AuthRequest *
92 > auth_make(struct Client *client)
93   {
94 <  auth_cb = register_callback("start_auth", start_auth);
95 <  eventAddIsh("timeout_auth_queries_event", timeout_auth_queries_event, NULL, 1);
94 >  struct AuthRequest *auth = xcalloc(sizeof(*auth));
95 >
96 >  auth->client = client;
97 >  auth->client->connection->auth = auth;
98 >
99 >  return auth;
100   }
101  
102 < /*
103 < * make_auth_request - allocate a new auth request
102 > /*! \brief Free memory
103 > * \param auth The allocated auth request to cleanup.
104   */
105 < static struct AuthRequest *
106 < make_auth_request(struct Client *client)
105 > static void
106 > auth_free(struct AuthRequest *auth)
107   {
108 <  struct AuthRequest *request = MyMalloc(sizeof(struct AuthRequest));
109 <
117 <  request->client  = client;
118 <  request->timeout = CurrentTime + CONNECTTIMEOUT;
119 <
120 <  return (request);
108 >  auth->client = NULL;
109 >  xfree(auth);
110   }
111  
112 < /*
113 < * release_auth_client - release auth client from auth system
114 < * this adds the client into the local client lists so it can be read by
126 < * the main io processing loop
112 > /*! \brief Release auth client from auth system. This adds the client into the
113 > *         local client lists so it can be read by the main io processing loop.
114 > * \param auth Pointer to AuthRequest struct to release
115   */
116 < void
117 < release_auth_client(struct Client *client)
116 > static void
117 > auth_release_client(struct AuthRequest *auth)
118   {
119 +  struct Client *client = auth->client;
120 +
121 +  assert(client);
122 +  assert(client->connection);
123 +
124 +  if (auth->ident_pending == true || auth->dns_pending == true)
125 +    return;
126 +
127 +  auth_free(auth);
128 +  client->connection->auth = NULL;
129 +
130    /*
131     * When a client has auth'ed, we want to start reading what it sends
132     * us. This is what read_packet() does.
133     *     -- adrian
134     */
135 <  client->localClient->allow_read = MAX_FLOOD;
136 <  comm_setflush(&client->localClient->fd, 1000, flood_recalc, client);
137 <  if ((client->node.prev != NULL) || (client->node.next != NULL))
138 <  {
139 <    sendto_realops_flags(UMODE_ALL, L_OPER,
140 <                         "already linked %s at %s:%d", client->name,
141 <                         __FILE__, __LINE__);
142 <    ilog(L_ERROR, "already linked %s at %s:%d", client->name,
143 <         __FILE__, __LINE__);
144 <    assert(0==5);
146 <  }
147 <  else
148 <    dlinkAdd(client, &client->node, &global_client_list);
149 <  read_packet(&client->localClient->fd, client);
135 >  comm_setflush(client->connection->fd, 1000, flood_recalc, client);
136 >
137 >  client->connection->since     = CurrentTime;
138 >  client->connection->lasttime  = CurrentTime;
139 >  client->connection->firsttime = CurrentTime;
140 >  AddFlag(client, FLAGS_FINISHED_AUTH);
141 >
142 >  strlcpy(client->realhost, client->host, sizeof(client->realhost));
143 >
144 >  read_packet(client->connection->fd, client);
145   }
146 <
147 < /*
148 < * auth_dns_callback - called when resolver query finishes
149 < * if the query resulted in a successful search, hp will contain
155 < * a non-null pointer, otherwise hp will be null.
156 < * set the client on it's way to a connection completion, regardless
157 < * of success of failure
146 >
147 > /*! Checks if a hostname is valid and doesn't contain illegal characters
148 > * \param hostname The string to verify
149 > * \return 1 if it is valid, 0 if it isn't
150   */
151 < static void
152 < auth_dns_callback(void *vptr, struct DNSReply *reply)
151 > static bool
152 > auth_verify_hostname(const char *hostname)
153   {
154 <  struct AuthRequest *auth = (struct AuthRequest *)vptr;
154 >  const char *p = hostname;
155  
156 <  dlinkDelete(&auth->dns_node, &auth_doing_dns_list);
165 <  ClearDNSPending(auth);
156 >  assert(p);
157  
158 <  if (reply != NULL)
159 <  {
169 <    struct sockaddr_in *v4, *v4dns;
170 < #ifdef IPV6
171 <    struct sockaddr_in6 *v6, *v6dns;
172 < #endif
173 <    int good = 1;
174 <
175 < #ifdef IPV6
176 <    if (auth->client->localClient->ip.ss.ss_family == AF_INET6)
177 <    {
178 <      v6 = (struct sockaddr_in6 *)&auth->client->localClient->ip;
179 <      v6dns = (struct sockaddr_in6 *)&reply->addr;
180 <      if (memcmp(&v6->sin6_addr, &v6dns->sin6_addr, sizeof(struct in6_addr)) != 0)
181 <      {
182 <        sendheader(auth->client, REPORT_IP_MISMATCH);
183 <        good = 0;
184 <      }
185 <    }
186 <    else
187 < #endif
188 <    {
189 <      v4 = (struct sockaddr_in *)&auth->client->localClient->ip;
190 <      v4dns = (struct sockaddr_in *)&reply->addr;
191 <      if(v4->sin_addr.s_addr != v4dns->sin_addr.s_addr)
192 <      {
193 <        sendheader(auth->client, REPORT_IP_MISMATCH);
194 <        good = 0;
195 <      }
196 <    }
197 <    if (good && strlen(reply->h_name) <= HOSTLEN)
198 <    {
199 <      strlcpy(auth->client->host, reply->h_name,
200 <              sizeof(auth->client->host));
201 <      sendheader(auth->client, REPORT_FIN_DNS);
202 <    }
203 <    else if (strlen(reply->h_name) > HOSTLEN)
204 <      sendheader(auth->client, REPORT_HOST_TOOLONG);
205 <  }
206 <  else
207 <      sendheader(auth->client, REPORT_FAIL_DNS);
158 >  if (EmptyString(p) || *p == '.' || *p == ':')
159 >    return false;
160  
161 <  MyFree(auth->client->localClient->dns_query);
162 <  auth->client->localClient->dns_query = NULL;
161 >  for (; *p; ++p)
162 >    if (!IsHostChar(*p))
163 >      return false;
164  
165 <  if (!IsDoingAuth(auth))
213 <  {
214 <    struct Client *client_p = auth->client;
215 <    MyFree(auth);
216 <    release_auth_client(client_p);
217 <  }
165 >  return true;
166   }
167  
168 < /*
169 < * authsenderr - handle auth send errors
168 > /*! \brief Handle a complete DNS lookup. Send the client on its way to a connection
169 > *         completion, regardless of success or failure.
170 > * \param vptr The pending struct AuthRequest.
171 > * \param addr IP address being resolved.
172 > * \param name Resolved name, or NULL if lookup failed.
173 > * \param namelength String length of the resolved hostname pointed by 'name'
174   */
175   static void
176 < auth_error(struct AuthRequest *auth)
176 > auth_dns_callback(void *vptr, const struct irc_ssaddr *addr, const char *name, size_t namelength)
177   {
178 <  ++ServerStats->is_abad;
178 >  struct AuthRequest *const auth = vptr;
179  
180 <  fd_close(&auth->fd);
180 >  assert(auth->client);
181 >  assert(auth->client->connection);
182  
183 <  dlinkDelete(&auth->ident_node, &auth_doing_ident_list);
231 <  ClearAuth(auth);
183 >  auth->dns_pending = false;
184  
185 <  sendheader(auth->client, REPORT_FAIL_ID);
186 <
187 <  if (!IsDNSPending(auth) && !IsCrit(auth))
185 >  if (namelength == 0)
186 >    auth_sendheader(auth->client, REPORT_FAIL_DNS);
187 >  else if (address_compare(addr, &auth->client->ip, false) == false)
188 >    auth_sendheader(auth->client, REPORT_IP_MISMATCH);
189 >  else if (namelength > HOSTLEN)
190 >    auth_sendheader(auth->client, REPORT_HOST_TOOLONG);
191 >  else if (auth_verify_hostname(name) == false)
192 >    auth_sendheader(auth->client, REPORT_HOST_INVALID);
193 >  else
194    {
195 <    release_auth_client(auth->client);
196 <    MyFree(auth);
195 >    strlcpy(auth->client->host, name, sizeof(auth->client->host));
196 >    auth_sendheader(auth->client, REPORT_FIN_DNS);
197    }
198 +
199 +  auth_release_client(auth);
200   }
201  
202   /*
203 < * start_auth_query - Flag the client to show that an attempt to
244 < * contact the ident server on
245 < * the client's host.  The connect and subsequently the socket are all put
246 < * into 'non-blocking' mode.  Should the connect or any later phase of the
247 < * identifing process fail, it is aborted and the user is given a username
248 < * of "unknown".
203 > * auth_error - handle auth send errors
204   */
205 < static int
206 < start_auth_query(struct AuthRequest *auth)
205 > static void
206 > auth_error(struct AuthRequest *auth)
207   {
208 <  struct irc_ssaddr localaddr;
209 <  socklen_t locallen = sizeof(struct irc_ssaddr);
210 < #ifdef IPV6
211 <  struct sockaddr_in6 *v6;
257 < #else
258 <  struct sockaddr_in *v4;
259 < #endif
260 <
261 <  /* open a socket of the same type as the client socket */
262 <  if (comm_open(&auth->fd, auth->client->localClient->ip.ss.ss_family,
263 <                SOCK_STREAM, 0, "ident") == -1)
264 <  {
265 <    report_error(L_ALL, "creating auth stream socket %s:%s",
266 <        get_client_name(auth->client, SHOW_IP), errno);
267 <    ilog(L_ERROR, "Unable to create auth socket for %s",
268 <        get_client_name(auth->client, SHOW_IP));
269 <    ++ServerStats->is_abad;
270 <    return 0;
271 <  }
208 >  assert(auth);
209 >  assert(auth->fd);
210 >  assert(auth->client);
211 >  assert(auth->client->connection);
212  
213 <  sendheader(auth->client, REPORT_DO_ID);
213 >  ++ServerStats.is_abad;
214  
215 <  /*
216 <   * get the local address of the client and bind to that to
217 <   * make the auth request.  This used to be done only for
278 <   * ifdef VIRTUAL_HOST, but needs to be done for all clients
279 <   * since the ident request must originate from that same address--
280 <   * and machines with multiple IP addresses are common now
281 <   */
282 <  memset(&localaddr, 0, locallen);
283 <  getsockname(auth->client->localClient->fd.fd, (struct sockaddr*)&localaddr,
284 <      &locallen);
215 >  fd_close(auth->fd);
216 >  auth->fd = NULL;
217 >  auth->ident_pending = false;
218  
219 < #ifdef IPV6
287 <  remove_ipv6_mapping(&localaddr);
288 <  v6 = (struct sockaddr_in6 *)&localaddr;
289 <  v6->sin6_port = htons(0);
290 < #else
291 <  localaddr.ss_len = locallen;
292 <  v4 = (struct sockaddr_in *)&localaddr;
293 <  v4->sin_port = htons(0);
294 < #endif
295 <  localaddr.ss_port = htons(0);
296 <
297 <  SetDoingAuth(auth);
298 <  dlinkAdd(auth, &auth->ident_node, &auth_doing_ident_list);
299 <
300 <  comm_connect_tcp(&auth->fd, auth->client->sockhost, 113,
301 <      (struct sockaddr *)&localaddr, localaddr.ss_len, auth_connect_callback,
302 <      auth, auth->client->localClient->ip.ss.ss_family,
303 <      GlobalSetOptions.ident_timeout);
304 <  return 1; /* We suceed here for now */
305 < }
219 >  auth_sendheader(auth->client, REPORT_FAIL_ID);
220  
221 < /*
308 < * GetValidIdent - parse ident query reply from identd server
309 < *
310 < * Inputs        - pointer to ident buf
311 < * Output        - NULL if no valid ident found, otherwise pointer to name
312 < * Side effects  -
313 < */
314 < /*
315 < * A few questions have been asked about this mess, obviously
316 < * it should have been commented better the first time.
317 < * The original idea was to remove all references to libc from ircd-hybrid.
318 < * Instead of having to write a replacement for sscanf(), I did a
319 < * rather gruseome parser here so we could remove this function call.
320 < * Note, that I had also removed a few floating point printfs as well (though
321 < * now we are still stuck with a few...)
322 < * Remember, we have a replacement ircd sprintf, we have bleeps fputs lib
323 < * it would have been nice to remove some unneeded code.
324 < * Oh well. If we don't remove libc stuff totally, then it would be
325 < * far cleaner to use sscanf()
326 < *
327 < * - Dianora
328 < */
329 < static char *
330 < GetValidIdent(char *buf)
331 < {
332 <  int   remp = 0;
333 <  int   locp = 0;
334 <  char* colon1Ptr;
335 <  char* colon2Ptr;
336 <  char* colon3Ptr;
337 <  char* commaPtr;
338 <  char* remotePortString;
339 <
340 <  /* All this to get rid of a sscanf() fun. */
341 <  remotePortString = buf;
342 <  
343 <  if ((colon1Ptr = strchr(remotePortString,':')) == NULL)
344 <    return 0;
345 <  *colon1Ptr = '\0';
346 <  colon1Ptr++;
347 <
348 <  if ((colon2Ptr = strchr(colon1Ptr,':')) == NULL)
349 <    return 0;
350 <  *colon2Ptr = '\0';
351 <  colon2Ptr++;
352 <  
353 <  if ((commaPtr = strchr(remotePortString, ',')) == NULL)
354 <    return 0;
355 <  *commaPtr = '\0';
356 <  commaPtr++;
357 <
358 <  if ((remp = atoi(remotePortString)) == 0)
359 <    return 0;
360 <              
361 <  if ((locp = atoi(commaPtr)) == 0)
362 <    return 0;
363 <
364 <  /* look for USERID bordered by first pair of colons */
365 <  if (strstr(colon1Ptr, "USERID") == NULL)
366 <    return 0;
367 <
368 <  if ((colon3Ptr = strchr(colon2Ptr,':')) == NULL)
369 <    return 0;
370 <  *colon3Ptr = '\0';
371 <  colon3Ptr++;
372 <  return (colon3Ptr);
221 >  auth_release_client(auth);
222   }
223  
224 < /*
225 < * start_auth
377 < *
378 < * inputs       - pointer to client to auth
379 < * output       - NONE
380 < * side effects - starts auth (identd) and dns queries for a client
381 < */
382 < static void *
383 < start_auth(va_list args)
224 > /** Enum used to index ident reply fields in a human-readable way. */
225 > enum IdentReplyFields
226   {
227 <  struct Client *client = va_arg(args, struct Client *);
228 <  struct AuthRequest *auth = NULL;
227 >  IDENT_PORT_NUMBERS,
228 >  IDENT_REPLY_TYPE,
229 >  IDENT_OS_TYPE,
230 >  IDENT_INFO,
231 >  USERID_TOKEN_COUNT
232 > };
233  
234 <  assert(client != NULL);
234 > /** Parse an ident reply line and extract the userid from it.
235 > * \param reply The ident reply line.
236 > * \return The userid, or NULL on parse failure.
237 > */
238 > static const char *
239 > auth_check_ident_reply(char *const reply)
240 > {
241 >  char *token = NULL, *end = NULL;
242 >  char *vector[USERID_TOKEN_COUNT];
243 >  const unsigned int count = token_vector(reply, ':', vector, USERID_TOKEN_COUNT);
244  
245 <  auth = make_auth_request(client);
246 <  SetCrit(auth);
245 >  if (USERID_TOKEN_COUNT != count)
246 >    return NULL;
247  
248 <  client->localClient->dns_query = MyMalloc(sizeof(struct DNSQuery));
249 <  client->localClient->dns_query->ptr = auth;
250 <  client->localClient->dns_query->callback = auth_dns_callback;
248 >  /*
249 >   * Second token is the reply type
250 >   */
251 >  token = vector[IDENT_REPLY_TYPE];
252 >
253 >  if (EmptyString(token))
254 >    return NULL;
255 >
256 >  while (IsSpace(*token))
257 >    ++token;
258 >
259 >  if (strncmp(token, "USERID", 6))
260 >    return NULL;
261 >
262 >  /*
263 >   * Third token is the os type
264 >   */
265 >  token = vector[IDENT_OS_TYPE];
266 >
267 >  if (EmptyString(token))
268 >    return NULL;
269  
270 <  sendheader(client, REPORT_DO_DNS);
270 >  while (IsSpace(*token))
271 >   ++token;
272  
273 <  if (ConfigFileEntry.disable_auth == 0)
274 <    start_auth_query(auth);
273 >  /*
274 >   * Unless "OTHER" is specified as the operating system type, the server
275 >   * is expected to return the "normal" user identification of the owner
276 >   * of this connection. "Normal" in this context may be taken to mean a
277 >   * string of characters which uniquely identifies the connection owner
278 >   * such as a user identifier assigned by the system administrator and
279 >   * used by such user as a mail identifier, or as the "user" part of a
280 >   * user/password pair used to gain access to system resources. When an
281 >   * operating system is specified (e.g., anything but "OTHER"), the user
282 >   * identifier is expected to be in a more or less immediately useful
283 >   * form - e.g., something that could be used as an argument to "finger"
284 >   * or as a mail address.
285 >   */
286 >  if (strncmp(token, "OTHER", 5) == 0)
287 >    return NULL;
288 >
289 >  /*
290 >   * Fourth token is the username
291 >   */
292 >  token = vector[IDENT_INFO];
293  
294 <  /* auth order changed, before gethost_byaddr can immediately call
295 <   * dns callback under win32 when the lookup cannot be started.
404 <   * And that would do MyFree(auth) etc -adx */
405 <  SetDNSPending(auth);
406 <  dlinkAdd(auth, &auth->dns_node, &auth_doing_dns_list);
407 <  ClearCrit(auth);
408 <  gethost_byaddr(&client->localClient->ip, client->localClient->dns_query);
294 >  if (EmptyString(token))
295 >    return NULL;
296  
297 <  return NULL;
297 >  while (IsSpace(*token))
298 >    ++token;
299 >
300 >  while (*token == '~' || *token == '^')
301 >    ++token;
302 >
303 >  /*
304 >   * Look for the end of the username, terminators are '\0, @, <SPACE>, :'
305 >   */
306 >  for (end = token; *end; ++end)
307 >    if (IsSpace(*end) || '@' == *end || ':' == *end)
308 >      break;
309 >  *end = '\0';
310 >
311 >  return token;
312   }
313  
314 < /*
315 < * timeout_auth_queries - timeout resolver and identd requests
316 < * allow clients through if requests failed
314 > /*! \brief Read the reply (if any) from the ident server we connected to. We
315 > *         only give it one shot, if the reply isn't good the first time fail
316 > *         the authentication entirely. --Bleep
317 > * \param F The socket/fd to read from.
318 > * \param data The request to read.
319   */
320   static void
321 < timeout_auth_queries_event(void *notused)
321 > auth_read_reply(fde_t *F, void *data)
322   {
323 <  dlink_node *ptr;
324 <  dlink_node *next_ptr;
325 <  struct AuthRequest* auth;
323 >  struct AuthRequest *const auth = data;
324 >  const char *username = NULL;
325 >  ssize_t len = 0;
326 >  char buf[RFC1413_BUFSIZ + 1];
327 >
328 >  assert(auth->fd == F);
329 >  assert(auth->client);
330 >  assert(auth->client->connection);
331  
332 <  DLINK_FOREACH_SAFE(ptr, next_ptr, auth_doing_ident_list.head)
332 >  if ((len = recv(auth->fd->fd, buf, sizeof(buf) - 1, 0)) > 0)
333    {
334 <    auth = ptr->data;
334 >    buf[len] = '\0';
335 >    username = auth_check_ident_reply(buf);
336 >  }
337  
338 <    if (auth->timeout <= CurrentTime)
339 <    {
340 <      fd_close(&auth->fd);
341 <
342 <      ++ServerStats->is_abad;
343 <      sendheader(auth->client, REPORT_FAIL_ID);
344 <
345 <      if (IsDNSPending(auth))
436 <      {
437 <        struct Client *client_p = auth->client;
438 <
439 <        dlinkDelete(&auth->dns_node, &auth_doing_dns_list);
440 <        if (client_p->localClient->dns_query != NULL)
441 <        {
442 <          delete_resolver_queries(client_p->localClient->dns_query);
443 <          MyFree(client_p->localClient->dns_query);
444 <        }
445 <        auth->client->localClient->dns_query = NULL;
446 <        sendheader(client_p, REPORT_FAIL_DNS);
447 <      }
448 <
449 <      ilog(L_INFO, "DNS/AUTH timeout %s",
450 <           get_client_name(auth->client, SHOW_IP));
451 <
452 <      dlinkDelete(&auth->ident_node, &auth_doing_ident_list);
453 <      release_auth_client(auth->client);
454 <      MyFree(auth);
455 <    }
338 >  fd_close(auth->fd);
339 >  auth->fd = NULL;
340 >  auth->ident_pending = false;
341 >
342 >  if (EmptyString(username))
343 >  {
344 >    auth_sendheader(auth->client, REPORT_FAIL_ID);
345 >    ++ServerStats.is_abad;
346    }
347 +  else
348 +  {
349 +    strlcpy(auth->client->username, username, sizeof(auth->client->username));
350 +    auth_sendheader(auth->client, REPORT_FIN_ID);
351 +    ++ServerStats.is_asuc;
352 +    AddFlag(auth->client, FLAGS_GOTID);
353 +  }
354 +
355 +  auth_release_client(auth);
356   }
357  
358   /*
# Line 468 | Line 367 | timeout_auth_queries_event(void *notused
367   * problems arise. -avalon
368   */
369   static void
370 < auth_connect_callback(fde_t *fd, int error, void *data)
370 > auth_connect_callback(fde_t *F, int error, void *data)
371   {
372 <  struct AuthRequest *auth = data;
372 >  struct AuthRequest *const auth = data;
373    struct irc_ssaddr us;
374    struct irc_ssaddr them;
375 <  char authbuf[32];
375 >  char authbuf[16];
376 >  ssize_t len = 0;
377    socklen_t ulen = sizeof(struct irc_ssaddr);
378    socklen_t tlen = sizeof(struct irc_ssaddr);
379 <  u_int16_t uport, tport;
480 < #ifdef IPV6
379 >  uint16_t uport, tport;
380    struct sockaddr_in6 *v6;
381 < #else
382 <  struct sockaddr_in *v4;
383 < #endif
381 >
382 >  assert(auth->fd == F);
383 >  assert(auth->client);
384 >  assert(auth->client->connection);
385  
386    if (error != COMM_OK)
387    {
# Line 489 | Line 389 | auth_connect_callback(fde_t *fd, int err
389      return;
390    }
391  
392 <  if (getsockname(auth->client->localClient->fd.fd, (struct sockaddr *) &us,
393 <      (socklen_t *) &ulen) ||
494 <      getpeername(auth->client->localClient->fd.fd, (struct sockaddr *) &them,
495 <      (socklen_t *) &tlen))
392 >  if (getsockname(auth->client->connection->fd->fd, (struct sockaddr *)&us, &ulen) ||
393 >      getpeername(auth->client->connection->fd->fd, (struct sockaddr *)&them, &tlen))
394    {
395 <    ilog(L_INFO, "auth get{sock,peer}name error for %s",
396 <        get_client_name(auth->client, SHOW_IP));
395 >    report_error(L_ALL, "auth get{sock,peer}name error %s:%s",
396 >                 client_get_name(auth->client, SHOW_IP), errno);
397      auth_error(auth);
398      return;
399    }
400  
503 #ifdef IPV6
401    v6 = (struct sockaddr_in6 *)&us;
402    uport = ntohs(v6->sin6_port);
403    v6 = (struct sockaddr_in6 *)&them;
404    tport = ntohs(v6->sin6_port);
508  remove_ipv6_mapping(&us);
509  remove_ipv6_mapping(&them);
510 #else
511  v4 = (struct sockaddr_in *)&us;
512  uport = ntohs(v4->sin_port);
513  v4 = (struct sockaddr_in *)&them;
514  tport = ntohs(v4->sin_port);
515  us.ss_len = ulen;
516  them.ss_len = tlen;
517 #endif
518  
519  ircsprintf(authbuf, "%u , %u\r\n", tport, uport);
405  
406 <  if (send(fd->fd, authbuf, strlen(authbuf), 0) == -1)
406 >  len = snprintf(authbuf, sizeof(authbuf), "%u, %u\r\n", tport, uport);
407 >
408 >  if (send(F->fd, authbuf, len, 0) != len)
409    {
410      auth_error(auth);
411      return;
412    }
413 <  read_auth_reply(&auth->fd, auth);
413 >
414 >  comm_setselect(F, COMM_SELECT_READ, auth_read_reply, auth, 0);
415   }
416  
417 < /*
418 < * read_auth_reply - read the reply (if any) from the ident server
419 < * we connected to.
420 < * We only give it one shot, if the reply isn't good the first time
421 < * fail the authentication entirely. --Bleep
417 > /*! \brief Flag the client to show an attempt to contact the ident server on
418 > *         the client's host. Should the connect or any later phase of the
419 > *         identifying process fail, it is aborted and the user is given a
420 > *         username of "unknown".
421 > * \param auth The request for which to start the ident lookup.
422   */
535 #define AUTH_BUFSIZ 128
536
423   static void
424 < read_auth_reply(fde_t *fd, void *data)
424 > auth_start_query(struct AuthRequest *auth)
425   {
426 <  struct AuthRequest *auth = data;
427 <  char *s = NULL;
428 <  char *t = NULL;
429 <  int len;
430 <  int count;
431 <  char buf[AUTH_BUFSIZ + 1]; /* buffer to read auth reply into */
432 <
433 <  len = recv(fd->fd, buf, AUTH_BUFSIZ, 0);
434 <  
435 <  if (len < 0)
436 <  {
437 < #ifdef _WIN32
438 <    errno = WSAGetLastError();
439 < #endif
554 <    if (ignoreErrno(errno))
555 <      comm_setselect(fd, COMM_SELECT_READ, read_auth_reply, auth, 0);
556 <    else
557 <      auth_error(auth);
426 >  struct irc_ssaddr localaddr;
427 >  socklen_t locallen = sizeof(struct irc_ssaddr);
428 >  struct sockaddr_in6 *v6;
429 >
430 >  assert(auth->client);
431 >  assert(auth->client->connection);
432 >
433 >  /* Open a socket of the same type as the client socket */
434 >  int fd = comm_socket(auth->client->ip.ss.ss_family, SOCK_STREAM, 0);
435 >  if (fd == -1)
436 >  {
437 >    report_error(L_ALL, "creating auth stream socket %s:%s",
438 >                 client_get_name(auth->client, SHOW_IP), errno);
439 >    ++ServerStats.is_abad;
440      return;
441    }
442  
443 <  if (len > 0)
444 <  {
563 <    buf[len] = '\0';
443 >  auth->fd = fd_open(fd, true, "ident");
444 >  auth->ident_pending = true;
445  
446 <    if ((s = GetValidIdent(buf)))
566 <    {
567 <      t = auth->client->username;
568 <
569 <      while (*s == '~' || *s == '^')
570 <        s++;
571 <
572 <      for (count = USERLEN; *s && count; s++)
573 <      {
574 <        if (*s == '@')
575 <          break;
576 <        if (!IsSpace(*s) && *s != ':' && *s != '[')
577 <        {
578 <          *t++ = *s;
579 <          count--;
580 <        }
581 <      }
446 >  auth_sendheader(auth->client, REPORT_DO_ID);
447  
448 <      *t = '\0';
449 <    }
450 <  }
448 >  /*
449 >   * Get the local address of the client and bind to that to
450 >   * make the auth request.
451 >   */
452 >  memset(&localaddr, 0, locallen);
453 >  getsockname(auth->client->connection->fd->fd, (struct sockaddr *)&localaddr, &locallen);
454  
455 <  fd_close(fd);
455 >  remove_ipv6_mapping(&localaddr);
456 >  v6 = (struct sockaddr_in6 *)&localaddr;
457 >  v6->sin6_port = htons(0);
458  
459 <  dlinkDelete(&auth->ident_node, &auth_doing_ident_list);  
460 <  ClearAuth(auth);
459 >  comm_connect_tcp(auth->fd, &auth->client->ip, RFC1413_PORT, &localaddr,
460 >                   auth_connect_callback, auth, 5);
461 > }
462  
463 <  if (s == NULL)
464 <  {
465 <    sendheader(auth->client, REPORT_FAIL_ID);
466 <    ++ServerStats->is_abad;
467 <  }
468 <  else
469 <  {
470 <    sendheader(auth->client, REPORT_FIN_ID);
471 <    ++ServerStats->is_asuc;
472 <    SetGotId(auth->client);
473 <  }
463 > /*
464 > * auth_start
465 > *
466 > * inputs       - pointer to client to auth
467 > * output       - NONE
468 > * side effects - starts auth (identd) and dns queries for a client
469 > */
470 > void
471 > auth_start(struct Client *client_p)
472 > {
473 >  struct AuthRequest *auth = auth_make(client_p);
474  
475 <  if (!IsDNSPending(auth) && !IsCrit(auth))
476 <  {
477 <    release_auth_client(auth->client);
478 <    MyFree(auth);
479 <  }
475 >  assert(client_p);
476 >  assert(client_p->connection);
477 >
478 >  auth_sendheader(client_p, REPORT_DO_DNS);
479 >
480 >  auth->dns_pending = true;
481 >
482 >  if (ConfigGeneral.disable_auth == 0)
483 >    auth_start_query(auth);
484 >
485 >  gethost_byaddr(auth_dns_callback, auth, &client_p->ip);
486   }
487  
488   /*
489 < * delete_auth()
489 > * auth_delete()
490   */
491 < void
492 < delete_auth(struct Client *target_p)
491 > void
492 > auth_delete(struct AuthRequest *auth)
493   {
494 <  dlink_node *ptr;
495 <  dlink_node *next_ptr;
619 <  struct AuthRequest *auth;
494 >  assert(auth->client);
495 >  assert(auth->client->connection);
496  
497 <  if (!IsUnknown(target_p))
498 <    return;
497 >  if (auth->fd)
498 >  {
499 >    fd_close(auth->fd);
500 >    auth->fd = NULL;
501 >  }
502  
503 <  if (target_p->localClient->dns_query != NULL)
625 <    DLINK_FOREACH_SAFE(ptr, next_ptr, auth_doing_dns_list.head)
626 <    {
627 <      auth = ptr->data;
628 <
629 <      if (auth->client == target_p)
630 <      {
631 <        delete_resolver_queries(target_p->localClient->dns_query);
632 <
633 <        dlinkDelete(&auth->dns_node, &auth_doing_dns_list);
634 <        if (!IsDoingAuth(auth))
635 <        {
636 <          MyFree(auth);
637 <          return;
638 <        }
639 <      }
640 <    }
503 >  auth->ident_pending = false;
504  
505 <  DLINK_FOREACH_SAFE(ptr, next_ptr, auth_doing_ident_list.head)
506 <  {
644 <    auth = ptr->data;
505 >  delete_resolver_queries(auth);
506 >  auth->dns_pending = false;
507  
508 <    if (auth->client == target_p)
647 <    {
648 <      fd_close(&auth->fd);
649 <
650 <      dlinkDelete(&auth->ident_node, &auth_doing_ident_list);
651 <      MyFree(auth);
652 <    }
653 <  }
508 >  auth_free(auth);
509   }

Comparing:
ircd-hybrid/src/s_auth.c (property svn:keywords), Revision 32 by knight, Sun Oct 2 20:41:23 2005 UTC vs.
ircd-hybrid/trunk/src/auth.c (property svn:keywords), Revision 8895 by michael, Sun Apr 21 14:29:36 2019 UTC

# Line 1 | Line 1
1 < Revision
1 > Id

Diff Legend

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