2 * IRC - Internet Relay Chat, ircd/s_auth.c
3 * Copyright (C) 1992 Darren Reed
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)
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.
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.
21 #include <sys/socket.h>
26 #include <sys/ioctl.h>
35 #include <arpa/inet.h>
53 #include "sprintf_irc.h"
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
66 void start_auth(aClient *cptr)
68 struct sockaddr_in sock;
70 int len = sizeof(struct sockaddr_in);
72 Debug((DEBUG_NOTICE, "start_auth(%p) fd %d status %d",
73 cptr, cptr->fd, cptr->status));
76 cptr->authfd = socket(AF_INET, SOCK_STREAM, 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));
86 syslog(LOG_ERR, "Unable to create auth socket for %s:%m",
87 get_client_name(cptr, TRUE));
89 Debug((DEBUG_ERROR, "Unable to create auth socket for %s:%s",
90 get_client_name(cptr, TRUE), strerror(get_sockerr(cptr))));
96 if (cptr->authfd >= (MAXCONNECTIONS - 2))
98 sendto_ops("Can't allocate fd for auth on %s", get_client_name(cptr, TRUE));
104 set_non_blocking(cptr->authfd, cptr);
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)
110 report_error("binding auth stream socket %s: %s", cptr);
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.
118 cptr->flags |= FLAGS_DEADSOCKET;
122 memcpy(&sock.sin_addr, &cptr->ip, sizeof(struct in_addr));
124 sock.sin_port = htons(113);
125 sock.sin_family = AF_INET;
128 if (connect(cptr->authfd, (struct sockaddr *)&sock,
129 sizeof(sock)) == -1 && errno != EINPROGRESS)
133 * No error report from this...
143 cptr->flags |= (FLAGS_WRAUTH | FLAGS_AUTH);
144 if (cptr->authfd > highest_fd)
145 highest_fd = cptr->authfd;
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
158 void send_authports(aClient *cptr)
160 struct sockaddr_in us, them;
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))
171 syslog(LOG_ERR, "auth get{sock,peer}name error for %s:%m",
172 get_client_name(cptr, TRUE));
177 sprintf_irc(authbuf, "%u , %u\r\n", (unsigned int)ntohs(them.sin_port),
178 (unsigned int)ntohs(us.sin_port));
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))
187 if (cptr->authfd == highest_fd)
188 while (!loc_clients[highest_fd])
191 cptr->flags &= ~FLAGS_AUTH;
195 cptr->flags &= ~FLAGS_WRAUTH;
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.
206 void read_authports(aClient *cptr)
210 char ruser[USERLEN + 1], system[8];
211 unsigned short int remp = 0, locp = 0;
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));
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
223 if ((len = read(cptr->authfd, cptr->buffer + cptr->count,
224 sizeof(cptr->buffer) - 1 - cptr->count)) >= 0)
227 cptr->buffer[cptr->count] = '\0';
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))
235 s = strrchr(cptr->buffer, ':');
237 for (t = (strrchr(cptr->buffer, ':') + 1); *t; t++)
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 != '@')
246 Debug((DEBUG_INFO, "auth reply ok [%s] [%s]", system, ruser));
250 if (!strchr(cptr->buffer, '\n') && !strchr(cptr->buffer, '\r'))
252 Debug((DEBUG_ERROR, "local %d remote %d", locp, remp));
253 Debug((DEBUG_ERROR, "bad auth reply in [%s]", cptr->buffer));
257 if (cptr->authfd == highest_fd)
258 while (!loc_clients[highest_fd])
266 Debug((DEBUG_INFO, "ident reply: [%s]", cptr->buffer));
268 if (!locp || !remp || !*ruser)
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));