Annotation of ircnowd/src/ngircd/login.c, Revision 1.1.1.1
1.1 tomglok 1: /*
2: * ngIRCd -- The Next Generation IRC Daemon
3: * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
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 2 of the License, or
8: * (at your option) any later version.
9: * Please read the file COPYING, README and AUTHORS for more information.
10: */
11:
12: #include "portab.h"
13:
14: /**
15: * @file
16: * Functions to deal with client logins
17: */
18:
19: #include <assert.h>
20: #include <stdlib.h>
21: #include <stdio.h>
22: #include <string.h>
23: #include <unistd.h>
24:
25: #include "conn.h"
26: #include "class.h"
27: #include "client-cap.h"
28: #include "channel.h"
29: #include "conf.h"
30: #include "parse.h"
31: #include "log.h"
32: #include "messages.h"
33: #include "ngircd.h"
34: #include "irc-info.h"
35: #include "irc-mode.h"
36: #include "irc-write.h"
37:
38: #include "login.h"
39:
40: #ifdef PAM
41:
42: #include "io.h"
43: #include "pam.h"
44:
45: static void cb_Read_Auth_Result PARAMS((int r_fd, UNUSED short events));
46:
47: #endif
48:
49: /**
50: * Initiate client login.
51: *
52: * This function is called after the daemon received the required NICK and
53: * USER commands of a new client. If the daemon is compiled with support for
54: * PAM, the authentication sub-processs is forked; otherwise the global server
55: * password is checked.
56: *
57: * @param Client The client logging in.
58: * @returns CONNECTED or DISCONNECTED.
59: */
60: GLOBAL bool
61: Login_User(CLIENT * Client)
62: {
63: #ifdef PAM
64: int pipefd[2], result;
65: pid_t pid;
66: #endif
67: CONN_ID conn;
68:
69: assert(Client != NULL);
70: conn = Client_Conn(Client);
71:
72: #ifndef STRICT_RFC
73: if (Conf_AuthPing) {
74: /* Did we receive the "auth PONG" already? */
75: if (Conn_GetAuthPing(conn)) {
76: Client_SetType(Client, CLIENT_WAITAUTHPING);
77: LogDebug("Connection %d: Waiting for AUTH PONG ...", conn);
78: return CONNECTED;
79: }
80: }
81: #endif
82:
83: /* Still waiting for "CAP END" command? */
84: if (Client_Cap(Client) & CLIENT_CAP_PENDING) {
85: Client_SetType(Client, CLIENT_WAITCAPEND);
86: LogDebug("Connection %d: Waiting for CAP END ...", conn);
87: return CONNECTED;
88: }
89:
90: #ifdef PAM
91: if (!Conf_PAM) {
92: /* Don't do any PAM authentication at all if PAM is not
93: * enabled, instead emulate the behavior of the daemon
94: * compiled without PAM support. */
95: if (strcmp(Conn_Password(conn), Conf_ServerPwd) == 0)
96: return Login_User_PostAuth(Client);
97: Client_Reject(Client, "Bad server password", false);
98: return DISCONNECTED;
99: }
100:
101: if (Conf_PAMIsOptional &&
102: strcmp(Conn_Password(conn), "") == 0) {
103: /* Clients are not required to send a password and to be PAM-
104: * authenticated at all. If not, they won't become "identified"
105: * and keep the "~" in their supplied user name.
106: * Therefore it is sensible to either set Conf_PAMisOptional or
107: * to enable IDENT lookups -- not both. */
108: return Login_User_PostAuth(Client);
109: }
110:
111: if (Conf_PAM) {
112: /* Fork child process for PAM authentication; and make sure that the
113: * process timeout is set higher than the login timeout! */
114: pid = Proc_Fork(Conn_GetProcStat(conn), pipefd,
115: cb_Read_Auth_Result, Conf_PongTimeout + 1);
116: if (pid > 0) {
117: LogDebug("Authenticator for connection %d created (PID %d).",
118: conn, pid);
119: return CONNECTED;
120: } else {
121: /* Sub process */
122: Log_Init_Subprocess("Auth");
123: Conn_CloseAllSockets(NONE);
124: result = PAM_Authenticate(Client);
125: if (write(pipefd[1], &result, sizeof(result)) != sizeof(result))
126: Log_Subprocess(LOG_ERR,
127: "Failed to pipe result to parent!");
128: Log_Exit_Subprocess("Auth");
129: exit(0);
130: }
131: } else return CONNECTED;
132: #else
133: /* Check global server password ... */
134: if (strcmp(Conn_Password(conn), Conf_ServerPwd) != 0) {
135: /* Bad password! */
136: Client_Reject(Client, "Bad server password", false);
137: return DISCONNECTED;
138: }
139: return Login_User_PostAuth(Client);
140: #endif
141: }
142:
143: /**
144: * Finish client registration.
145: *
146: * Introduce the new client to the network and send all "hello messages"
147: * to it after authentication has been succeeded.
148: *
149: * @param Client The client logging in.
150: * @return CONNECTED or DISCONNECTED.
151: */
152: GLOBAL bool
153: Login_User_PostAuth(CLIENT *Client)
154: {
155: REQUEST Req;
156: char modes[CLIENT_MODE_LEN + 1];
157:
158: assert(Client != NULL);
159:
160: if (Class_HandleServerBans(Client) != CONNECTED)
161: return DISCONNECTED;
162:
163: Client_Introduce(NULL, Client, CLIENT_USER);
164:
165: if (!IRC_WriteStrClient
166: (Client, RPL_WELCOME_MSG, Client_ID(Client), Client_Mask(Client)))
167: return false;
168: if (!IRC_WriteStrClient
169: (Client, RPL_YOURHOST_MSG, Client_ID(Client),
170: Client_ID(Client_ThisServer()), PACKAGE_VERSION, HOST_CPU,
171: HOST_VENDOR, HOST_OS))
172: return false;
173: if (!IRC_WriteStrClient
174: (Client, RPL_CREATED_MSG, Client_ID(Client), NGIRCd_StartStr))
175: return false;
176: if (!IRC_WriteStrClient
177: (Client, RPL_MYINFO_MSG, Client_ID(Client),
178: Client_ID(Client_ThisServer()), PACKAGE_VERSION, USERMODES,
179: CHANMODES))
180: return false;
181:
182: /* Features supported by this server (005 numeric, ISUPPORT),
183: * see <http://www.irc.org/tech_docs/005.html> for details. */
184: if (!IRC_Send_ISUPPORT(Client))
185: return DISCONNECTED;
186:
187: if (!IRC_Send_LUSERS(Client))
188: return DISCONNECTED;
189: if (!IRC_Show_MOTD(Client))
190: return DISCONNECTED;
191:
192: /* Set default user modes */
193: if (Conf_DefaultUserModes[0]) {
194: snprintf(modes, sizeof(modes), "+%s", Conf_DefaultUserModes);
195: Req.prefix = Client_ID(Client_ThisServer());
196: Req.command = "MODE";
197: Req.argc = 2;
198: Req.argv[0] = Client_ID(Client);
199: Req.argv[1] = modes;
200: IRC_MODE(Client, &Req);
201: } else
202: IRC_SetPenalty(Client, 1);
203:
204: return CONNECTED;
205: }
206:
207: #ifdef PAM
208:
209: /**
210: * Read result of the authenticator sub-process from pipe
211: *
212: * @param r_fd File descriptor of the pipe.
213: * @param events (ignored IO specification)
214: */
215: static void
216: cb_Read_Auth_Result(int r_fd, UNUSED short events)
217: {
218: char user[CLIENT_USER_LEN], *ptr;
219: CONN_ID conn;
220: CLIENT *client;
221: int result;
222: size_t len;
223: PROC_STAT *proc;
224:
225: LogDebug("Auth: Got callback on fd %d, events %d", r_fd, events);
226: conn = Conn_GetFromProc(r_fd);
227: if (conn == NONE) {
228: /* Ops, none found? Probably the connection has already
229: * been closed!? We'll ignore that ... */
230: io_close(r_fd);
231: LogDebug("Auth: Got callback for unknown connection!?");
232: return;
233: }
234: proc = Conn_GetProcStat(conn);
235: client = Conn_GetClient(conn);
236:
237: /* Read result from pipe */
238: len = Proc_Read(proc, &result, sizeof(result));
239: Proc_Close(proc);
240: if (len == 0)
241: return;
242:
243: if (len != sizeof(result)) {
244: Log(LOG_CRIT, "Auth: Got malformed result!");
245: Client_Reject(client, "Internal error", false);
246: return;
247: }
248:
249: if (result == true) {
250: /* Authentication succeeded, now set the correct user name
251: * supplied by the client (without prepended '~' for exmaple),
252: * but cut it at the first '@' character: */
253: strlcpy(user, Client_OrigUser(client), sizeof(user));
254: ptr = strchr(user, '@');
255: if (ptr)
256: *ptr = '\0';
257: Client_SetUser(client, user, true);
258: (void)Login_User_PostAuth(client);
259: } else
260: Client_Reject(client, "Bad password", false);
261: }
262:
263: #endif
264:
265: /* -eof- */
CVSweb