Chandlog since HylaFAX 4.3.1
+* PAM reworked to use complete sessions independantly (25 Jan 2007)
* Added debian/ directory with rules to create a simple Debian package (21 Jan 2007)
* Simplify/Unify mime encoder selection and use (9 Jan 2007)
* Add the Include: option for Config file options (8 Jan 2007)
adminAttempts = 0; // NB: not reset by REIN command
idcache = NULL;
-#ifdef HAVE_PAM
- pamh = NULL;
- pam_chrooted = false;
-#endif
-
data = -1; // current data connection (socket)
pdata = -1; // passive mode data connect (socket)
faxqFd = -1;
#include "config.h"
-#ifdef HAVE_PAM
-extern "C" {
-#include <security/pam_appl.h>
-#include <grp.h>
-}
-#endif // HAVE_PAM
-
#include <sys/types.h>
#include <sys/socket.h>
#include <dirent.h>
/*
* User authentication and login-related state.
*/
-#ifdef HAVE_PAM
- pam_handle_t *pamh; // handle to current pam session
- bool pam_chrooted; // if already chrooted, PAM gets disabled
-#endif
-
fxStr passwd; // encrypted user password
fxStr adminwd; // encrypted passwd for admin privileges
u_int uid; // client's ID
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
+ fxStr admingroup; // name of local user group that is allowed
// to administer the fax server
IDCache* idcache; // fax UID -> name mapping table
/*
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);
- void pamEnd(int pamret);
+
bool checkUser(const char*);
- bool checkuser(FILE*, const char *name);
- bool checkuser(const char *name);
+ bool checkPasswd(const char*);
+
+ bool checkuserHosts(FILE*, const char *name);
+ bool checkuserPAM(const char *name);
+
+ bool checkpasswdHosts(const char* passwd);
+ bool checkpasswdPAM(const char* passwd);
+
+ bool isAdminGroup(const char* user=NULL);
+
void login(int code);
void end_login(void);
virtual void dologout(int status);
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
+#include <grp.h>
#include <pwd.h>
#if HAS_CRYPT_H
#include <crypt.h>
loginRefused("user denied");
}
-#ifdef HAVE_PAM
-int
-pamconv(int num_msg, STRUCT_PAM_MESSAGE **msg, struct pam_response **resp, void *appdata)
-{
- char *password =(char*) appdata;
- struct pam_response* replies;
-
- if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF)
- return PAM_CONV_ERR;
-
- if (password == NULL)
- /*
- * Solaris doesn't have PAM_CONV_AGAIN defined.
- */
- #ifdef PAM_CONV_AGAIN
- return PAM_CONV_AGAIN;
- #else
- return PAM_CONV_ERR;
- #endif
-
- replies=(struct pam_response*)calloc(num_msg, sizeof(struct pam_response));
-
- replies[0].resp = strdup(password);
- replies[0].resp_retcode = 0;
- *resp = replies;
-
- return PAM_SUCCESS;
-}
-#endif //HAVE_PAM
-
bool
-HylaFAXServer::pamIsAdmin(const char* user)
+HylaFAXServer::isAdminGroup(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;
- }
+ if (admingroup.length() > 0) {
+ 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 (pamh == NULL)
- return false;
-
- if (user == NULL) user = the_user;
- if (pass == NULL) pass = passwd.c_str();
-
- struct pam_conv conv = {
- pamconv,
- (void*)pass
- };
-
-
- int pamret;
-
- /*
- * Solaris has proprietary pam_[sg]et_item() extension.
- * Sun defines PAM_MSG_VERSION therefore is possible to use
- * it in order to recognize the extensions of Solaris
- */
- #ifdef PAM_MSG_VERSION
- pamret = pam_set_item(pamh, PAM_CONV, (const void *)&conv);
- #else
- pamret = pam_set_item(pamh, PAM_CONV, &conv);
- #endif
-
- if (pamret == PAM_SUCCESS)
- pamret = pam_authenticate(pamh, 0);
-
- if (pamret == PAM_SUCCESS)
- pamret = pam_acct_mgmt(pamh, 0);
-
- if (pamret == PAM_SUCCESS)
- retval = true;
-
- pamEnd(pamret);
-#endif
- return retval;
-}
-
-void HylaFAXServer::pamEnd(int pamret)
-{
-#ifdef HAVE_PAM
- if (pamret == PAM_SUCCESS)
- {
- if (pamIsAdmin())
- state |= S_PRIVILEGED;
-
- char *newname=NULL;
-
- /*
- * Solaris has proprietary pam_[sg]et_item() extension.
- * Sun defines PAM_MSG_VERSION therefore is possible to use
- * it in order to recognize the extensions of Solaris
- */
- #ifdef PAM_MSG_VERSION
- pamret = pam_get_item(pamh, PAM_USER, (void **)&newname);
- #else
- pamret = pam_get_item(pamh, PAM_USER, (const void **)&newname);
- #endif
-
- if (pamret == PAM_SUCCESS && newname != NULL)
- the_user = strdup(newname);
-
- struct passwd* uinfo=getpwnam((const char *)the_user);
- if (uinfo != NULL) {
- uid = uinfo->pw_uid;
- }
-
- }
- pamret = pam_end(pamh, pamret);
- pamh = NULL;
-
-#endif //HAVE_PAM
-}
-
void
HylaFAXServer::passCmd(const char* pass)
{
pass++;
} else
state |= S_LREPLIES;
- if (pass[0] == '\0' || !(strcmp(crypt(pass, passwd), passwd) == 0 || pamCheck(the_user, pass))) {
+
+ if (! checkPasswd(pass)) {
if (++loginAttempts >= maxLoginAttempts) {
reply(530, "Login incorrect (closing connection).");
logNotice("Repeated login failures for user %s from %s [%s]"
return;
}
-#ifdef HAVE_PAM
- pam_chrooted = true;
-#endif
-
(void) isShutdown(false); // display any shutdown messages
reply(code, "User %s logged in.", (const char*) the_user);
if (TRACE(LOGIN))
initDefaultJob(); // setup connection-related state
dirSetup(); // initialize directory handling
- if (pamIsAdmin()) state |= S_PRIVILEGED;
+ if (isAdminGroup()) state |= S_PRIVILEGED;
}
void
{
fxAssert(IS(LOGGEDIN), "ADMIN command permitted when not logged in");
// NB: null adminwd is permitted
- if ((strcmp(crypt(pass, adminwd), adminwd) != 0) && !pamIsAdmin()) {
+ if ((strcmp(crypt(pass, adminwd), adminwd) != 0) && !isAdminGroup()) {
if (++adminAttempts >= maxAdminAttempts) {
reply(530, "Password incorrect (closing connection).");
logNotice("Repeated admin failures from %s [%s]"
Status.c++ \
Trigger.c++ \
User.c++ \
+ PAM.c++ \
\
SuperServer.c++ \
InetFaxServer.c++ \
passwd = "*"; // just in case...
if (checkUser(loginID)) {
- if (passwd != "") {
- if (pass[0] == '\0' || !(streq(crypt(pass, passwd), passwd) || pamCheck(the_user, pass))) {
+ if (! checkPasswd(passwd)) {
if (++loginAttempts >= maxLoginAttempts) {
reply(421, "Login incorrect (closing connection).");
logNotice("Repeated SNPP login failures for user %s from %s [%s]"
);
return;
}
- }
login(250);
} else {
if (++loginAttempts >= maxLoginAttempts) {
#endif
#endif /* CHAR_BIT */
+
/*
* User Access Control Support.
*/
gid_t HylaFAXServer::faxuid = 0; // reserved fax uid
#define FAXUID_RESV HylaFAXServer::faxuid // reserved fax uid
-#ifdef HAVE_PAM
-extern int
-pamconv(int num_msg, STRUCT_PAM_MESSAGE **msg, struct pam_response **resp, void *appdata);
-#endif
-
bool
HylaFAXServer::checkUser(const char* name)
{
bool check = false;
FILE* db = fopen(fixPathname(userAccessFile), "r");
if (db != NULL) {
- check = checkuser(db, name) || checkuser(name);
+ check = checkuserHosts(db, name);
fclose(db);
} else
logError("Unable to open the user access file %s: %s",
(const char*) userAccessFile, strerror(errno));
+
+ if (! check)
+ check = checkuserPAM(name);
+
/*
* This causes the user to be prompted for a password
* and then denied access. We do this to guard against
return (true);
}
+bool
+HylaFAXServer::checkPasswd (const char* pass)
+{
+ if (pass[0] == '\0')
+ return false;
+
+ if (checkpasswdHosts(pass))
+ return true;
+
+ if (checkpasswdPAM(pass))
+ return true;
+
+ return false;
+}
+
+
static bool
nextRecord(FILE* db, char line[], u_int size)
{
return (false);
}
-bool
-HylaFAXServer::checkuser(const char* name)
-{
- bool retval=false;
-
-#ifdef HAVE_PAM
- if (pam_chrooted) {
- logNotice("PAM authentication for %s can't be used for a re-issuance of USER command because of chroot jail\n", name);
- return false;
- }
-
- int pamret;
- struct pam_conv conv = {pamconv, NULL};
-
- pamret = pam_start(FAX_SERVICE, name, &conv, &pamh);
-
- if (pamret == PAM_SUCCESS)
- pamret = pam_authenticate(pamh, 0);
-
- if (pamret == PAM_SUCCESS)
- pamret = pam_acct_mgmt(pamh, 0);
-
- if (pamret == PAM_SUCCESS) {
- passwd = "";
- pamEnd(pamret);
- } else {
- 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
* user the server and setup password handling.
*/
bool
-HylaFAXServer::checkuser(FILE* db, const char* name)
+HylaFAXServer::checkuserHosts(FILE* db, const char* name)
{
struct stat sb;
if (Sys::fstat(fileno(db), sb) < 0)
return (false);
}
+bool
+HylaFAXServer::checkpasswdHosts (const char* pass)
+{
+ if (strcmp(crypt(pass,passwd),passwd) == 0)
+ return true;
+
+ return false;
+}
+
fxDECLARE_PtrKeyDictionary(IDCache, u_int, fxStr)
fxIMPLEMENT_PtrKeyObjValueDictionary(IDCache, u_int, fxStr)