diff options
author | Steve Langasek <steve.langasek@ubuntu.com> | 2019-01-03 12:48:14 -0800 |
---|---|---|
committer | Steve Langasek <steve.langasek@ubuntu.com> | 2019-01-03 12:48:14 -0800 |
commit | d5b06b67bbeeed7c05c0eb2e05d6a972ad050d1c (patch) | |
tree | ba5654cffacfd2002eefc5bc3764a7971afff1dc /Linux-PAM/modules/pam_mail/pam_mail.c | |
parent | 4c51da22e068907adb7857d50f5109a467c94d7c (diff) | |
parent | 7cbfa335c57d068d59508c844f3957165cccfb9b (diff) | |
download | pam-d5b06b67bbeeed7c05c0eb2e05d6a972ad050d1c.tar.gz pam-d5b06b67bbeeed7c05c0eb2e05d6a972ad050d1c.tar.bz2 pam-d5b06b67bbeeed7c05c0eb2e05d6a972ad050d1c.zip |
New upstream version 0.99.7.1
Diffstat (limited to 'Linux-PAM/modules/pam_mail/pam_mail.c')
-rw-r--r-- | Linux-PAM/modules/pam_mail/pam_mail.c | 442 |
1 files changed, 216 insertions, 226 deletions
diff --git a/Linux-PAM/modules/pam_mail/pam_mail.c b/Linux-PAM/modules/pam_mail/pam_mail.c index 7987cb28..7d43d5e0 100644 --- a/Linux-PAM/modules/pam_mail/pam_mail.c +++ b/Linux-PAM/modules/pam_mail/pam_mail.c @@ -1,14 +1,12 @@ /* pam_mail module */ /* - * $Id: pam_mail.c,v 1.6 2004/11/16 14:27:41 toady Exp $ - * * Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11 * $HOME additions by David Kinchlea <kinch@kinch.ark.com> 1997/1/7 * mailhash additions by Chris Adams <cadams@ro.com> 1998/7/11 */ -#include <security/_pam_aconf.h> +#include "config.h" #include <ctype.h> #include <pwd.h> @@ -21,18 +19,16 @@ #include <sys/types.h> #include <unistd.h> #include <dirent.h> +#include <errno.h> -#ifdef WANT_PWDB -#include <pwdb/pwdb_public.h> +#ifdef HAVE_PATHS_H +#include <paths.h> #endif #define DEFAULT_MAIL_DIRECTORY PAM_PATH_MAILDIR #define MAIL_FILE_FORMAT "%s%s/%s" #define MAIL_ENV_NAME "MAIL" #define MAIL_ENV_FORMAT MAIL_ENV_NAME "=%s" -#define YOUR_MAIL_VERBOSE_FORMAT "You have %s mail in %s." -#define YOUR_MAIL_STANDARD_FORMAT "You have %smail." -#define NO_MAIL_STANDARD_FORMAT "No mail." /* * here, we make a definition for the externally accessible function @@ -46,20 +42,8 @@ #include <security/pam_modules.h> #include <security/_pam_macros.h> -#include <security/_pam_modutil.h> - -/* some syslogging */ - -static void _log_err(int err, const char *format, ...) -{ - va_list args; - - va_start(args, format); - openlog("PAM-mail", LOG_CONS|LOG_PID, LOG_AUTH); - vsyslog(err, format, args); - va_end(args); - closelog(); -} +#include <security/pam_modutil.h> +#include <security/pam_ext.h> /* argument parsing */ @@ -74,8 +58,14 @@ static void _log_err(int err, const char *format, ...) #define PAM_STANDARD_MAIL 0x0400 #define PAM_QUIET_MAIL 0x1000 -static int _pam_parse(int flags, int argc, const char **argv, char **maildir, - int *hashcount) +#define HAVE_NEW_MAIL 0x1 +#define HAVE_OLD_MAIL 0x2 +#define HAVE_NO_MAIL 0x3 +#define HAVE_MAIL 0x4 + +static int +_pam_parse (const pam_handle_t *pamh, int flags, int argc, + const char **argv, const char **maildir, size_t *hashcount) { int ctrl=0; @@ -97,18 +87,18 @@ static int _pam_parse(int flags, int argc, const char **argv, char **maildir, else if (!strcmp(*argv,"standard")) ctrl |= PAM_STANDARD_MAIL | PAM_EMPTY_TOO; else if (!strncmp(*argv,"dir=",4)) { - *maildir = x_strdup(4+*argv); - if (*maildir != NULL) { + *maildir = 4 + *argv; + if (**maildir != '\0') { D(("new mail directory: %s", *maildir)); ctrl |= PAM_NEW_MAIL_DIR; } else { - _log_err(LOG_CRIT, - "failed to duplicate mail directory - ignored"); + pam_syslog(pamh, LOG_ERR, + "dir= specification missing argument - ignored"); } } else if (!strncmp(*argv,"hash=",5)) { char *ep = NULL; - *hashcount = strtol(*argv+5,&ep,10); - if (!ep || (*hashcount < 0)) { + *hashcount = strtoul(*argv+5,&ep,10); + if (!ep) { *hashcount = 0; } } else if (!strcmp(*argv,"close")) { @@ -120,90 +110,56 @@ static int _pam_parse(int flags, int argc, const char **argv, char **maildir, } else if (!strcmp(*argv,"empty")) { ctrl |= PAM_EMPTY_TOO; } else { - _log_err(LOG_ERR,"pam_parse: unknown option; %s",*argv); + pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv); } } if ((*hashcount != 0) && !(ctrl & PAM_NEW_MAIL_DIR)) { - *maildir = x_strdup(DEFAULT_MAIL_DIRECTORY); + *maildir = DEFAULT_MAIL_DIRECTORY; ctrl |= PAM_NEW_MAIL_DIR; } return ctrl; } -/* a front end for conversations */ - -static int converse(pam_handle_t *pamh, int ctrl, int nargs - , struct pam_message **message - , struct pam_response **response) -{ - int retval; - struct pam_conv *conv; - - D(("begin to converse")); - - retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ; - if ( retval == PAM_SUCCESS && conv ) { - - retval = conv->conv(nargs, ( const struct pam_message ** ) message - , response, conv->appdata_ptr); - - D(("returned from application's conversation function")); - - if (retval != PAM_SUCCESS && (PAM_DEBUG_ARG & ctrl) ) { - _log_err(LOG_DEBUG, "conversation failure [%s]" - , pam_strerror(pamh, retval)); - } - - } else { - _log_err(LOG_ERR, "couldn't obtain coversation function [%s]" - , pam_strerror(pamh, retval)); - if (retval == PAM_SUCCESS) - retval = PAM_BAD_ITEM; /* conv was NULL */ - } - - D(("ready to return from module conversation")); - - return retval; /* propagate error status */ -} - -static int get_folder(pam_handle_t *pamh, int ctrl, - char **path_mail, char **folder_p, int hashcount) +static int +get_folder(pam_handle_t *pamh, int ctrl, + const char *path_mail, char **folder_p, size_t hashcount) { int retval; const char *user, *path; - char *folder; - const struct passwd *pwd=NULL; + char *folder = NULL; + const struct passwd *pwd = NULL; retval = pam_get_user(pamh, &user, NULL); if (retval != PAM_SUCCESS || user == NULL) { - _log_err(LOG_ERR, "no user specified"); - return PAM_USER_UNKNOWN; + pam_syslog(pamh, LOG_ERR, "cannot determine username"); + retval = PAM_USER_UNKNOWN; + goto get_folder_cleanup; } if (ctrl & PAM_NEW_MAIL_DIR) { - path = *path_mail; - if (*path == '~') { /* support for $HOME delivery */ - pwd = _pammodutil_getpwnam(pamh, user); + path = path_mail; + if (*path == '~') { /* support for $HOME delivery */ + pwd = pam_modutil_getpwnam(pamh, user); if (pwd == NULL) { - _log_err(LOG_ERR, "user [%s] unknown", user); - _pam_overwrite(*path_mail); - _pam_drop(*path_mail); - return PAM_USER_UNKNOWN; + pam_syslog(pamh, LOG_ERR, "user unknown"); + retval = PAM_USER_UNKNOWN; + goto get_folder_cleanup; } /* * "~/xxx" and "~xxx" are treated as same */ if (!*++path || (*path == '/' && !*++path)) { - _log_err(LOG_ALERT, "badly formed mail path [%s]", *path_mail); - _pam_overwrite(*path_mail); - _pam_drop(*path_mail); - return PAM_ABORT; + pam_syslog(pamh, LOG_ERR, + "badly formed mail path [%s]", path_mail); + retval = PAM_SERVICE_ERR; + goto get_folder_cleanup; } ctrl |= PAM_HOME_MAIL; if (hashcount != 0) { - _log_err(LOG_ALERT, "can't do hash= and home directory mail"); + pam_syslog(pamh, LOG_ERR, + "cannot do hash= and home directory mail"); } } } else { @@ -212,153 +168,188 @@ static int get_folder(pam_handle_t *pamh, int ctrl, /* put folder together */ + hashcount = hashcount < strlen(user) ? hashcount : strlen(user); + + retval = PAM_BUF_ERR; if (ctrl & PAM_HOME_MAIL) { - folder = malloc(sizeof(MAIL_FILE_FORMAT) - +strlen(pwd->pw_dir)+strlen(path)); + if (pwd == NULL) { + pwd = pam_modutil_getpwnam(pamh, user); + if (pwd == NULL) { + pam_syslog(pamh, LOG_ERR, "user unknown"); + retval = PAM_USER_UNKNOWN; + goto get_folder_cleanup; + } + } + if (asprintf(&folder, MAIL_FILE_FORMAT, pwd->pw_dir, "", path) < 0) + goto get_folder_cleanup; } else { - folder = malloc(sizeof(MAIL_FILE_FORMAT)+strlen(path)+strlen(user) - +2*hashcount); - } + int rc; + size_t i; + char *hash; - if (folder != NULL) { - if (ctrl & PAM_HOME_MAIL) { - sprintf(folder, MAIL_FILE_FORMAT, pwd->pw_dir, "", path); - } else { - int i; - char *hash = malloc(2*hashcount+1); + if ((hash = malloc(2 * hashcount + 1)) == NULL) + goto get_folder_cleanup; - if (hash) { - for (i = 0; i < hashcount; i++) { - hash[2*i] = '/'; - hash[2*i+1] = user[i]; - } - hash[2*i] = '\0'; - sprintf(folder, MAIL_FILE_FORMAT, path, hash, user); - _pam_overwrite(hash); - _pam_drop(hash); - } else { - _pam_drop(folder); - _log_err(LOG_CRIT, "out of memory for mail folder"); - return PAM_BUF_ERR; - } + for (i = 0; i < hashcount; i++) { + hash[2 * i] = '/'; + hash[2 * i + 1] = user[i]; } - D(("folder =[%s]", folder)); + hash[2 * i] = '\0'; + + rc = asprintf(&folder, MAIL_FILE_FORMAT, path, hash, user); + _pam_overwrite(hash); + _pam_drop(hash); + if (rc < 0) + goto get_folder_cleanup; } + D(("folder=[%s]", folder)); + retval = PAM_SUCCESS; /* tidy up */ - _pam_overwrite(*path_mail); - _pam_drop(*path_mail); + get_folder_cleanup: user = NULL; - - if (folder == NULL) { - _log_err(LOG_CRIT, "out of memory for mail folder"); - return PAM_BUF_ERR; - } + path = NULL; *folder_p = folder; folder = NULL; - return PAM_SUCCESS; + if (retval == PAM_BUF_ERR) + pam_syslog(pamh, LOG_CRIT, "out of memory for mail folder"); + + return retval; } -static const char *get_mail_status(int ctrl, const char *folder) +static int +get_mail_status(pam_handle_t *pamh, int ctrl, const char *folder) { - const char *type = NULL; - static char dir[256]; + int type = 0; struct stat mail_st; - struct dirent **namelist; - int i; - if (stat(folder, &mail_st) == 0) { - if (S_ISDIR(mail_st.st_mode)) { /* Assume Maildir format */ - sprintf(dir, "%.250s/new", folder); + if (stat(folder, &mail_st) < 0) + return 0; + + if (S_ISDIR(mail_st.st_mode)) { /* Assume Maildir format */ + int i, save_errno; + char *dir; + struct dirent **namelist; + + if (asprintf(&dir, "%s/new", folder) < 0) { + pam_syslog(pamh, LOG_CRIT, "out of memory"); + goto get_mail_status_cleanup; + } + i = scandir(dir, &namelist, 0, alphasort); + save_errno = errno; + _pam_overwrite(dir); + _pam_drop(dir); + if (i < 0) { + type = 0; + namelist = NULL; + if (save_errno == ENOMEM) { + pam_syslog(pamh, LOG_CRIT, "out of memory"); + goto get_mail_status_cleanup; + } + } + type = (i > 2) ? HAVE_NEW_MAIL : 0; + while (--i >= 0) + _pam_drop(namelist[i]); + _pam_drop(namelist); + if (type == 0) { + if (asprintf(&dir, "%s/cur", folder) < 0) { + pam_syslog(pamh, LOG_CRIT, "out of memory"); + goto get_mail_status_cleanup; + } i = scandir(dir, &namelist, 0, alphasort); - if (i > 2) { - type = "new"; - while (--i) - free(namelist[i]); - } else { - while (--i >= 0) - free(namelist[i]); - sprintf(dir, "%.250s/cur", folder); - i = scandir(dir, &namelist, 0, alphasort); - if (i > 2) { - type = "old"; - while (--i) - free(namelist[i]); - } else if (ctrl & PAM_EMPTY_TOO) { - while (--i >= 0) - free(namelist[i]); - type = "no"; - } else { - type = NULL; + save_errno = errno; + _pam_overwrite(dir); + _pam_drop(dir); + if (i < 0) { + type = 0; + namelist = NULL; + if (save_errno == ENOMEM) { + pam_syslog(pamh, LOG_CRIT, "out of memory"); + goto get_mail_status_cleanup; } } + if (i > 2) + type = HAVE_OLD_MAIL; + else + type = (ctrl & PAM_EMPTY_TOO) ? HAVE_NO_MAIL : 0; + while (--i >= 0) + _pam_drop(namelist[i]); + _pam_drop(namelist); + } + } else { + if (mail_st.st_size > 0) { + if (mail_st.st_atime < mail_st.st_mtime) /* new */ + type = HAVE_NEW_MAIL; + else /* old */ + type = (ctrl & PAM_STANDARD_MAIL) ? HAVE_MAIL : HAVE_OLD_MAIL; + } else if (ctrl & PAM_EMPTY_TOO) { + type = HAVE_NO_MAIL; } else { - if (mail_st.st_size > 0) { - if (mail_st.st_atime < mail_st.st_mtime) /* new */ - type = (ctrl & PAM_STANDARD_MAIL) ? "new " : "new"; - else /* old */ - type = (ctrl & PAM_STANDARD_MAIL) ? "" : "old"; - } else if (ctrl & PAM_EMPTY_TOO) { - type = "no"; - } else { - type = NULL; - } + type = 0; } } - memset(dir, 0, 256); + get_mail_status_cleanup: memset(&mail_st, 0, sizeof(mail_st)); - D(("user has %s mail in %s folder", type, folder)); + D(("user has %d mail in %s folder", type, folder)); return type; } -static int report_mail(pam_handle_t *pamh, int ctrl - , const char *type, const char *folder) +static int +report_mail(pam_handle_t *pamh, int ctrl, int type, const char *folder) { int retval; - if (!(ctrl & PAM_MAIL_SILENT) || ((ctrl & PAM_QUIET_MAIL) && strcmp(type, "new"))) { - char *remark; - + if (!(ctrl & PAM_MAIL_SILENT) || + ((ctrl & PAM_QUIET_MAIL) && type == HAVE_NEW_MAIL)) + { if (ctrl & PAM_STANDARD_MAIL) - if (!strcmp(type, "no")) - remark = malloc(strlen(NO_MAIL_STANDARD_FORMAT)+1); - else - remark = malloc(strlen(YOUR_MAIL_STANDARD_FORMAT)+strlen(type)+1); + switch (type) + { + case HAVE_NO_MAIL: + retval = pam_info (pamh, "%s", _("No mail.")); + break; + case HAVE_NEW_MAIL: + retval = pam_info (pamh, "%s", _("You have new mail.")); + break; + case HAVE_OLD_MAIL: + retval = pam_info (pamh, "%s", _("You have old mail.")); + break; + case HAVE_MAIL: + default: + retval = pam_info (pamh, "%s", _("You have mail.")); + break; + } else - remark = malloc(strlen(YOUR_MAIL_VERBOSE_FORMAT)+strlen(type)+strlen(folder)+1); - if (remark == NULL) { - retval = PAM_BUF_ERR; - } else { - struct pam_message msg[1], *mesg[1]; - struct pam_response *resp=NULL; - - if (ctrl & PAM_STANDARD_MAIL) - if (!strcmp(type, "no")) - sprintf(remark, NO_MAIL_STANDARD_FORMAT); - else - sprintf(remark, YOUR_MAIL_STANDARD_FORMAT, type); - else - sprintf(remark, YOUR_MAIL_VERBOSE_FORMAT, type, folder); - - mesg[0] = &msg[0]; - msg[0].msg_style = PAM_TEXT_INFO; - msg[0].msg = remark; - - retval = converse(pamh, ctrl, 1, mesg, &resp); - - _pam_overwrite(remark); - _pam_drop(remark); - if (resp) - _pam_drop_reply(resp, 1); - } - } else { + switch (type) + { + case HAVE_NO_MAIL: + retval = pam_info (pamh, _("You have no mail in folder %s."), + folder); + break; + case HAVE_NEW_MAIL: + retval = pam_info (pamh, _("You have new mail in folder %s."), + folder); + break; + case HAVE_OLD_MAIL: + retval = pam_info (pamh, _("You have old mail in folder %s."), + folder); + break; + case HAVE_MAIL: + default: + retval = pam_info (pamh, _("You have mail in folder %s."), + folder); + break; + } + } + else + { D(("keeping quiet")); retval = PAM_SUCCESS; - } + } D(("returning %s", pam_strerror(pamh, retval))); return retval; @@ -368,9 +359,9 @@ static int _do_mail(pam_handle_t *, int, int, const char **, int); /* --- authentication functions --- */ -PAM_EXTERN -int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc, - const char **argv) +PAM_EXTERN int +pam_sm_authenticate (pam_handle_t *pamh UNUSED, int flags UNUSED, + int argc UNUSED, const char **argv UNUSED) { return PAM_IGNORE; } @@ -408,16 +399,17 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, static int _do_mail(pam_handle_t *pamh, int flags, int argc, const char **argv, int est) { - int retval, ctrl, hashcount; - char *path_mail=NULL, *folder; - const char *type; + int retval, ctrl, type; + size_t hashcount; + char *folder = NULL; + const char *path_mail = NULL; /* * this module (un)sets the MAIL environment variable, and checks if * the user has any new mail. */ - ctrl = _pam_parse(flags, argc, argv, &path_mail, &hashcount); + ctrl = _pam_parse(pamh, flags, argc, argv, &path_mail, &hashcount); /* Do we have anything to do? */ @@ -426,7 +418,7 @@ static int _do_mail(pam_handle_t *pamh, int flags, int argc, /* which folder? */ - retval = get_folder(pamh, ctrl, &path_mail, &folder, hashcount); + retval = get_folder(pamh, ctrl, path_mail, &folder, hashcount); if (retval != PAM_SUCCESS) { D(("failed to find folder")); return retval; @@ -437,24 +429,21 @@ static int _do_mail(pam_handle_t *pamh, int flags, int argc, if (!(ctrl & PAM_NO_ENV) && est) { char *tmp; - tmp = malloc(strlen(folder)+sizeof(MAIL_ENV_FORMAT)); - if (tmp != NULL) { - sprintf(tmp, MAIL_ENV_FORMAT, folder); - D(("setting env: %s", tmp)); - retval = pam_putenv(pamh, tmp); - _pam_overwrite(tmp); - _pam_drop(tmp); - if (retval != PAM_SUCCESS) { - _pam_overwrite(folder); - _pam_drop(folder); - _log_err(LOG_CRIT, "unable to set " MAIL_ENV_NAME " variable"); - return retval; - } - } else { - _log_err(LOG_CRIT, "no memory for " MAIL_ENV_NAME " variable"); - _pam_overwrite(folder); - _pam_drop(folder); - return retval; + if (asprintf(&tmp, MAIL_ENV_FORMAT, folder) < 0) { + pam_syslog(pamh, LOG_CRIT, + "no memory for " MAIL_ENV_NAME " variable"); + retval = PAM_BUF_ERR; + goto do_mail_cleanup; + } + D(("setting env: %s", tmp)); + retval = pam_putenv(pamh, tmp); + _pam_overwrite(tmp); + _pam_drop(tmp); + if (retval != PAM_SUCCESS) { + pam_syslog(pamh, LOG_CRIT, + "unable to set " MAIL_ENV_NAME " variable"); + retval = PAM_BUF_ERR; + goto do_mail_cleanup; } } else { D(("not setting " MAIL_ENV_NAME " variable")); @@ -466,10 +455,10 @@ static int _do_mail(pam_handle_t *pamh, int flags, int argc, if ((est && !(ctrl & PAM_NO_LOGIN)) || (!est && (ctrl & PAM_LOGOUT_TOO))) { - type = get_mail_status(ctrl, folder); - if (type != NULL) { + type = get_mail_status(pamh, ctrl, folder); + if (type != 0) { retval = report_mail(pamh, ctrl, type, folder); - type = NULL; + type = 0; } } @@ -477,7 +466,8 @@ static int _do_mail(pam_handle_t *pamh, int flags, int argc, if ( ! est && ! (ctrl & PAM_NO_ENV) ) (void) pam_putenv(pamh, MAIL_ENV_NAME); - _pam_overwrite(folder); /* clean up */ + do_mail_cleanup: + _pam_overwrite(folder); _pam_drop(folder); /* indicate success or failure */ |