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=03fea99ad4e8f79ceb3a426d073f75444817933e;hp=7b73d40f99f285a5e9da7951ccc6b88be96061cb;hb=a988bbc86aed404b7bcfdbceafc030ea4bc5ecab;hpb=c191ea53a9600467c9b36baa6b930e2fa1a5796f diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c index 7b73d40f..03fea99a 100644 --- a/src/ngircd/irc-login.c +++ b/src/ngircd/irc-login.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2008 Alexander Barton (alex@barton.de) + * Copyright (c)2001-2010 Alexander Barton (alex@barton.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,15 +20,17 @@ #include #include #include +#include +#include #include "ngircd.h" -#include "resolve.h" #include "conn-func.h" #include "conf.h" -#include "client.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" @@ -39,11 +41,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". @@ -356,7 +364,7 @@ IRC_NICK( CLIENT *Client, REQUEST *Req ) * RFC 1459: announce the new client only after receiving the * USER command, first we need more information! */ if (Req->argc < 7) { - LogDebug("Client \"%s\" is beeing registered (RFC 1459) ...", + LogDebug("Client \"%s\" is being registered (RFC 1459) ...", Client_Mask(c)); Client_SetType(c, CLIENT_GOTNICK); } else @@ -403,6 +411,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" @@ -435,6 +444,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]); @@ -557,6 +567,32 @@ IRC_SERVICE(CLIENT *Client, REQUEST *Req) } /* IRC_SERVICE */ +/** + * Handler for the IRC command "WEBIRC". + * Syntax: WEBIRC + */ +GLOBAL bool +IRC_WEBIRC(CLIENT *Client, REQUEST *Req) +{ + /* Exactly 4 parameters are requited */ + if (Req->argc != 4) + return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, + Client_ID(Client), Req->command); + + if (!Conf_WebircPwd[0] || strcmp(Req->argv[0], Conf_WebircPwd) != 0) + return IRC_WriteStrClient(Client, ERR_PASSWDMISMATCH_MSG, + Client_ID(Client)); + + LogDebug("Connection %d: got valid WEBIRC command: user=%s, host=%s, ip=%s", + 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 */ + + GLOBAL bool IRC_QUIT( CLIENT *Client, REQUEST *Req ) { @@ -734,18 +770,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_NoPAM) { + /* 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 @@ -779,7 +913,7 @@ Hello_User(CLIENT * Client) IRC_SetPenalty(Client, 1); return CONNECTED; -} /* Hello_User */ +} static void @@ -815,10 +949,16 @@ Introduce_Client(CLIENT *From, CLIENT *Client, int Type) Client_Modes(Client), Client_ID(From), Client_ID(Client_Introducer(Client)), Client_Hops(Client), Client_Hops(Client) > 1 ? "s": ""); - } else + } else { Log(LOG_NOTICE, "%s \"%s\" registered (connection %d).", Client_TypeText(Client), Client_Mask(Client), Client_Conn(Client)); + Log_ServerNotice('c', "Client connecting: %s (%s@%s) [%s] - %s", + Client_ID(Client), Client_User(Client), + Client_Hostname(Client), + Conn_IPA(Client_Conn(Client)), + Client_TypeText(Client)); + } /* Inform other servers */ IRC_WriteStrServersPrefixFlag_CB(From,