Annotation of ircnowd/src/ngircd/login.c, Revision 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