ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/auth.c
Revision: 8620
Committed: Sat Nov 3 17:46:37 2018 UTC (6 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 15168 byte(s)
Log Message:
- Stylistic changes

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2018 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
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file auth.c
23 * \brief Implementation of DNS and ident lookups.
24 * \version $Id$
25 */
26
27 /*
28 * Changes:
29 * July 6, 1999 - Rewrote most of the code here. When a client connects
30 * to the server and passes initial socket validation checks, it
31 * is owned by this module (auth) which returns it to the rest of the
32 * server when dns and auth queries are finished. Until the client is
33 * released, the server does not know it exists and does not process
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 "auth.h"
43 #include "conf.h"
44 #include "client.h"
45 #include "event.h"
46 #include "irc_string.h"
47 #include "ircd.h"
48 #include "packet.h"
49 #include "res.h"
50 #include "s_bsd.h"
51 #include "log.h"
52 #include "send.h"
53 #include "memory.h"
54
55
56 enum
57 {
58 REPORT_DO_DNS,
59 REPORT_FIN_DNS,
60 REPORT_FAIL_DNS,
61 REPORT_DO_ID,
62 REPORT_FIN_ID,
63 REPORT_FAIL_ID,
64 REPORT_IP_MISMATCH,
65 REPORT_HOST_TOOLONG,
66 REPORT_HOST_INVALID
67 };
68
69 static const char *const HeaderMessages[] =
70 {
71 [REPORT_DO_DNS] = ":*** Looking up your hostname",
72 [REPORT_FIN_DNS] = ":*** Found your hostname",
73 [REPORT_FAIL_DNS] = ":*** Couldn't look up your hostname",
74 [REPORT_DO_ID] = ":*** Checking Ident",
75 [REPORT_FIN_ID] = ":*** Got Ident response",
76 [REPORT_FAIL_ID] = ":*** No Ident response",
77 [REPORT_IP_MISMATCH] = ":*** Your forward and reverse DNS do not match, ignoring hostname",
78 [REPORT_HOST_TOOLONG] = ":*** Your hostname is too long, ignoring hostname",
79 [REPORT_HOST_INVALID] = ":*** Your hostname contains illegal characters, ignoring hostname"
80 };
81
82 #define auth_sendheader(c, i) sendto_one_notice((c), &me, "%s", HeaderMessages[(i)])
83
84 static dlink_list auth_list;
85
86
87 /*! \brief Allocate a new auth request.
88 * \param client The client being looked up.
89 * \return The newly allocated auth request.
90 */
91 static struct AuthRequest *
92 auth_make(struct Client *client)
93 {
94 struct AuthRequest *auth = xcalloc(sizeof(*auth));
95
96 auth->client = client;
97 auth->client->connection->auth = auth;
98 auth->timeout = CurrentTime + CONNECTTIMEOUT;
99
100 return auth;
101 }
102
103 /*! \brief Unlink auth request from auth_list and free memory
104 * \param auth The allocated auth request to cleanup.
105 */
106 static void
107 auth_free(struct AuthRequest *auth)
108 {
109 assert(dlinkFind(&auth_list, auth));
110 dlinkDelete(&auth->node, &auth_list);
111 assert(dlinkFind(&auth_list, auth) == NULL);
112
113 xfree(auth);
114 }
115
116 /*! \brief Release auth client from auth system. This adds the client into the
117 * local client lists so it can be read by the main io processing loop.
118 * \param auth Pointer to AuthRequest struct to release
119 */
120 static void
121 auth_release_client(struct AuthRequest *auth)
122 {
123 struct Client *client = auth->client;
124
125 if (IsDoingAuth(auth) || IsDNSPending(auth))
126 return;
127
128 auth_free(auth);
129 client->connection->auth = NULL;
130
131 /*
132 * When a client has auth'ed, we want to start reading what it sends
133 * us. This is what read_packet() does.
134 * -- adrian
135 */
136 client->connection->allow_read = MAX_FLOOD;
137 comm_setflush(client->connection->fd, 1000, flood_recalc, client);
138
139 client->connection->since = CurrentTime;
140 client->connection->lasttime = CurrentTime;
141 client->connection->firsttime = CurrentTime;
142 AddFlag(client, FLAGS_FINISHED_AUTH);
143
144 strlcpy(client->realhost, client->host, sizeof(client->realhost));
145
146 read_packet(client->connection->fd, client);
147 }
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 int
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 0;
162
163 for (; *p; ++p)
164 if (!IsHostChar(*p))
165 return 0;
166
167 return 1;
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, size_t namelength)
179 {
180 struct AuthRequest *const auth = vptr;
181
182 ClearDNSPending(auth);
183
184 if (EmptyString(name))
185 auth_sendheader(auth->client, REPORT_FAIL_DNS);
186 else
187 {
188 if (auth->client->ip.ss.ss_family == AF_INET6)
189 {
190 const struct sockaddr_in6 *const v6 = (const struct sockaddr_in6 *)&auth->client->ip;
191 const struct sockaddr_in6 *const v6dns = (const struct sockaddr_in6 *)addr;
192
193 if (memcmp(&v6->sin6_addr, &v6dns->sin6_addr, sizeof(struct in6_addr)))
194 {
195 auth_sendheader(auth->client, REPORT_IP_MISMATCH);
196 auth_release_client(auth);
197 return;
198 }
199 }
200 else
201 {
202 const struct sockaddr_in *const v4 = (const struct sockaddr_in *)&auth->client->ip;
203 const struct sockaddr_in *const v4dns = (const struct sockaddr_in *)addr;
204
205 if (v4->sin_addr.s_addr != v4dns->sin_addr.s_addr)
206 {
207 auth_sendheader(auth->client, REPORT_IP_MISMATCH);
208 auth_release_client(auth);
209 return;
210 }
211 }
212
213 if (namelength > HOSTLEN)
214 auth_sendheader(auth->client, REPORT_HOST_TOOLONG);
215 else if (auth_verify_hostname(name) == 0)
216 auth_sendheader(auth->client, REPORT_HOST_INVALID);
217 else
218 {
219 strlcpy(auth->client->host, name, sizeof(auth->client->host));
220 auth_sendheader(auth->client, REPORT_FIN_DNS);
221 }
222 }
223
224 auth_release_client(auth);
225 }
226
227 /*
228 * auth_error - handle auth send errors
229 */
230 static void
231 auth_error(struct AuthRequest *auth)
232 {
233 assert(auth);
234 assert(auth->fd);
235
236 ++ServerStats.is_abad;
237
238 fd_close(auth->fd);
239 auth->fd = NULL;
240
241 ClearAuth(auth);
242
243 auth_sendheader(auth->client, REPORT_FAIL_ID);
244
245 auth_release_client(auth);
246 }
247
248 /** Enum used to index ident reply fields in a human-readable way. */
249 enum IdentReplyFields
250 {
251 IDENT_PORT_NUMBERS,
252 IDENT_REPLY_TYPE,
253 IDENT_OS_TYPE,
254 IDENT_INFO,
255 USERID_TOKEN_COUNT
256 };
257
258 /** Parse an ident reply line and extract the userid from it.
259 * \param reply The ident reply line.
260 * \return The userid, or NULL on parse failure.
261 */
262 static const char *
263 auth_check_ident_reply(char *const reply)
264 {
265 char *token = NULL, *end = NULL;
266 char *vector[USERID_TOKEN_COUNT];
267 const unsigned int count = token_vector(reply, ':', vector, USERID_TOKEN_COUNT);
268
269 if (USERID_TOKEN_COUNT != count)
270 return NULL;
271
272 /*
273 * Second token is the reply type
274 */
275 token = vector[IDENT_REPLY_TYPE];
276
277 if (EmptyString(token))
278 return NULL;
279
280 while (IsSpace(*token))
281 ++token;
282
283 if (strncmp(token, "USERID", 6))
284 return NULL;
285
286 /*
287 * Third token is the os type
288 */
289 token = vector[IDENT_OS_TYPE];
290
291 if (EmptyString(token))
292 return NULL;
293
294 while (IsSpace(*token))
295 ++token;
296
297 /*
298 * Unless "OTHER" is specified as the operating system type, the server
299 * is expected to return the "normal" user identification of the owner
300 * of this connection. "Normal" in this context may be taken to mean a
301 * string of characters which uniquely identifies the connection owner
302 * such as a user identifier assigned by the system administrator and
303 * used by such user as a mail identifier, or as the "user" part of a
304 * user/password pair used to gain access to system resources. When an
305 * operating system is specified (e.g., anything but "OTHER"), the user
306 * identifier is expected to be in a more or less immediately useful
307 * form - e.g., something that could be used as an argument to "finger"
308 * or as a mail address.
309 */
310 if (strncmp(token, "OTHER", 5) == 0)
311 return NULL;
312
313 /*
314 * Fourth token is the username
315 */
316 token = vector[IDENT_INFO];
317
318 if (EmptyString(token))
319 return NULL;
320
321 while (IsSpace(*token))
322 ++token;
323
324 while (*token == '~' || *token == '^')
325 ++token;
326
327 /*
328 * Look for the end of the username, terminators are '\0, @, <SPACE>, :'
329 */
330 for (end = token; *end; ++end)
331 if (IsSpace(*end) || '@' == *end || ':' == *end)
332 break;
333 *end = '\0';
334
335 return token;
336 }
337
338 /*! \brief Read the reply (if any) from the ident server we connected to. We
339 * only give it one shot, if the reply isn't good the first time fail
340 * the authentication entirely. --Bleep
341 * \param F The socket/fd to read from.
342 * \param data The request to read.
343 */
344 static void
345 auth_read_reply(fde_t *F, void *data)
346 {
347 struct AuthRequest *const auth = data;
348 const char *username = NULL;
349 ssize_t len = 0;
350 char buf[RFC1413_BUFSIZ + 1];
351
352 assert(auth->fd == F);
353
354 if ((len = recv(auth->fd->fd, buf, RFC1413_BUFSIZ, 0)) > 0)
355 {
356 buf[len] = '\0';
357 username = auth_check_ident_reply(buf);
358 }
359
360 fd_close(auth->fd);
361 auth->fd = NULL;
362
363 ClearAuth(auth);
364
365 if (EmptyString(username))
366 {
367 auth_sendheader(auth->client, REPORT_FAIL_ID);
368 ++ServerStats.is_abad;
369 }
370 else
371 {
372 strlcpy(auth->client->username, username, sizeof(auth->client->username));
373 auth_sendheader(auth->client, REPORT_FIN_ID);
374 ++ServerStats.is_asuc;
375 AddFlag(auth->client, FLAGS_GOTID);
376 }
377
378 auth_release_client(auth);
379 }
380
381 /*
382 * auth_connect_callback() - deal with the result of comm_connect_tcp()
383 *
384 * If the connection failed, we simply close the auth fd and report
385 * a failure. If the connection suceeded send the ident server a query
386 * giving "theirport , ourport". The write is only attempted *once* so
387 * it is deemed to be a fail if the entire write doesn't write all the
388 * data given. This shouldnt be a problem since the socket should have
389 * a write buffer far greater than this message to store it in should
390 * problems arise. -avalon
391 */
392 static void
393 auth_connect_callback(fde_t *F, int error, void *data)
394 {
395 struct AuthRequest *const auth = data;
396 struct irc_ssaddr us;
397 struct irc_ssaddr them;
398 char authbuf[16];
399 ssize_t len = 0;
400 socklen_t ulen = sizeof(struct irc_ssaddr);
401 socklen_t tlen = sizeof(struct irc_ssaddr);
402 uint16_t uport, tport;
403 struct sockaddr_in6 *v6;
404
405 if (error != COMM_OK)
406 {
407 auth_error(auth);
408 return;
409 }
410
411 assert(auth->fd == F);
412
413 if (getsockname(auth->client->connection->fd->fd, (struct sockaddr *)&us, &ulen) ||
414 getpeername(auth->client->connection->fd->fd, (struct sockaddr *)&them, &tlen))
415 {
416 report_error(L_ALL, "auth get{sock,peer}name error %s:%s",
417 client_get_name(auth->client, SHOW_IP), errno);
418 auth_error(auth);
419 return;
420 }
421
422 v6 = (struct sockaddr_in6 *)&us;
423 uport = ntohs(v6->sin6_port);
424 v6 = (struct sockaddr_in6 *)&them;
425 tport = ntohs(v6->sin6_port);
426
427 len = snprintf(authbuf, sizeof(authbuf), "%u, %u\r\n", tport, uport);
428
429 if (send(F->fd, authbuf, len, 0) != len)
430 {
431 auth_error(auth);
432 return;
433 }
434
435 comm_setselect(F, COMM_SELECT_READ, auth_read_reply, auth, 0);
436 }
437
438 /*! \brief Flag the client to show an attempt to contact the ident server on
439 * the client's host. Should the connect or any later phase of the
440 * identifying process fail, it is aborted and the user is given a
441 * username of "unknown".
442 * \param auth The request for which to start the ident lookup.
443 */
444 static void
445 auth_start_query(struct AuthRequest *auth)
446 {
447 struct irc_ssaddr localaddr;
448 socklen_t locallen = sizeof(struct irc_ssaddr);
449 struct sockaddr_in6 *v6;
450
451 /* Open a socket of the same type as the client socket */
452 int fd = comm_socket(auth->client->ip.ss.ss_family, SOCK_STREAM, 0);
453 if (fd == -1)
454 {
455 report_error(L_ALL, "creating auth stream socket %s:%s",
456 client_get_name(auth->client, SHOW_IP), errno);
457 ++ServerStats.is_abad;
458 return;
459 }
460
461 auth->fd = fd_open(fd, 1, "ident");
462
463 SetDoingAuth(auth);
464 auth_sendheader(auth->client, REPORT_DO_ID);
465
466 /*
467 * Get the local address of the client and bind to that to
468 * make the auth request.
469 */
470 memset(&localaddr, 0, locallen);
471 getsockname(auth->client->connection->fd->fd, (struct sockaddr *)&localaddr, &locallen);
472
473 remove_ipv6_mapping(&localaddr);
474 v6 = (struct sockaddr_in6 *)&localaddr;
475 v6->sin6_port = htons(0);
476 localaddr.ss_port = htons(0);
477
478 comm_connect_tcp(auth->fd, auth->client->sockhost, RFC1413_PORT,
479 (struct sockaddr *)&localaddr, localaddr.ss_len, auth_connect_callback,
480 auth, auth->client->ip.ss.ss_family,
481 GlobalSetOptions.ident_timeout);
482 }
483
484 /*
485 * auth_start
486 *
487 * inputs - pointer to client to auth
488 * output - NONE
489 * side effects - starts auth (identd) and dns queries for a client
490 */
491 void
492 auth_start(struct Client *client_p)
493 {
494 struct AuthRequest *auth = auth_make(client_p);
495
496 dlinkAddTail(auth, &auth->node, &auth_list);
497
498 auth_sendheader(client_p, REPORT_DO_DNS);
499
500 SetDNSPending(auth);
501
502 if (ConfigGeneral.disable_auth == 0)
503 auth_start_query(auth);
504
505 gethost_byaddr(auth_dns_callback, auth, &client_p->ip);
506 }
507
508 /*
509 * auth_delete()
510 */
511 void
512 auth_delete(struct AuthRequest *auth)
513 {
514 if (IsDoingAuth(auth))
515 {
516 fd_close(auth->fd);
517 auth->fd = NULL;
518
519 ClearAuth(auth);
520 }
521
522 if (IsDNSPending(auth))
523 {
524 delete_resolver_queries(auth);
525 ClearDNSPending(auth);
526 }
527
528 auth_free(auth);
529 }
530
531 /*
532 * auth_timeout_queries - timeout resolver and identd requests
533 * allow clients through if requests failed
534 */
535 static void
536 auth_timeout_queries(void *notused)
537 {
538 dlink_node *node, *node_next;
539
540 DLINK_FOREACH_SAFE(node, node_next, auth_list.head)
541 {
542 struct AuthRequest *auth = node->data;
543
544 if (auth->timeout > CurrentTime)
545 break;
546
547 if (IsDoingAuth(auth))
548 {
549 ++ServerStats.is_abad;
550
551 fd_close(auth->fd);
552 auth->fd = NULL;
553
554 ClearAuth(auth);
555
556 auth_sendheader(auth->client, REPORT_FAIL_ID);
557 }
558
559 if (IsDNSPending(auth))
560 {
561 delete_resolver_queries(auth);
562 ClearDNSPending(auth);
563
564 auth_sendheader(auth->client, REPORT_FAIL_DNS);
565 }
566
567 auth_release_client(auth);
568 }
569 }
570
571 /* auth_init
572 *
573 * Initialise the auth code
574 */
575 void
576 auth_init(void)
577 {
578 static struct event timeout_auth_queries =
579 {
580 .name = "auth_timeout_queries",
581 .handler = auth_timeout_queries,
582 .when = 1
583 };
584
585 event_add(&timeout_auth_queries, NULL);
586 }

Properties

Name Value
svn:eol-style native
svn:keywords Id