[BACK]Return to login.c CVS log [TXT][DIR] Up to [local] / ircnowd / src / ngircd

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