2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
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.
16 * Functions to deal with client logins
29 #include "client-cap.h"
39 #include "irc-write.h"
45 static void cb_Read_Auth_Result PARAMS((int r_fd, UNUSED short events));
49 * Initiate client login.
51 * This function is called after the daemon received the required NICK and
52 * USER commands of a new client. If the daemon is compiled with support for
53 * PAM, the authentication sub-processs is forked; otherwise the global server
54 * password is checked.
56 * @param Client The client logging in.
57 * @returns CONNECTED or DISCONNECTED.
60 Login_User(CLIENT * Client)
63 int pipefd[2], result;
68 assert(Client != NULL);
69 conn = Client_Conn(Client);
73 /* Did we receive the "auth PONG" already? */
74 if (Conn_GetAuthPing(conn)) {
75 Client_SetType(Client, CLIENT_WAITAUTHPING);
76 LogDebug("Connection %d: Waiting for AUTH PONG ...", conn);
82 /* Still waiting for "CAP END" command? */
83 if (Client_Cap(Client) & CLIENT_CAP_PENDING)
88 /* Don't do any PAM authentication at all, instead emulate
89 * the beahiour of the daemon compiled without PAM support:
90 * because there can't be any "server password", all
91 * passwords supplied are classified as "wrong". */
92 if(Client_Password(Client)[0] == '\0')
93 return Login_User_PostAuth(Client);
94 Client_Reject(Client, "Non-empty password", false);
98 if (Conf_PAMIsOptional && strcmp(Client_Password(Client), "") == 0) {
99 /* Clients are not required to send a password and to be PAM-
100 * authenticated at all. If not, they won't become "identified"
101 * and keep the "~" in their supplied user name.
102 * Therefore it is sensible to either set Conf_PAMisOptional or
103 * to enable IDENT lookups -- not both. */
104 return Login_User_PostAuth(Client);
107 /* Fork child process for PAM authentication; and make sure that the
108 * process timeout is set higher than the login timeout! */
109 pid = Proc_Fork(Conn_GetProcStat(conn), pipefd,
110 cb_Read_Auth_Result, Conf_PongTimeout + 1);
112 LogDebug("Authenticator for connection %d created (PID %d).",
117 Log_Init_Subprocess("Auth");
118 Conn_CloseAllSockets(NONE);
119 result = PAM_Authenticate(Client);
120 if (write(pipefd[1], &result, sizeof(result)) != sizeof(result))
121 Log_Subprocess(LOG_ERR,
122 "Failed to pipe result to parent!");
123 Log_Exit_Subprocess("Auth");
127 /* Check global server password ... */
128 if (strcmp(Client_Password(Client), Conf_ServerPwd) != 0) {
130 Client_Reject(Client, "Bad server password", false);
133 return Login_User_PostAuth(Client);
138 * Finish client registration.
140 * Introduce the new client to the network and send all "hello messages"
141 * to it after authentication has been succeeded.
143 * @param Client The client logging in.
144 * @return CONNECTED or DISCONNECTED.
147 Login_User_PostAuth(CLIENT *Client)
149 assert(Client != NULL);
151 if (Class_HandleServerBans(Client) != CONNECTED)
154 Client_Introduce(NULL, Client, CLIENT_USER);
156 if (!IRC_WriteStrClient
157 (Client, RPL_WELCOME_MSG, Client_ID(Client), Client_Mask(Client)))
159 if (!IRC_WriteStrClient
160 (Client, RPL_YOURHOST_MSG, Client_ID(Client),
161 Client_ID(Client_ThisServer()), PACKAGE_VERSION, TARGET_CPU,
162 TARGET_VENDOR, TARGET_OS))
164 if (!IRC_WriteStrClient
165 (Client, RPL_CREATED_MSG, Client_ID(Client), NGIRCd_StartStr))
167 if (!IRC_WriteStrClient
168 (Client, RPL_MYINFO_MSG, Client_ID(Client),
169 Client_ID(Client_ThisServer()), PACKAGE_VERSION, USERMODES,
173 /* Features supported by this server (005 numeric, ISUPPORT),
174 * see <http://www.irc.org/tech_docs/005.html> for details. */
175 if (!IRC_Send_ISUPPORT(Client))
178 if (!IRC_Send_LUSERS(Client))
180 if (!IRC_Show_MOTD(Client))
183 /* Suspend the client for a second ... */
184 IRC_SetPenalty(Client, 1);
192 * Read result of the authenticatior sub-process from pipe
194 * @param r_fd File descriptor of the pipe.
195 * @param events (ignored IO specification)
198 cb_Read_Auth_Result(int r_fd, UNUSED short events)
206 LogDebug("Auth: Got callback on fd %d, events %d", r_fd, events);
207 conn = Conn_GetFromProc(r_fd);
209 /* Ops, none found? Probably the connection has already
210 * been closed!? We'll ignore that ... */
212 LogDebug("Auth: Got callback for unknown connection!?");
215 proc = Conn_GetProcStat(conn);
216 client = Conn_GetClient(conn);
218 /* Read result from pipe */
219 len = Proc_Read(proc, &result, sizeof(result));
224 if (len != sizeof(result)) {
225 Log(LOG_CRIT, "Auth: Got malformed result!");
226 Client_Reject(client, "Internal error", false);
230 if (result == true) {
231 Client_SetUser(client, Client_OrigUser(client), true);
232 (void)Login_User_PostAuth(client);
234 Client_Reject(client, "Bad password", false);