PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/src/s_auth.c

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