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 1155 by michael, Tue Aug 9 20:27:45 2011 UTC vs.
ircd-hybrid/trunk/src/auth.c (file contents), Revision 8919 by michael, Mon Apr 22 09:52:53 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"
39   #include "list.h"
40   #include "ircd_defs.h"
41   #include "fdlist.h"
42 < #include "s_auth.h"
43 < #include "s_conf.h"
41 < #include "balloc.h"
42 > #include "auth.h"
43 > #include "conf.h"
44   #include "client.h"
43 #include "common.h"
45   #include "event.h"
45 #include "hook.h"
46   #include "irc_string.h"
47   #include "ircd.h"
48   #include "packet.h"
49 < #include "irc_res.h"
49 > #include "res.h"
50   #include "s_bsd.h"
51 < #include "s_log.h"
51 > #include "log.h"
52   #include "send.h"
53 + #include "memory.h"
54 + #include "misc.h"
55  
56  
57 < static const char *HeaderMessages[] = {
58 <  ":%s NOTICE AUTH :*** Looking up your hostname...",
57 <  ":%s NOTICE AUTH :*** Found your hostname",
58 <  ":%s NOTICE AUTH :*** Couldn't look up your hostname",
59 <  ":%s NOTICE AUTH :*** Checking Ident",
60 <  ":%s NOTICE AUTH :*** Got Ident response",
61 <  ":%s NOTICE AUTH :*** No Ident response",
62 <  ":%s NOTICE AUTH :*** Your forward and reverse DNS do not match, ignoring hostname.",
63 <  ":%s NOTICE AUTH :*** Your hostname is too long, ignoring hostname"
64 < };
65 <
66 < enum {
57 > enum
58 > {
59    REPORT_DO_DNS,
60    REPORT_FIN_DNS,
61    REPORT_FAIL_DNS,
# Line 71 | 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 < static BlockHeap *auth_heap = NULL;
73 < static dlink_list auth_doing_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  
84 static PF read_auth_reply;
85 static CNCB auth_connect_callback;
86 static CBFUNC start_auth;
85  
88 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_heap = BlockHeapCreate("auth", sizeof(struct AuthRequest), AUTH_HEAP_SIZE);
95 <  auth_cb = register_callback("start_auth", start_auth);
96 <  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 = BlockHeapAlloc(auth_heap);
109 <
110 <  client->localClient->auth = request;
111 <  request->client           = client;
112 <  request->timeout          = CurrentTime + CONNECTTIMEOUT;
113 <
114 <  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
120 < * 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 AuthRequest *auth)
116 > static void
117 > auth_release_client(struct AuthRequest *auth)
118   {
119    struct Client *client = auth->client;
120  
121 <  if (IsDoingAuth(auth) || IsDNSPending(auth))
121 >  assert(client);
122 >  assert(client->connection);
123 >
124 >  if (auth->ident_pending == true || auth->dns_pending == true)
125      return;
126  
127 <  client->localClient->auth = NULL;
128 <  dlinkDelete(&auth->node, &auth_doing_list);
132 <  BlockHeapFree(auth_heap, auth);
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);
135 >  comm_setflush(client->connection->fd, 1000, flood_recalc, client);
136 >
137 >  client->connection->last_ping = event_base->time.sec_monotonic;
138 >  client->connection->last_data = event_base->time.sec_monotonic;
139 >  client->connection->created_real = event_base->time.sec_real;
140 >  client->connection->created_monotonic = event_base->time.sec_monotonic;
141  
142 <  dlinkAdd(client, &client->node, &global_client_list);
142 >  AddFlag(client, FLAGS_FINISHED_AUTH);
143  
144 <  client->since  = client->lasttime = client->firsttime = CurrentTime;
145 <  client->flags |= FLAGS_FINISHED_AUTH;
144 >  strlcpy(client->realhost, client->host, sizeof(client->realhost));
145  
146 <  read_packet(&client->localClient->fd, client);
146 >  read_packet(client->connection->fd, client);
147   }
148 <
149 < /*
150 < * auth_dns_callback - called when resolver query finishes
151 < * if the query resulted in a successful search, name will contain
152 < * a non-NULL pointer, otherwise name will be NULL.
153 < * set the client on it's way to a connection completion, regardless
154 < * of success of failure
148 >
149 > /*! Checks if a hostname is valid and doesn't contain illegal characters
150 > * \param hostname The string to verify
151 > * \return 1 if it is valid, 0 if it isn't
152 > */
153 > static bool
154 > auth_verify_hostname(const char *hostname)
155 > {
156 >  const char *p = hostname;
157 >
158 >  assert(p);
159 >
160 >  if (EmptyString(p) || *p == '.' || *p == ':')
161 >    return false;
162 >
163 >  for (; *p; ++p)
164 >    if (!IsHostChar(*p))
165 >      return false;
166 >
167 >  return true;
168 > }
169 >
170 > /*! \brief Handle a complete DNS lookup. Send the client on its way to a connection
171 > *         completion, regardless of success or failure.
172 > * \param vptr The pending struct AuthRequest.
173 > * \param addr IP address being resolved.
174 > * \param name Resolved name, or NULL if lookup failed.
175 > * \param namelength String length of the resolved hostname pointed by 'name'
176   */
177   static void
178 < auth_dns_callback(void *vptr, const struct irc_ssaddr *addr, const char *name)
178 > auth_dns_callback(void *vptr, const struct irc_ssaddr *addr, const char *name, size_t namelength)
179   {
180 <  struct AuthRequest *auth = vptr;
180 >  struct AuthRequest *const auth = vptr;
181  
182 <  ClearDNSPending(auth);
182 >  assert(auth->client);
183 >  assert(auth->client->connection);
184  
185 <  if (name != NULL)
185 >  auth->dns_pending = false;
186 >
187 >  if (namelength == 0)
188 >    auth_sendheader(auth->client, REPORT_FAIL_DNS);
189 >  else if (address_compare(addr, &auth->client->ip, false) == false)
190 >    auth_sendheader(auth->client, REPORT_IP_MISMATCH);
191 >  else if (namelength > HOSTLEN)
192 >    auth_sendheader(auth->client, REPORT_HOST_TOOLONG);
193 >  else if (auth_verify_hostname(name) == false)
194 >    auth_sendheader(auth->client, REPORT_HOST_INVALID);
195 >  else
196    {
197 <    const struct sockaddr_in *v4, *v4dns;
198 < #ifdef IPV6
168 <    const struct sockaddr_in6 *v6, *v6dns;
169 < #endif
170 <    int good = 1;
171 <
172 < #ifdef IPV6
173 <    if (auth->client->localClient->ip.ss.ss_family == AF_INET6)
174 <    {
175 <      v6 = (const struct sockaddr_in6 *)&auth->client->localClient->ip;
176 <      v6dns = (const struct sockaddr_in6 *)addr;
177 <      if (memcmp(&v6->sin6_addr, &v6dns->sin6_addr, sizeof(struct in6_addr)) != 0)
178 <      {
179 <        sendheader(auth->client, REPORT_IP_MISMATCH);
180 <        good = 0;
181 <      }
182 <    }
183 <    else
184 < #endif
185 <    {
186 <      v4 = (const struct sockaddr_in *)&auth->client->localClient->ip;
187 <      v4dns = (const struct sockaddr_in *)addr;
188 <      if(v4->sin_addr.s_addr != v4dns->sin_addr.s_addr)
189 <      {
190 <        sendheader(auth->client, REPORT_IP_MISMATCH);
191 <        good = 0;
192 <      }
193 <    }
194 <    if (good && strlen(name) <= HOSTLEN)
195 <    {
196 <      strlcpy(auth->client->host, name,
197 <              sizeof(auth->client->host));
198 <      sendheader(auth->client, REPORT_FIN_DNS);
199 <    }
200 <    else if (strlen(name) > HOSTLEN)
201 <      sendheader(auth->client, REPORT_HOST_TOOLONG);
197 >    strlcpy(auth->client->host, name, sizeof(auth->client->host));
198 >    auth_sendheader(auth->client, REPORT_FIN_DNS);
199    }
203  else
204    sendheader(auth->client, REPORT_FAIL_DNS);
200  
201 <  release_auth_client(auth);
201 >  auth_release_client(auth);
202   }
203  
204   /*
205 < * authsenderr - handle auth send errors
205 > * auth_error - handle auth send errors
206   */
207   static void
208   auth_error(struct AuthRequest *auth)
209   {
210 <  ++ServerStats.is_abad;
210 >  assert(auth);
211 >  assert(auth->fd);
212 >  assert(auth->client);
213 >  assert(auth->client->connection);
214  
215 <  fd_close(&auth->fd);
215 >  ++ServerStats.is_abad;
216  
217 <  ClearAuth(auth);
217 >  fd_close(auth->fd);
218 >  auth->fd = NULL;
219 >  auth->ident_pending = false;
220  
221 <  sendheader(auth->client, REPORT_FAIL_ID);
221 >  auth_sendheader(auth->client, REPORT_FAIL_ID);
222  
223 <  release_auth_client(auth);
223 >  auth_release_client(auth);
224   }
225  
226 < /*
227 < * start_auth_query - Flag the client to show that an attempt to
228 < * contact the ident server on
229 < * the client's host.  The connect and subsequently the socket are all put
230 < * into 'non-blocking' mode.  Should the connect or any later phase of the
231 < * identifing process fail, it is aborted and the user is given a username
232 < * of "unknown".
233 < */
234 < static int
235 < start_auth_query(struct AuthRequest *auth)
226 > /** Enum used to index ident reply fields in a human-readable way. */
227 > enum IdentReplyFields
228   {
229 <  struct irc_ssaddr localaddr;
230 <  socklen_t locallen = sizeof(struct irc_ssaddr);
231 < #ifdef IPV6
232 <  struct sockaddr_in6 *v6;
233 < #else
234 <  struct sockaddr_in *v4;
243 < #endif
244 <
245 <  /* open a socket of the same type as the client socket */
246 <  if (comm_open(&auth->fd, auth->client->localClient->ip.ss.ss_family,
247 <                SOCK_STREAM, 0, "ident") == -1)
248 <  {
249 <    report_error(L_ALL, "creating auth stream socket %s:%s",
250 <        get_client_name(auth->client, SHOW_IP), errno);
251 <    ilog(L_ERROR, "Unable to create auth socket for %s",
252 <        get_client_name(auth->client, SHOW_IP));
253 <    ++ServerStats.is_abad;
254 <    return 0;
255 <  }
229 >  IDENT_PORT_NUMBERS,
230 >  IDENT_REPLY_TYPE,
231 >  IDENT_OS_TYPE,
232 >  IDENT_INFO,
233 >  USERID_TOKEN_COUNT
234 > };
235  
236 <  sendheader(auth->client, REPORT_DO_ID);
236 > /** Parse an ident reply line and extract the userid from it.
237 > * \param reply The ident reply line.
238 > * \return The userid, or NULL on parse failure.
239 > */
240 > static const char *
241 > auth_check_ident_reply(char *const reply)
242 > {
243 >  char *token = NULL, *end = NULL;
244 >  char *vector[USERID_TOKEN_COUNT];
245 >  const unsigned int count = token_vector(reply, ':', vector, USERID_TOKEN_COUNT);
246  
247 <  /*
248 <   * get the local address of the client and bind to that to
249 <   * make the auth request.  This used to be done only for
250 <   * ifdef VIRTUAL_HOST, but needs to be done for all clients
251 <   * since the ident request must originate from that same address--
264 <   * and machines with multiple IP addresses are common now
247 >  if (USERID_TOKEN_COUNT != count)
248 >    return NULL;
249 >
250 >  /*
251 >   * Second token is the reply type
252     */
253 <  memset(&localaddr, 0, locallen);
267 <  getsockname(auth->client->localClient->fd.fd, (struct sockaddr*)&localaddr,
268 <      &locallen);
253 >  token = vector[IDENT_REPLY_TYPE];
254  
255 < #ifdef IPV6
256 <  remove_ipv6_mapping(&localaddr);
272 <  v6 = (struct sockaddr_in6 *)&localaddr;
273 <  v6->sin6_port = htons(0);
274 < #else
275 <  localaddr.ss_len = locallen;
276 <  v4 = (struct sockaddr_in *)&localaddr;
277 <  v4->sin_port = htons(0);
278 < #endif
279 <  localaddr.ss_port = htons(0);
280 <
281 <  comm_connect_tcp(&auth->fd, auth->client->sockhost, 113,
282 <      (struct sockaddr *)&localaddr, localaddr.ss_len, auth_connect_callback,
283 <      auth, auth->client->localClient->ip.ss.ss_family,
284 <      GlobalSetOptions.ident_timeout);
285 <  return 1; /* We suceed here for now */
286 < }
255 >  if (EmptyString(token))
256 >    return NULL;
257  
258 < /*
259 < * GetValidIdent - parse ident query reply from identd server
290 < *
291 < * Inputs        - pointer to ident buf
292 < * Output        - NULL if no valid ident found, otherwise pointer to name
293 < * Side effects  -
294 < */
295 < /*
296 < * A few questions have been asked about this mess, obviously
297 < * it should have been commented better the first time.
298 < * The original idea was to remove all references to libc from ircd-hybrid.
299 < * Instead of having to write a replacement for sscanf(), I did a
300 < * rather gruseome parser here so we could remove this function call.
301 < * Note, that I had also removed a few floating point printfs as well (though
302 < * now we are still stuck with a few...)
303 < * Remember, we have a replacement ircd sprintf, we have bleeps fputs lib
304 < * it would have been nice to remove some unneeded code.
305 < * Oh well. If we don't remove libc stuff totally, then it would be
306 < * far cleaner to use sscanf()
307 < *
308 < * - Dianora
309 < */
310 < static char *
311 < GetValidIdent(char *buf)
312 < {
313 <  int   remp = 0;
314 <  int   locp = 0;
315 <  char* colon1Ptr;
316 <  char* colon2Ptr;
317 <  char* colon3Ptr;
318 <  char* commaPtr;
319 <  char* remotePortString;
320 <
321 <  /* All this to get rid of a sscanf() fun. */
322 <  remotePortString = buf;
323 <  
324 <  if ((colon1Ptr = strchr(remotePortString,':')) == NULL)
325 <    return 0;
326 <  *colon1Ptr = '\0';
327 <  colon1Ptr++;
328 <
329 <  if ((colon2Ptr = strchr(colon1Ptr,':')) == NULL)
330 <    return 0;
331 <  *colon2Ptr = '\0';
332 <  colon2Ptr++;
333 <  
334 <  if ((commaPtr = strchr(remotePortString, ',')) == NULL)
335 <    return 0;
336 <  *commaPtr = '\0';
337 <  commaPtr++;
338 <
339 <  if ((remp = atoi(remotePortString)) == 0)
340 <    return 0;
341 <              
342 <  if ((locp = atoi(commaPtr)) == 0)
343 <    return 0;
344 <
345 <  /* look for USERID bordered by first pair of colons */
346 <  if (strstr(colon1Ptr, "USERID") == NULL)
347 <    return 0;
348 <
349 <  if ((colon3Ptr = strchr(colon2Ptr,':')) == NULL)
350 <    return 0;
351 <  *colon3Ptr = '\0';
352 <  colon3Ptr++;
353 <  return (colon3Ptr);
354 < }
258 >  while (IsSpace(*token))
259 >    ++token;
260  
261 < /*
262 < * start_auth
358 < *
359 < * inputs       - pointer to client to auth
360 < * output       - NONE
361 < * side effects - starts auth (identd) and dns queries for a client
362 < */
363 < static void *
364 < start_auth(va_list args)
365 < {
366 <  struct Client *client = va_arg(args, struct Client *);
367 <  struct AuthRequest *auth = NULL;
261 >  if (strncmp(token, "USERID", 6))
262 >    return NULL;
263  
264 <  assert(client != NULL);
264 >  /*
265 >   * Third token is the os type
266 >   */
267 >  token = vector[IDENT_OS_TYPE];
268  
269 <  auth = make_auth_request(client);
270 <  dlinkAdd(auth, &auth->node, &auth_doing_list);
269 >  if (EmptyString(token))
270 >    return NULL;
271  
272 <  sendheader(client, REPORT_DO_DNS);
272 >  while (IsSpace(*token))
273 >   ++token;
274  
275 <  SetDNSPending(auth);
275 >  /*
276 >   * Unless "OTHER" is specified as the operating system type, the server
277 >   * is expected to return the "normal" user identification of the owner
278 >   * of this connection. "Normal" in this context may be taken to mean a
279 >   * string of characters which uniquely identifies the connection owner
280 >   * such as a user identifier assigned by the system administrator and
281 >   * used by such user as a mail identifier, or as the "user" part of a
282 >   * user/password pair used to gain access to system resources. When an
283 >   * operating system is specified (e.g., anything but "OTHER"), the user
284 >   * identifier is expected to be in a more or less immediately useful
285 >   * form - e.g., something that could be used as an argument to "finger"
286 >   * or as a mail address.
287 >   */
288 >  if (strncmp(token, "OTHER", 5) == 0)
289 >    return NULL;
290  
291 <  if (ConfigFileEntry.disable_auth == 0)
292 <  {
293 <    SetDoingAuth(auth);
294 <    start_auth_query(auth);
295 <  }
291 >  /*
292 >   * Fourth token is the username
293 >   */
294 >  token = vector[IDENT_INFO];
295 >
296 >  if (EmptyString(token))
297 >    return NULL;
298  
299 <  gethost_byaddr(auth_dns_callback, auth, &client->localClient->ip);
299 >  while (IsSpace(*token))
300 >    ++token;
301  
302 <  return NULL;
302 >  while (*token == '~' || *token == '^')
303 >    ++token;
304 >
305 >  /*
306 >   * Look for the end of the username, terminators are '\0, @, <SPACE>, :'
307 >   */
308 >  for (end = token; *end; ++end)
309 >    if (IsSpace(*end) || '@' == *end || ':' == *end)
310 >      break;
311 >  *end = '\0';
312 >
313 >  return token;
314   }
315  
316 < /*
317 < * timeout_auth_queries - timeout resolver and identd requests
318 < * allow clients through if requests failed
316 > /*! \brief Read the reply (if any) from the ident server we connected to. We
317 > *         only give it one shot, if the reply isn't good the first time fail
318 > *         the authentication entirely. --Bleep
319 > * \param F The socket/fd to read from.
320 > * \param data The request to read.
321   */
322   static void
323 < timeout_auth_queries_event(void *notused)
323 > auth_read_reply(fde_t *F, void *data)
324   {
325 <  dlink_node *ptr = NULL, *next_ptr = NULL;
325 >  struct AuthRequest *const auth = data;
326 >  const char *username = NULL;
327 >  ssize_t len = 0;
328 >  char buf[RFC1413_BUFSIZ + 1];
329 >
330 >  assert(auth->fd == F);
331 >  assert(auth->client);
332 >  assert(auth->client->connection);
333  
334 <  DLINK_FOREACH_SAFE(ptr, next_ptr, auth_doing_list.head)
334 >  if (F->read_handler == NULL && (len = recv(auth->fd->fd, buf, sizeof(buf) - 1, 0)) > 0)
335    {
336 <    struct AuthRequest *auth = ptr->data;
336 >    buf[len] = '\0';
337 >    username = auth_check_ident_reply(buf);
338 >  }
339  
340 <    if (auth->timeout > CurrentTime)
341 <      continue;
340 >  fd_close(auth->fd);
341 >  auth->fd = NULL;
342 >  auth->ident_pending = false;
343  
344 <    if (IsDoingAuth(auth))
345 <    {  
346 <      ++ServerStats.is_abad;
347 <      fd_close(&auth->fd);
348 <      ClearAuth(auth);
349 <      sendheader(auth->client, REPORT_FAIL_ID);
350 <    }
351 <
352 <    if (IsDNSPending(auth))
353 <    {
354 <      delete_resolver_queries(auth);
416 <      ClearDNSPending(auth);
417 <      sendheader(auth->client, REPORT_FAIL_DNS);
418 <    }
419 <
420 <    ilog(L_INFO, "DNS/AUTH timeout %s",
421 <         get_client_name(auth->client, SHOW_IP));
422 <    release_auth_client(auth);
344 >  if (EmptyString(username))
345 >  {
346 >    auth_sendheader(auth->client, REPORT_FAIL_ID);
347 >    ++ServerStats.is_abad;
348 >  }
349 >  else
350 >  {
351 >    strlcpy(auth->client->username, username, sizeof(auth->client->username));
352 >    auth_sendheader(auth->client, REPORT_FIN_ID);
353 >    ++ServerStats.is_asuc;
354 >    AddFlag(auth->client, FLAGS_GOTID);
355    }
356 +
357 +  auth_release_client(auth);
358   }
359  
360   /*
# Line 435 | Line 369 | timeout_auth_queries_event(void *notused
369   * problems arise. -avalon
370   */
371   static void
372 < auth_connect_callback(fde_t *fd, int error, void *data)
372 > auth_connect_callback(fde_t *F, int error, void *data)
373   {
374 <  struct AuthRequest *auth = data;
374 >  struct AuthRequest *const auth = data;
375    struct irc_ssaddr us;
376    struct irc_ssaddr them;
377 <  char authbuf[32];
377 >  char authbuf[16];
378 >  ssize_t len = 0;
379    socklen_t ulen = sizeof(struct irc_ssaddr);
380    socklen_t tlen = sizeof(struct irc_ssaddr);
381    uint16_t uport, tport;
447 #ifdef IPV6
382    struct sockaddr_in6 *v6;
383 < #else
384 <  struct sockaddr_in *v4;
385 < #endif
383 >
384 >  assert(auth->fd == F);
385 >  assert(auth->client);
386 >  assert(auth->client->connection);
387  
388    if (error != COMM_OK)
389    {
# Line 456 | Line 391 | auth_connect_callback(fde_t *fd, int err
391      return;
392    }
393  
394 <  if (getsockname(auth->client->localClient->fd.fd, (struct sockaddr *)&us,
395 <      &ulen) ||
461 <      getpeername(auth->client->localClient->fd.fd, (struct sockaddr *)&them,
462 <      &tlen))
394 >  if (getsockname(auth->client->connection->fd->fd, (struct sockaddr *)&us, &ulen) ||
395 >      getpeername(auth->client->connection->fd->fd, (struct sockaddr *)&them, &tlen))
396    {
397 <    ilog(L_INFO, "auth get{sock,peer}name error for %s",
398 <        get_client_name(auth->client, SHOW_IP));
397 >    report_error(L_ALL, "auth get{sock,peer}name error %s:%s",
398 >                 client_get_name(auth->client, SHOW_IP), errno);
399      auth_error(auth);
400      return;
401    }
402  
470 #ifdef IPV6
403    v6 = (struct sockaddr_in6 *)&us;
404    uport = ntohs(v6->sin6_port);
405    v6 = (struct sockaddr_in6 *)&them;
406    tport = ntohs(v6->sin6_port);
475  remove_ipv6_mapping(&us);
476  remove_ipv6_mapping(&them);
477 #else
478  v4 = (struct sockaddr_in *)&us;
479  uport = ntohs(v4->sin_port);
480  v4 = (struct sockaddr_in *)&them;
481  tport = ntohs(v4->sin_port);
482  us.ss_len = ulen;
483  them.ss_len = tlen;
484 #endif
485  
486  snprintf(authbuf, sizeof(authbuf), "%u , %u\r\n", tport, uport);
407  
408 <  if (send(fd->fd, authbuf, strlen(authbuf), 0) == -1)
408 >  len = snprintf(authbuf, sizeof(authbuf), "%u, %u\r\n", tport, uport);
409 >
410 >  if (send(F->fd, authbuf, len, 0) != len)
411    {
412      auth_error(auth);
413      return;
414    }
415  
416 <  read_auth_reply(&auth->fd, auth);
416 >  comm_setselect(F, COMM_SELECT_READ, auth_read_reply, auth, 3);
417   }
418  
419 < /*
420 < * read_auth_reply - read the reply (if any) from the ident server
421 < * we connected to.
422 < * We only give it one shot, if the reply isn't good the first time
423 < * fail the authentication entirely. --Bleep
419 > /*! \brief Flag the client to show an attempt to contact the ident server on
420 > *         the client's host. Should the connect or any later phase of the
421 > *         identifying process fail, it is aborted and the user is given a
422 > *         username of "unknown".
423 > * \param auth The request for which to start the ident lookup.
424   */
503 #define AUTH_BUFSIZ 128
504
425   static void
426 < read_auth_reply(fde_t *fd, void *data)
426 > auth_start_query(struct AuthRequest *auth)
427   {
428 <  struct AuthRequest *auth = data;
429 <  char *s = NULL;
430 <  char *t = NULL;
431 <  int len;
432 <  int count;
433 <  char buf[AUTH_BUFSIZ + 1]; /* buffer to read auth reply into */
514 <
515 <  /* Why?
516 <   * Well, recv() on many POSIX systems is a per-packet operation,
517 <   * and we do not necessarily want this, because on lowspec machines,
518 <   * the ident response may come back fragmented, thus resulting in an
519 <   * invalid ident response, even if the ident response was really OK.
520 <   *
521 <   * So PLEASE do not change this code to recv without being aware of the
522 <   * consequences.
523 <   *
524 <   *    --nenolod
525 <   */
526 <  len = read(fd->fd, buf, AUTH_BUFSIZ);
428 >  struct irc_ssaddr localaddr;
429 >  socklen_t locallen = sizeof(struct irc_ssaddr);
430 >  struct sockaddr_in6 *v6;
431 >
432 >  assert(auth->client);
433 >  assert(auth->client->connection);
434  
435 <  if (len < 0)
435 >  /* Open a socket of the same type as the client socket */
436 >  int fd = comm_socket(auth->client->ip.ss.ss_family, SOCK_STREAM, 0);
437 >  if (fd == -1)
438    {
439 <    if (ignoreErrno(errno))
440 <      comm_setselect(fd, COMM_SELECT_READ, read_auth_reply, auth, 0);
441 <    else
533 <      auth_error(auth);
439 >    report_error(L_ALL, "creating auth stream socket %s:%s",
440 >                 client_get_name(auth->client, SHOW_IP), errno);
441 >    ++ServerStats.is_abad;
442      return;
443    }
444  
445 <  if (len > 0)
446 <  {
539 <    buf[len] = '\0';
445 >  auth->fd = fd_open(fd, true, "ident");
446 >  auth->ident_pending = true;
447  
448 <    if ((s = GetValidIdent(buf)))
542 <    {
543 <      t = auth->client->username;
544 <
545 <      while (*s == '~' || *s == '^')
546 <        s++;
547 <
548 <      for (count = USERLEN; *s && count; s++)
549 <      {
550 <        if (*s == '@')
551 <          break;
552 <        if (!IsSpace(*s) && *s != ':' && *s != '[')
553 <        {
554 <          *t++ = *s;
555 <          count--;
556 <        }
557 <      }
448 >  auth_sendheader(auth->client, REPORT_DO_ID);
449  
450 <      *t = '\0';
451 <    }
452 <  }
450 >  /*
451 >   * Get the local address of the client and bind to that to
452 >   * make the auth request.
453 >   */
454 >  memset(&localaddr, 0, locallen);
455 >  getsockname(auth->client->connection->fd->fd, (struct sockaddr *)&localaddr, &locallen);
456  
457 <  fd_close(fd);
457 >  remove_ipv6_mapping(&localaddr);
458 >  v6 = (struct sockaddr_in6 *)&localaddr;
459 >  v6->sin6_port = htons(0);
460  
461 <  ClearAuth(auth);
461 >  comm_connect_tcp(auth->fd, &auth->client->ip, RFC1413_PORT, &localaddr,
462 >                   auth_connect_callback, auth, 5);
463 > }
464  
465 <  if (s == NULL)
466 <  {
467 <    sendheader(auth->client, REPORT_FAIL_ID);
468 <    ++ServerStats.is_abad;
469 <  }
470 <  else
471 <  {
472 <    sendheader(auth->client, REPORT_FIN_ID);
473 <    ++ServerStats.is_asuc;
474 <    SetGotId(auth->client);
475 <  }
465 > /*
466 > * auth_start
467 > *
468 > * inputs       - pointer to client to auth
469 > * output       - NONE
470 > * side effects - starts auth (identd) and dns queries for a client
471 > */
472 > void
473 > auth_start(struct Client *client_p)
474 > {
475 >  struct AuthRequest *auth = auth_make(client_p);
476 >
477 >  assert(client_p);
478 >  assert(client_p->connection);
479  
480 <  release_auth_client(auth);
480 >  auth_sendheader(client_p, REPORT_DO_DNS);
481 >
482 >  auth->dns_pending = true;
483 >
484 >  if (ConfigGeneral.disable_auth == 0)
485 >    auth_start_query(auth);
486 >
487 >  gethost_byaddr(auth_dns_callback, auth, &client_p->ip);
488   }
489  
490   /*
491 < * delete_auth()
491 > * auth_delete()
492   */
493 < void
494 < delete_auth(struct AuthRequest *auth)
493 > void
494 > auth_delete(struct AuthRequest *auth)
495   {
496 <  if (IsDNSPending(auth))
497 <    delete_resolver_queries(auth);
496 >  assert(auth->client);
497 >  assert(auth->client->connection);
498 >
499 >  if (auth->fd)
500 >  {
501 >    fd_close(auth->fd);
502 >    auth->fd = NULL;
503 >  }
504 >
505 >  auth->ident_pending = false;
506  
507 <  if (IsDoingAuth(auth))
508 <    fd_close(&auth->fd);
507 >  delete_resolver_queries(auth);
508 >  auth->dns_pending = false;
509  
510 <  dlinkDelete(&auth->node, &auth_doing_list);
595 <  BlockHeapFree(auth_heap, auth);
510 >  auth_free(auth);
511   }

Comparing:
ircd-hybrid/src/s_auth.c (property svn:keywords), Revision 1155 by michael, Tue Aug 9 20:27:45 2011 UTC vs.
ircd-hybrid/trunk/src/auth.c (property svn:keywords), Revision 8919 by michael, Mon Apr 22 09:52:53 2019 UTC

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

Diff Legend

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