Author: Gte <gte@atomicrevs.demon.co.uk>
[ircu2.10.12-pk.git] / ircd / s_auth.c
1 /*
2  * IRC - Internet Relay Chat, ircd/s_auth.c
3  * Copyright (C) 1992 Darren Reed
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 1, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 #include "sys.h"
21 #include <sys/socket.h>
22 #if HAVE_SYS_FILE_H
23 #include <sys/file.h>
24 #endif
25 #if HAVE_SYS_IOCTL_H
26 #include <sys/ioctl.h>
27 #endif
28 #ifdef  UNIXPORT
29 #include <sys/un.h>
30 #endif
31 #if HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 #ifdef HPUX
35 #include <arpa/inet.h>
36 #endif /* HPUX */
37 #if HAVE_FCNTL_H
38 #include <fcntl.h>
39 #endif
40 #ifdef USE_SYSLOG
41 #include <syslog.h>
42 #endif
43 #include "h.h"
44 #include "res.h"
45 #include "struct.h"
46 #include "common.h"
47 #include "send.h"
48 #include "s_bsd.h"
49 #include "s_misc.h"
50 #include "support.h"
51 #include "ircd.h"
52 #include "s_auth.h"
53 #include "sprintf_irc.h"
54
55 RCSTAG_CC("$Id$");
56
57 /*
58  * start_auth
59  *
60  * Flag the client to show that an attempt to contact the ident server on
61  * the client's host.  The connect and subsequently the socket are all put
62  * into 'non-blocking' mode.  Should the connect or any later phase of the
63  * identifing process fail, it is aborted and the user is given a username
64  * of "unknown".
65  */
66 void start_auth(aClient *cptr)
67 {
68   struct sockaddr_in sock;
69   int err;
70   int len = sizeof(struct sockaddr_in);
71
72   Debug((DEBUG_NOTICE, "start_auth(%p) fd %d status %d",
73       cptr, cptr->fd, cptr->status));
74
75   alarm(2);
76   cptr->authfd = socket(AF_INET, SOCK_STREAM, 0);
77   err = errno;
78   alarm(0);
79   if (cptr->authfd < 0 && err == EAGAIN)
80     sendto_ops("Can't allocate fd for auth on %s : socket: No more sockets",
81         get_client_name(cptr, TRUE));
82
83   if (cptr->authfd < 0)
84   {
85 #ifdef  USE_SYSLOG
86     syslog(LOG_ERR, "Unable to create auth socket for %s:%m",
87         get_client_name(cptr, TRUE));
88 #endif
89     Debug((DEBUG_ERROR, "Unable to create auth socket for %s:%s",
90         get_client_name(cptr, TRUE), strerror(get_sockerr(cptr))));
91     if (!DoingDNS(cptr))
92       SetAccess(cptr);
93     ircstp->is_abad++;
94     return;
95   }
96   if (cptr->authfd >= (MAXCONNECTIONS - 2))
97   {
98     sendto_ops("Can't allocate fd for auth on %s", get_client_name(cptr, TRUE));
99     close(cptr->authfd);
100     cptr->authfd = -1;
101     return;
102   }
103
104   set_non_blocking(cptr->authfd, cptr);
105
106   if (getsockname(cptr->fd, (struct sockaddr *)&sock, &len) == -1
107       || (sock.sin_port = 0)    /* Reset sin_port and let OS choose the port */
108       || bind(cptr->authfd, (struct sockaddr *)&sock, len) == -1)
109   {
110     report_error("binding auth stream socket %s: %s", cptr);
111     close(cptr->authfd);
112     cptr->authfd = -1;
113     /*
114      * fsck can't return exit_client here ... let read_message
115      * do it when we get done here. At any rate this error is
116      * fatal for the client, mark it dead.
117      */
118     cptr->flags |= FLAGS_DEADSOCKET;
119     return;
120   }
121
122   memcpy(&sock.sin_addr, &cptr->ip, sizeof(struct in_addr));
123
124   sock.sin_port = htons(113);
125   sock.sin_family = AF_INET;
126
127   alarm((unsigned)4);
128   if (connect(cptr->authfd, (struct sockaddr *)&sock,
129       sizeof(sock)) == -1 && errno != EINPROGRESS)
130   {
131     ircstp->is_abad++;
132     /*
133      * No error report from this...
134      */
135     alarm((unsigned)0);
136     close(cptr->authfd);
137     cptr->authfd = -1;
138     if (!DoingDNS(cptr))
139       SetAccess(cptr);
140     return;
141   }
142   alarm((unsigned)0);
143   cptr->flags |= (FLAGS_WRAUTH | FLAGS_AUTH);
144   if (cptr->authfd > highest_fd)
145     highest_fd = cptr->authfd;
146   return;
147 }
148
149 /*
150  * send_authports
151  *
152  * Send the ident server a query giving "theirport , ourport".
153  * The write is only attempted *once* so it is deemed to be a fail if the
154  * entire write doesn't write all the data given.  This shouldnt be a
155  * problem since the socket should have a write buffer far greater than
156  * this message to store it in should problems arise. -avalon
157  */
158 void send_authports(aClient *cptr)
159 {
160   struct sockaddr_in us, them;
161   char authbuf[32];
162   size_t ulen, tlen;
163
164   Debug((DEBUG_NOTICE, "write_authports(%p) fd %d authfd %d stat %d",
165       cptr, cptr->fd, cptr->authfd, cptr->status));
166   tlen = ulen = sizeof(us);
167   if (getsockname(cptr->fd, (struct sockaddr *)&us, &ulen) ||
168       getpeername(cptr->fd, (struct sockaddr *)&them, &tlen))
169   {
170 #ifdef  USE_SYSLOG
171     syslog(LOG_ERR, "auth get{sock,peer}name error for %s:%m",
172         get_client_name(cptr, TRUE));
173 #endif
174     goto authsenderr;
175   }
176
177   sprintf_irc(authbuf, "%u , %u\r\n", (unsigned int)ntohs(them.sin_port),
178       (unsigned int)ntohs(us.sin_port));
179
180   Debug((DEBUG_SEND, "sending [%s] to auth port %s.113",
181       authbuf, inetntoa(them.sin_addr)));
182   if (write(cptr->authfd, authbuf, strlen(authbuf)) != (int)strlen(authbuf))
183   {
184   authsenderr:
185     ircstp->is_abad++;
186     close(cptr->authfd);
187     if (cptr->authfd == highest_fd)
188       while (!loc_clients[highest_fd])
189         highest_fd--;
190     cptr->authfd = -1;
191     cptr->flags &= ~FLAGS_AUTH;
192     if (!DoingDNS(cptr))
193       SetAccess(cptr);
194   }
195   cptr->flags &= ~FLAGS_WRAUTH;
196   return;
197 }
198
199 /*
200  * read_authports
201  *
202  * read the reply (if any) from the ident server we connected to.
203  * The actual read processijng here is pretty weak - no handling of the reply
204  * if it is fragmented by IP.
205  */
206 void read_authports(aClient *cptr)
207 {
208   Reg1 char *s, *t;
209   Reg2 int len;
210   char ruser[USERLEN + 1], system[8];
211   unsigned short int remp = 0, locp = 0;
212
213   *system = *ruser = '\0';
214   Debug((DEBUG_NOTICE, "read_authports(%p) fd %d authfd %d stat %d",
215       cptr, cptr->fd, cptr->authfd, cptr->status));
216   /*
217    * Nasty.  Cant allow any other reads from client fd while we're
218    * waiting on the authfd to return a full valid string.  Use the
219    * client's input buffer to buffer the authd reply.
220    * Oh. this is needed because an authd reply may come back in more
221    * than 1 read! -avalon
222    */
223   if ((len = read(cptr->authfd, cptr->buffer + cptr->count,
224       sizeof(cptr->buffer) - 1 - cptr->count)) >= 0)
225   {
226     cptr->count += len;
227     cptr->buffer[cptr->count] = '\0';
228   }
229
230   cptr->lasttime = now;
231   if ((len > 0) && (cptr->count != (sizeof(cptr->buffer) - 1)) &&
232       (sscanf(cptr->buffer, "%hd , %hd : USERID : %*[^:]: %10s",
233       &remp, &locp, ruser) == 3))
234   {
235     s = strrchr(cptr->buffer, ':');
236     *s++ = '\0';
237     for (t = (strrchr(cptr->buffer, ':') + 1); *t; t++)
238       if (!isSpace(*t))
239         break;
240     strncpy(system, t, sizeof(system) - 1);
241     system[sizeof(system) - 1] = 0;
242     for (t = ruser; *s && (t < ruser + sizeof(ruser)); s++)
243       if (!isSpace(*s) && *s != ':' && *s != '@')
244         *t++ = *s;
245     *t = '\0';
246     Debug((DEBUG_INFO, "auth reply ok [%s] [%s]", system, ruser));
247   }
248   else if (len != 0)
249   {
250     if (!strchr(cptr->buffer, '\n') && !strchr(cptr->buffer, '\r'))
251       return;
252     Debug((DEBUG_ERROR, "local %d remote %d", locp, remp));
253     Debug((DEBUG_ERROR, "bad auth reply in [%s]", cptr->buffer));
254     *ruser = '\0';
255   }
256   close(cptr->authfd);
257   if (cptr->authfd == highest_fd)
258     while (!loc_clients[highest_fd])
259       highest_fd--;
260   cptr->count = 0;
261   cptr->authfd = -1;
262   ClearAuth(cptr);
263   if (!DoingDNS(cptr))
264     SetAccess(cptr);
265   if (len > 0)
266     Debug((DEBUG_INFO, "ident reply: [%s]", cptr->buffer));
267
268   if (!locp || !remp || !*ruser)
269   {
270     ircstp->is_abad++;
271     return;
272   }
273   ircstp->is_asuc++;
274   strncpy(cptr->username, ruser, USERLEN);
275   cptr->username[USERLEN] = 0;  /* This is the LA bug --Run */
276   if (strncmp(system, "OTHER", 5))
277     cptr->flags |= FLAGS_GOTID;
278   Debug((DEBUG_INFO, "got username [%s]", ruser));
279   return;
280 }