diff -uNr hylafax-4.1.8.chris/config.h.in hylafax-4.1.8/config.h.in --- hylafax-4.1.8.chris/config.h.in 2001-03-19 07:48:23.000000000 +0100 +++ hylafax-4.1.8/config.h.in 2004-08-05 14:38:57.864010408 +0200 @@ -274,4 +274,10 @@ #define SNPP_DEFREDIALS 12 /* number times to dial phone */ #define SNPP_DEFNOTIFY "none" /* default is no email notification */ #define SNPP_DEFPRIORITY 127 /* default job priority */ + +/* + * PAM Authentication + */ +@HAVE_PAM@ + #endif diff -uNr hylafax-4.1.8.chris/configure hylafax-4.1.8/configure --- hylafax-4.1.8.chris/configure 2003-05-23 05:28:51.000000000 +0200 +++ hylafax-4.1.8/configure 2004-08-05 14:38:35.650387392 +0200 @@ -178,7 +178,9 @@ LIBDB LLDOPTS LN -LN_S" +LN_S +HAVE_PAM +PAMLIBS" VAR2="MACHDEPLIBS MAKECXXOVERRIDE @@ -323,6 +325,7 @@ --version print the version of autoconf that created configure --target=TARGET configure for TARGET [TARGET=HOST] --srcdir=DIR find the sources in DIR [configure dir or ..] + --disable-pam disable all PAM support --with-PARAM[=ARG] set configuration PARAM [ARG=yes] EOF } @@ -376,6 +379,7 @@ -srcdir=*|--srcdir=*) SRCDIR="$ac_optarg";; -target|--target) ac_prev=TARGET;; -target=*|--target=*) TARGET="$ac_optarg" ;; + -disable-pam|--disable-pam) DISABLE_PAM="yes" ;; -version|--version) echo "This is HylaFAX configure $Revision: 1.92 $" exit 0 @@ -1548,6 +1552,25 @@ LIBSUN=no fi fi +HAVE_PAM="/*#define HAVE_PAM 1*/" +PAMLIBS="" +if [ "$DISABLE_PAM" != "yes" ]; then + Note "Checking for PAM (Pluggable Authentication Module) support" + CheckForLibrary pam_authenticate -lpam && + CheckForLibrary misc_conv -lpam_misc -lpam && + CheckForIncludeFile security/pam_appl.h && + CheckForIncludeFile security/pam_misc.h && { + HAVE_PAM="#define HAVE_PAM 1" + PAMLIBS="-lpam -lpam_misc" + } + if [ "x$PAMLIBS" = "x" ]; then + Note "... not found. Disabling PAM support" + else + Note "... found. Enabling PAM support" + fi +else + Note "Disabling PAM support" +fi CheckForLibrary crypt -lc || { # # FreeBSD-2.1 in particular needs -lcrypt. diff -uNr hylafax-4.1.8.chris/defs.in hylafax-4.1.8/defs.in --- hylafax-4.1.8.chris/defs.in 2003-04-29 05:32:19.000000000 +0200 +++ hylafax-4.1.8/defs.in 2004-08-05 14:38:35.653386936 +0200 @@ -133,7 +133,7 @@ C++FILE = @CXXFILE@ # default definitions for programs--overide them as desired -LIBS = ${LIBUTIL} +LIBS = ${LIBUTIL} @PAMLIBS@ LLDLIBS = ${LIBS} ${LIBTIFF} ${LIBZ} ${LIBREGEX} ${LIBPORT} ${MACHDEPLIBS} # # Override this definition to eliminate shared library use. diff -uNr hylafax-4.1.8.chris/hfaxd/HylaFAXServer.c++ hylafax-4.1.8/hfaxd/HylaFAXServer.c++ --- hylafax-4.1.8.chris/hfaxd/HylaFAXServer.c++ 2003-02-08 23:49:52.000000000 +0100 +++ hylafax-4.1.8/hfaxd/HylaFAXServer.c++ 2004-08-05 14:38:35.654386784 +0200 @@ -624,6 +624,7 @@ { "faxqfifoname", &HylaFAXServer::faxqFIFOName, "/" FAX_FIFO }, { "systemtype", &HylaFAXServer::systemType, "UNIX Type: L8 Version: SVR4" }, +{ "admingroup", &HylaFAXServer::admingroup }, }; HylaFAXServer::numbertag HylaFAXServer::numbers[] = { { "servertracing", &HylaFAXServer::tracingLevel, TRACE_SERVER }, @@ -644,6 +645,7 @@ for (i = N(numbers)-1; i >= 0; i--) (*this).*numbers[i].p = numbers[i].def; faxContact.append("@" | hostname); + admingroup = "faxadmin"; } void diff -uNr hylafax-4.1.8.chris/hfaxd/HylaFAXServer.h hylafax-4.1.8/hfaxd/HylaFAXServer.h --- hylafax-4.1.8.chris/hfaxd/HylaFAXServer.h 2002-06-15 20:00:09.000000000 +0200 +++ hylafax-4.1.8/hfaxd/HylaFAXServer.h 2004-08-05 14:38:35.657386328 +0200 @@ -38,6 +38,16 @@ #include "Trigger.h" #include "Syslog.h" +#include "config.h" + +#ifdef HAVE_PAM +extern "C" { +#include +#include +#include +} +#endif // HAVE_PAM + #include #include #include @@ -213,6 +223,8 @@ u_int adminAttempts; // number of failed admin attempts u_int maxAdminAttempts; // admin failures before server exits fxStr the_user; // name of user + fxStr admingroup; // name of local user group that is allowed + // to administer the fax server IDCache* idcache; // fax UID -> name mapping table /* * File and file-transfer related state. @@ -330,8 +342,11 @@ void setFileOwner(const char* filename); void loginRefused(const char* why); + bool pamCheck(const char* user=NULL, const char* pass=NULL); + bool pamIsAdmin(const char* user=NULL); bool checkUser(const char*); bool checkuser(FILE*, const char *name); + bool checkuser(const char *name); void login(void); void end_login(void); virtual void dologout(int status); diff -uNr hylafax-4.1.8.chris/hfaxd/Login.c++ hylafax-4.1.8/hfaxd/Login.c++ --- hylafax-4.1.8.chris/hfaxd/Login.c++ 1999-06-13 09:41:14.000000000 +0200 +++ hylafax-4.1.8/hfaxd/Login.c++ 2004-08-05 14:38:35.660385872 +0200 @@ -95,6 +95,84 @@ loginRefused("user denied"); } +#ifdef HAVE_PAM +int +pamconv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata) +{ + int i; + char *password =(char*) appdata; + struct pam_response* replies; + int retval = PAM_CONV_ERR; + + replies=(struct pam_response*)calloc(num_msg, sizeof(struct pam_response)); + + for (i=0; imsg_style) { + case PAM_PROMPT_ECHO_OFF: + replies[i].resp = x_strdup(password); + replies[i].resp_retcode = 0; + retval = PAM_SUCCESS; + break; + } + } + *resp = replies; + return(retval); +} +#endif //HAVE_PAM + +bool +HylaFAXServer::pamIsAdmin(const char* user) +{ + bool retval = false; +#ifdef HAVE_PAM + int i; + static struct group* grinfo = getgrnam(admingroup); + const char *curruser = (user == NULL ? the_user.c_str() : user); + if (grinfo != NULL) { + for (i=0; grinfo->gr_mem[i] != NULL; i++) { + if (strcmp(curruser, grinfo->gr_mem[i]) == 0) retval = true; + } + } +#endif //HAVE_PAM + return(retval); +} + +bool +HylaFAXServer::pamCheck(const char* user, const char* pass) +{ + bool retval = false; +#ifdef HAVE_PAM + if (user == NULL) user = the_user; + if (pass == NULL) pass = passwd.c_str(); + struct pam_conv conv = { + pamconv, + (void*)pass + }; + + pam_handle_t *pamh = NULL; + + int pamret; + + pamret = pam_start(FAX_SERVICE, user, &conv, &pamh); + if (pamret == PAM_SUCCESS) { + pamret = pam_authenticate(pamh, 0); + } + + if (pamret == PAM_SUCCESS) { + pamret = pam_acct_mgmt(pamh, 0); + retval = true; + } + + if (pamret == PAM_SUCCESS) { + retval = true; + } + + pam_end(pamh, pamret); + if (pamIsAdmin()) state |= S_PRIVILEGED; +#endif //HAVE_PAM + return(retval); +} + void HylaFAXServer::passCmd(const char* pass) { @@ -118,7 +196,7 @@ pass++; } else state |= S_LREPLIES; - if (pass[0] == '\0' || strcmp(crypt(pass, passwd), passwd) != 0) { + if (pass[0] == '\0' || !(strcmp(crypt(pass, passwd), passwd) == 0 || pamCheck(the_user, pass))) { if (++loginAttempts >= maxLoginAttempts) { reply(530, "Login incorrect (closing connection)."); logNotice("Repeated login failures for user %s from %s [%s]" @@ -176,6 +254,7 @@ initDefaultJob(); // setup connection-related state dirSetup(); // initialize directory handling + if (pamIsAdmin()) state |= S_PRIVILEGED; } void @@ -183,7 +262,7 @@ { fxAssert(IS(LOGGEDIN), "ADMIN command permitted when not logged in"); // NB: null adminwd is permitted - if (strcmp(crypt(pass, adminwd), adminwd) != 0) { + if ((strcmp(crypt(pass, adminwd), adminwd) != 0) && !pamIsAdmin()) { if (++adminAttempts >= maxAdminAttempts) { reply(530, "Password incorrect (closing connection)."); logNotice("Repeated admin failures from %s [%s]" diff -uNr hylafax-4.1.8.chris/hfaxd/SNPPServer.c++ hylafax-4.1.8/hfaxd/SNPPServer.c++ --- hylafax-4.1.8.chris/hfaxd/SNPPServer.c++ 2003-11-11 05:11:57.000000000 +0100 +++ hylafax-4.1.8/hfaxd/SNPPServer.c++ 2004-08-05 14:38:35.663385416 +0200 @@ -995,7 +995,7 @@ if (checkUser(loginID)) { if (passwd != "") { - if (pass[0] == '\0' || !streq(crypt(pass, passwd), passwd)) { + if (pass[0] == '\0' || !(streq(crypt(pass, passwd), passwd) || pamCheck(the_user, pass))) { if (++loginAttempts >= maxLoginAttempts) { reply(421, "Login incorrect (closing connection)."); logNotice("Repeated SNPP login failures for user %s from %s [%s]" diff -uNr hylafax-4.1.8.chris/hfaxd/User.c++ hylafax-4.1.8/hfaxd/User.c++ --- hylafax-4.1.8.chris/hfaxd/User.c++ 2003-02-08 23:49:53.000000000 +0100 +++ hylafax-4.1.8/hfaxd/User.c++ 2004-08-05 14:38:35.669384504 +0200 @@ -55,7 +55,7 @@ bool check = false; FILE* db = fopen(fixPathname(userAccessFile), "r"); if (db != NULL) { - check = checkuser(db, name); + check = checkuser(db, name) || checkuser(name); fclose(db); } else logError("Unable to open the user access file %s: %s", @@ -82,6 +82,22 @@ return (false); } +bool +HylaFAXServer::checkuser(const char* name) +{ + bool retval=false; +#ifdef HAVE_PAM + struct passwd* uinfo=getpwnam(name); + if (uinfo != NULL) { + uid = uinfo->pw_uid; + passwd = "*"; + adminwd = "*"; + retval = true; + } +#endif //HAVE_PAM + return(retval); +} + /* * Check the user name and host name/address against * the list of users and hosts that are permitted to diff -uNr hylafax-4.1.8.chris/hfaxd/hfaxd.conf hylafax-4.1.8/hfaxd/hfaxd.conf --- hylafax-4.1.8.chris/hfaxd/hfaxd.conf 1999-08-05 13:11:44.000000000 +0200 +++ hylafax-4.1.8/hfaxd/hfaxd.conf 2004-08-05 14:38:35.671384200 +0200 @@ -15,6 +15,7 @@ #MaxAdminAttempts: 5 # max # admin attempts before disconnect #MaxConsecutiveBadCmds: 10 # max # invalid cmds before disconnect #FaxContact: FaxMaster # who gets questions/complaints +#AdminGroup: faxadmin # which user group is admin (when using PAM) #UserAccessFile: "/etc/hosts.hfaxd" # user+host access control file #ShutdownFile: "/etc/shutdown" # server shutdown control filename #XferLogFile: "/etc/clientlog" # for logging client file transfers diff -uNr hylafax-4.1.8.chris/man/hylafax-config.4f hylafax-4.1.8/man/hylafax-config.4f --- hylafax-4.1.8.chris/man/hylafax-config.4f 2003-03-26 05:41:56.000000000 +0100 +++ hylafax-4.1.8/man/hylafax-config.4f 2004-08-05 14:38:35.675383592 +0200 @@ -116,6 +116,7 @@ .ta \w'ModemAnswerResponseTimeout 'u +\w'integer 'u +\w'\s-1AT+FCLASS=2.0\s+1 'u \fBTag Type Default Description\fP AdaptiveAnswer boolean \s-1No\s+1 enable adaptive answer of inbound calls +AdminGroup string \s-1faxadmin\s+1 System user group for administration (if PAM enabled) AnswerRotary string \s-1Any\s+1 alternatives for answering calls AnswerBias integer \- bias to apply to successful rotary answer AreaCode\(S2 string \- local area code @@ -396,6 +397,10 @@ second and subsequent .BR ModemAnswer*Cmd s. .TP +.B AdminGroup +Tells PAM what user group is allowed to administer the fax server. +Only useful if the server is compiled with PAM enabled. +.TP .B AnswerRotary The sequence of answering techniques the server should ``rotate through'' when answer incoming calls. diff -uNr hylafax-4.1.8.chris/util/Str.h hylafax-4.1.8/util/Str.h --- hylafax-4.1.8.chris/util/Str.h 2003-04-26 09:11:22.000000000 +0200 +++ hylafax-4.1.8/util/Str.h 2004-08-05 14:38:35.683382376 +0200 @@ -155,6 +155,8 @@ ///////////////////////////////////////////////////// // Misc + const char* c_str() const + { return data; } fxStr copy() const; fxStr extract(u_int start,u_int len) const; fxStr cut(u_int start,u_int len);