X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Firc-login.c;h=b310d8b84614e7a37737825518125d9eb78ca705;hp=5a52d3cb68a9955079e75d4053f50ca61841ef19;hb=03628dbeaf40a9de34b3eb6d5bf6dd34eed8248c;hpb=5462c6c50fd01fd516e29a42ee0b15c946c11d27 diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c index 5a52d3cb..b310d8b8 100644 --- a/src/ngircd/irc-login.c +++ b/src/ngircd/irc-login.c @@ -7,26 +7,33 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. - * - * Login and logout */ #include "portab.h" +/** + * @file + * Login and logout + */ + #include "imp.h" #include #include #include #include #include +#include +#include #include "ngircd.h" #include "conn-func.h" #include "conf.h" #include "channel.h" +#include "io.h" #include "log.h" #include "messages.h" +#include "pam.h" #include "parse.h" #include "irc.h" #include "irc-info.h" @@ -37,11 +44,17 @@ static bool Hello_User PARAMS(( CLIENT *Client )); +static bool Hello_User_PostAuth PARAMS(( CLIENT *Client )); static void Kill_Nick PARAMS(( char *Nick, char *Reason )); static void Introduce_Client PARAMS((CLIENT *To, CLIENT *Client, int Type)); +static void Reject_Client PARAMS((CLIENT *Client)); + static void cb_introduceClient PARAMS((CLIENT *Client, CLIENT *Prefix, void *i)); +#ifdef PAM +static void cb_Read_Auth_Result PARAMS((int r_fd, UNUSED short events)); +#endif /** * Handler for the IRC command "PASS". @@ -133,16 +146,17 @@ IRC_PASS( CLIENT *Client, REQUEST *Req ) if (type && strcmp(type, PROTOIRCPLUS) == 0) { /* The peer seems to be a server which supports the * IRC+ protocol (see doc/Protocol.txt). */ - serverver = ptr + 1; - flags = strchr(serverver, ':'); + serverver = ptr ? ptr + 1 : "?"; + flags = strchr(ptr ? serverver : impl, ':'); if (flags) { *flags = '\0'; flags++; } else flags = ""; Log(LOG_INFO, - "Peer announces itself as %s-%s using protocol %d.%d/IRC+ (flags: \"%s\").", - impl, serverver, protohigh, protolow, flags); + "Peer on conenction %d announces itself as %s-%s using protocol %d.%d/IRC+ (flags: \"%s\").", + Client_Conn(Client), impl, serverver, + protohigh, protolow, flags); } else { /* The peer seems to be a server supporting the * "original" IRC protocol (RFC 2813). */ @@ -151,8 +165,9 @@ IRC_PASS( CLIENT *Client, REQUEST *Req ) else flags = ""; Log(LOG_INFO, - "Peer announces itself as \"%s\" using protocol %d.%d (flags: \"%s\").", - impl, protohigh, protolow, flags); + "Peer on connection %d announces itself as \"%s\" using protocol %d.%d (flags: \"%s\").", + Client_Conn(Client), impl, + protohigh, protolow, flags); } Client_SetFlags(Client, flags); } @@ -401,6 +416,7 @@ IRC_USER(CLIENT * Client, REQUEST * Req) #else Client_SetUser(Client, Req->argv[0], false); #endif + Client_SetOrigUser(Client, Req->argv[0]); /* "Real name" or user info text: Don't set it to the empty * string, the original ircd can't deal with such "real names" @@ -433,6 +449,7 @@ IRC_USER(CLIENT * Client, REQUEST * Req) Req->prefix); Client_SetUser(c, Req->argv[0], true); + Client_SetOrigUser(c, Req->argv[0]); Client_SetHostname(c, Req->argv[1]); Client_SetInfo(c, Req->argv[3]); @@ -575,6 +592,7 @@ IRC_WEBIRC(CLIENT *Client, REQUEST *Req) Client_Conn(Client), Req->argv[1], Req->argv[2], Req->argv[3]); Client_SetUser(Client, Req->argv[1], true); + Client_SetOrigUser(Client, Req->argv[1]); Client_SetHostname(Client, Req->argv[2]); return CONNECTED; } /* IRC_WEBIRC */ @@ -757,18 +775,116 @@ IRC_PONG(CLIENT *Client, REQUEST *Req) static bool Hello_User(CLIENT * Client) { +#ifdef PAM + int pipefd[2], result; + CONN_ID conn; + pid_t pid; + + assert(Client != NULL); + conn = Client_Conn(Client); + + if (!Conf_PAM) { + /* Don't do any PAM authentication at all, instead emulate + * the beahiour of the daemon compiled without PAM support: + * because there can't be any "server password", all + * passwords supplied are classified as "wrong". */ + if(Client_Password(Client)[0] == '\0') + return Hello_User_PostAuth(Client); + Reject_Client(Client); + return DISCONNECTED; + } + + /* Fork child process for PAM authentication; and make sure that the + * process timeout is set higher than the login timeout! */ + pid = Proc_Fork(Conn_GetProcStat(conn), pipefd, + cb_Read_Auth_Result, Conf_PongTimeout + 1); + if (pid > 0) { + LogDebug("Authenticator for connection %d created (PID %d).", + conn, pid); + return CONNECTED; + } else { + /* Sub process */ + Log_Init_Subprocess("Auth"); + result = PAM_Authenticate(Client); + write(pipefd[1], &result, sizeof(result)); + Log_Exit_Subprocess("Auth"); + exit(0); + } +#else assert(Client != NULL); - /* Check password ... */ + /* Check global server password ... */ if (strcmp(Client_Password(Client), Conf_ServerPwd) != 0) { /* Bad password! */ - Log(LOG_ERR, - "Client \"%s\" rejected (connection %d): Bad password!", - Client_Mask(Client), Client_Conn(Client)); - Conn_Close(Client_Conn(Client), NULL, "Bad password", true); + Reject_Client(Client); return DISCONNECTED; } + return Hello_User_PostAuth(Client); +#endif +} + + +#ifdef PAM + +/** + * Read result of the authenticatior sub-process from pipe + */ +static void +cb_Read_Auth_Result(int r_fd, UNUSED short events) +{ + CONN_ID conn; + CLIENT *client; + int result; + size_t len; + PROC_STAT *proc; + + LogDebug("Auth: Got callback on fd %d, events %d", r_fd, events); + conn = Conn_GetFromProc(r_fd); + if (conn == NONE) { + /* Ops, none found? Probably the connection has already + * been closed!? We'll ignore that ... */ + io_close(r_fd); + LogDebug("Auth: Got callback for unknown connection!?"); + return; + } + proc = Conn_GetProcStat(conn); + client = Conn_GetClient(conn); + + /* Read result from pipe */ + len = Proc_Read(proc, &result, sizeof(result)); + if (len == 0) + return; + + if (len != sizeof(result)) { + Log(LOG_CRIT, "Auth: Got malformed result!"); + Reject_Client(client); + return; + } + + if (result == true) { + Client_SetUser(client, Client_OrigUser(client), true); + (void)Hello_User_PostAuth(client); + } else + Reject_Client(client); +} + +#endif + + +static void +Reject_Client(CLIENT *Client) +{ + Log(LOG_ERR, + "User \"%s\" rejected (connection %d): Access denied!", + Client_Mask(Client), Client_Conn(Client)); + Conn_Close(Client_Conn(Client), NULL, + "Access denied! Bad password?", true); +} + +static bool +Hello_User_PostAuth(CLIENT *Client) +{ Introduce_Client(NULL, Client, CLIENT_USER); if (!IRC_WriteStrClient @@ -802,7 +918,7 @@ Hello_User(CLIENT * Client) IRC_SetPenalty(Client, 1); return CONNECTED; -} /* Hello_User */ +} static void