ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/auth.c
Revision: 9101
Committed: Wed Jan 1 09:58:45 2020 UTC (5 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 13672 byte(s)
Log Message:
- Bump copyright years everywhere

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2020 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 #include "misc.h"
55
56
57 enum
58 {
59 REPORT_DO_DNS,
60 REPORT_FIN_DNS,
61 REPORT_FAIL_DNS,
62 REPORT_DO_ID,
63 REPORT_FIN_ID,
64 REPORT_FAIL_ID,
65 REPORT_IP_MISMATCH,
66 REPORT_HOST_TOOLONG,
67 REPORT_HOST_INVALID
68 };
69
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 #define auth_sendheader(c, i) sendto_one_notice((c), &me, "%s", HeaderMessages[(i)])
84
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
99 return auth;
100 }
101
102 /*! \brief Free memory
103 * \param auth The allocated auth request to cleanup.
104 */
105 static void
106 auth_free(struct AuthRequest *auth)
107 {
108 auth->client = NULL;
109 xfree(auth);
110 }
111
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 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 comm_setflush(client->connection->fd, 1, 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 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 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, size_t namelength)
179 {
180 struct AuthRequest *const auth = vptr;
181
182 assert(auth->client);
183 assert(auth->client->connection);
184
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 strlcpy(auth->client->host, name, sizeof(auth->client->host));
198 auth_sendheader(auth->client, REPORT_FIN_DNS);
199 }
200
201 auth_release_client(auth);
202 }
203
204 /*
205 * auth_error - handle auth send errors
206 */
207 static void
208 auth_error(struct AuthRequest *auth)
209 {
210 assert(auth);
211 assert(auth->fd);
212 assert(auth->client);
213 assert(auth->client->connection);
214
215 ++ServerStats.is_abad;
216
217 fd_close(auth->fd);
218 auth->fd = NULL;
219 auth->ident_pending = false;
220
221 auth_sendheader(auth->client, REPORT_FAIL_ID);
222
223 auth_release_client(auth);
224 }
225
226 /** Enum used to index ident reply fields in a human-readable way. */
227 enum IdentReplyFields
228 {
229 IDENT_PORT_NUMBERS,
230 IDENT_REPLY_TYPE,
231 IDENT_OS_TYPE,
232 IDENT_INFO,
233 USERID_TOKEN_COUNT
234 };
235
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 if (USERID_TOKEN_COUNT != count)
248 return NULL;
249
250 /*
251 * Second token is the reply type
252 */
253 token = vector[IDENT_REPLY_TYPE];
254
255 if (EmptyString(token))
256 return NULL;
257
258 while (IsSpace(*token))
259 ++token;
260
261 if (strncmp(token, "USERID", 6))
262 return NULL;
263
264 /*
265 * Third token is the os type
266 */
267 token = vector[IDENT_OS_TYPE];
268
269 if (EmptyString(token))
270 return NULL;
271
272 while (IsSpace(*token))
273 ++token;
274
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 /*
292 * Fourth token is the username
293 */
294 token = vector[IDENT_INFO];
295
296 if (EmptyString(token))
297 return NULL;
298
299 while (IsSpace(*token))
300 ++token;
301
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 /*! \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 auth_read_reply(fde_t *F, void *data)
324 {
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 if (F->read_handler == NULL && (len = recv(auth->fd->fd, buf, sizeof(buf) - 1, 0)) > 0)
335 {
336 buf[len] = '\0';
337 username = auth_check_ident_reply(buf);
338 }
339
340 fd_close(auth->fd);
341 auth->fd = NULL;
342 auth->ident_pending = false;
343
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 /*
361 * auth_connect_callback() - deal with the result of comm_connect_tcp()
362 *
363 * If the connection failed, we simply close the auth fd and report
364 * a failure. If the connection suceeded send the ident server a query
365 * giving "theirport , ourport". The write is only attempted *once* so
366 * it is deemed to be a fail if the entire write doesn't write all the
367 * data given. This shouldnt be a problem since the socket should have
368 * a write buffer far greater than this message to store it in should
369 * problems arise. -avalon
370 */
371 static void
372 auth_connect_callback(fde_t *F, int error, void *data)
373 {
374 struct AuthRequest *const auth = data;
375 struct irc_ssaddr us;
376 struct irc_ssaddr them;
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;
382 struct sockaddr_in6 *v6;
383
384 assert(auth->fd == F);
385 assert(auth->client);
386 assert(auth->client->connection);
387
388 if (error != COMM_OK)
389 {
390 auth_error(auth);
391 return;
392 }
393
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 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
403 v6 = (struct sockaddr_in6 *)&us;
404 uport = ntohs(v6->sin6_port);
405 v6 = (struct sockaddr_in6 *)&them;
406 tport = ntohs(v6->sin6_port);
407
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 comm_setselect(F, COMM_SELECT_READ, auth_read_reply, auth, 4);
417 }
418
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 */
425 static void
426 auth_start_query(struct AuthRequest *auth)
427 {
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 /* 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 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 auth->fd = fd_open(fd, true, "ident");
446 auth->ident_pending = true;
447
448 auth_sendheader(auth->client, REPORT_DO_ID);
449
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 remove_ipv6_mapping(&localaddr);
458 v6 = (struct sockaddr_in6 *)&localaddr;
459 v6->sin6_port = htons(0);
460
461 comm_connect_tcp(auth->fd, &auth->client->ip, RFC1413_PORT, &localaddr,
462 auth_connect_callback, auth, 4);
463 }
464
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 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 * auth_delete()
492 */
493 void
494 auth_delete(struct AuthRequest *auth)
495 {
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 delete_resolver_queries(auth);
508 auth->dns_pending = false;
509
510 auth_free(auth);
511 }

Properties

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