diff options
Diffstat (limited to 'modules/pam_pwhistory/opasswd.c')
-rw-r--r-- | modules/pam_pwhistory/opasswd.c | 146 |
1 files changed, 109 insertions, 37 deletions
diff --git a/modules/pam_pwhistory/opasswd.c b/modules/pam_pwhistory/opasswd.c index 77142f2c..859b3da4 100644 --- a/modules/pam_pwhistory/opasswd.c +++ b/modules/pam_pwhistory/opasswd.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Thorsten Kukuk <kukuk@suse.de> + * Copyright (c) 2013 Red Hat, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -38,25 +39,36 @@ #endif #include <pwd.h> +#include <shadow.h> #include <time.h> #include <ctype.h> #include <errno.h> #include <fcntl.h> +#include <limits.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <syslog.h> +#ifdef HELPER_COMPILE +#include <stdarg.h> +#endif #include <sys/stat.h> -#if defined HAVE_LIBXCRYPT -#include <xcrypt.h> -#elif defined (HAVE_CRYPT_H) +#ifdef HAVE_CRYPT_H #include <crypt.h> #endif +#ifdef HELPER_COMPILE +#define pam_modutil_getpwnam(h,n) getpwnam(n) +#define pam_modutil_getspnam(h,n) getspnam(n) +#define pam_syslog(h,a,...) helper_log_err(a,__VA_ARGS__) +#else +#include <security/pam_modutil.h> #include <security/pam_ext.h> +#endif #include <security/pam_modules.h> +#include "pam_inline.h" #include "opasswd.h" @@ -64,8 +76,7 @@ #define RANDOM_DEVICE "/dev/urandom" #endif -#define OLD_PASSWORDS_FILE "/etc/security/opasswd" -#define TMP_PASSWORDS_FILE OLD_PASSWORDS_FILE".tmpXXXXXX" +#define DEFAULT_OLD_PASSWORDS_FILE SCONFIGDIR "/opasswd" #define DEFAULT_BUFLEN 4096 @@ -76,6 +87,20 @@ typedef struct { char *old_passwords; } opwd; +#ifdef HELPER_COMPILE +PAM_FORMAT((printf, 2, 3)) +void +helper_log_err(int err, const char *format, ...) +{ + va_list args; + + va_start(args, format); + openlog(HELPER_COMPILE, LOG_CONS | LOG_PID, LOG_AUTHPRIV); + vsyslog(err, format, args); + va_end(args); + closelog(); +} +#endif static int parse_entry (char *line, opwd *data) @@ -105,6 +130,7 @@ compare_password(const char *newpass, const char *oldpass) char *outval; #ifdef HAVE_CRYPT_R struct crypt_data output; + int retval; output.initialized = 0; @@ -113,13 +139,14 @@ compare_password(const char *newpass, const char *oldpass) outval = crypt (newpass, oldpass); #endif - return outval != NULL && strcmp(outval, oldpass) == 0; + retval = outval != NULL && strcmp(outval, oldpass) == 0; + pam_overwrite_string(outval); + return retval; } /* Check, if the new password is already in the opasswd file. */ -int -check_old_pass (pam_handle_t *pamh, const char *user, - const char *newpass, int debug) +PAMH_ARG_DECL(int +check_old_pass, const char *user, const char *newpass, const char *filename, int debug) { int retval = PAM_SUCCESS; FILE *oldpf; @@ -128,10 +155,18 @@ check_old_pass (pam_handle_t *pamh, const char *user, opwd entry; int found = 0; - if ((oldpf = fopen (OLD_PASSWORDS_FILE, "r")) == NULL) +#ifndef HELPER_COMPILE + if (SELINUX_ENABLED) + return PAM_PWHISTORY_RUN_HELPER; +#endif + + const char *opasswd_file = + (filename != NULL ? filename : DEFAULT_OLD_PASSWORDS_FILE); + + if ((oldpf = fopen (opasswd_file, "r")) == NULL) { if (errno != ENOENT) - pam_syslog (pamh, LOG_ERR, "Cannot open %s: %m", OLD_PASSWORDS_FILE); + pam_syslog (pamh, LOG_ERR, "Cannot open %s: %m", opasswd_file); return PAM_SUCCESS; } @@ -207,17 +242,15 @@ check_old_pass (pam_handle_t *pamh, const char *user, } while (oldpass != NULL); } - if (buf) - free (buf); + pam_overwrite_n(buf, buflen); + free (buf); return retval; } -int -save_old_pass (pam_handle_t *pamh, const char *user, uid_t uid, - const char *oldpass, int howmany, int debug UNUSED) +PAMH_ARG_DECL(int +save_old_pass, const char *user, int howmany, const char *filename, int debug UNUSED) { - char opasswd_tmp[] = TMP_PASSWORDS_FILE; struct stat opasswd_stat; FILE *oldpf, *newpf; int newpf_fd; @@ -226,31 +259,63 @@ save_old_pass (pam_handle_t *pamh, const char *user, uid_t uid, char *buf = NULL; size_t buflen = 0; int found = 0; + struct passwd *pwd; + const char *oldpass; + + /* Define opasswd file and temp file for opasswd */ + const char *opasswd_file = + (filename != NULL ? filename : DEFAULT_OLD_PASSWORDS_FILE); + char opasswd_tmp[PATH_MAX]; + + if ((size_t) snprintf (opasswd_tmp, sizeof (opasswd_tmp), "%s.tmpXXXXXX", + opasswd_file) >= sizeof (opasswd_tmp)) + return PAM_BUF_ERR; + + pwd = pam_modutil_getpwnam (pamh, user); + if (pwd == NULL) + return PAM_USER_UNKNOWN; if (howmany <= 0) return PAM_SUCCESS; +#ifndef HELPER_COMPILE + if (SELINUX_ENABLED) + return PAM_PWHISTORY_RUN_HELPER; +#endif + + if ((strcmp(pwd->pw_passwd, "x") == 0) || + ((pwd->pw_passwd[0] == '#') && + (pwd->pw_passwd[1] == '#') && + (strcmp(pwd->pw_name, pwd->pw_passwd + 2) == 0))) + { + struct spwd *spw = pam_modutil_getspnam (pamh, user); + + if (spw == NULL) + return PAM_USER_UNKNOWN; + oldpass = spw->sp_pwdp; + } + else + oldpass = pwd->pw_passwd; + if (oldpass == NULL || *oldpass == '\0') return PAM_SUCCESS; - if ((oldpf = fopen (OLD_PASSWORDS_FILE, "r")) == NULL) + if ((oldpf = fopen (opasswd_file, "r")) == NULL) { if (errno == ENOENT) { - pam_syslog (pamh, LOG_NOTICE, "Creating %s", - OLD_PASSWORDS_FILE); + pam_syslog (pamh, LOG_NOTICE, "Creating %s", opasswd_file); do_create = 1; } else { - pam_syslog (pamh, LOG_ERR, "Cannot open %s: %m", - OLD_PASSWORDS_FILE); + pam_syslog (pamh, LOG_ERR, "Cannot open %s: %m", opasswd_file); return PAM_AUTHTOK_ERR; } } else if (fstat (fileno (oldpf), &opasswd_stat) < 0) { - pam_syslog (pamh, LOG_ERR, "Cannot stat %s: %m", OLD_PASSWORDS_FILE); + pam_syslog (pamh, LOG_ERR, "Cannot stat %s: %m", opasswd_file); fclose (oldpf); return PAM_AUTHTOK_ERR; } @@ -260,7 +325,7 @@ save_old_pass (pam_handle_t *pamh, const char *user, uid_t uid, if (newpf_fd == -1) { pam_syslog (pamh, LOG_ERR, "Cannot create %s temp file: %m", - OLD_PASSWORDS_FILE); + opasswd_file); if (oldpf) fclose (oldpf); return PAM_AUTHTOK_ERR; @@ -269,23 +334,19 @@ save_old_pass (pam_handle_t *pamh, const char *user, uid_t uid, { if (fchmod (newpf_fd, S_IRUSR|S_IWUSR) != 0) pam_syslog (pamh, LOG_ERR, - "Cannot set permissions of %s temp file: %m", - OLD_PASSWORDS_FILE); + "Cannot set permissions of %s temp file: %m", opasswd_file); if (fchown (newpf_fd, 0, 0) != 0) pam_syslog (pamh, LOG_ERR, - "Cannot set owner/group of %s temp file: %m", - OLD_PASSWORDS_FILE); + "Cannot set owner/group of %s temp file: %m", opasswd_file); } else { if (fchmod (newpf_fd, opasswd_stat.st_mode) != 0) pam_syslog (pamh, LOG_ERR, - "Cannot set permissions of %s temp file: %m", - OLD_PASSWORDS_FILE); + "Cannot set permissions of %s temp file: %m", opasswd_file); if (fchown (newpf_fd, opasswd_stat.st_uid, opasswd_stat.st_gid) != 0) pam_syslog (pamh, LOG_ERR, - "Cannot set owner/group of %s temp file: %m", - OLD_PASSWORDS_FILE); + "Cannot set owner/group of %s temp file: %m", opasswd_file); } newpf = fdopen (newpf_fd, "w+"); if (newpf == NULL) @@ -452,7 +513,7 @@ save_old_pass (pam_handle_t *pamh, const char *user, uid_t uid, { char *out; - if (asprintf (&out, "%s:%d:1:%s\n", user, uid, oldpass) < 0) + if (asprintf (&out, "%s:%d:1:%s\n", user, pwd->pw_uid, oldpass) < 0) { retval = PAM_AUTHTOK_ERR; if (oldpf) @@ -462,6 +523,7 @@ save_old_pass (pam_handle_t *pamh, const char *user, uid_t uid, } if (fputs (out, newpf) < 0) { + pam_overwrite_string(out); free (out); retval = PAM_AUTHTOK_ERR; if (oldpf) @@ -469,6 +531,7 @@ save_old_pass (pam_handle_t *pamh, const char *user, uid_t uid, fclose (newpf); goto error_opasswd; } + pam_overwrite_string(out); free (out); } @@ -498,14 +561,23 @@ save_old_pass (pam_handle_t *pamh, const char *user, uid_t uid, goto error_opasswd; } - unlink (OLD_PASSWORDS_FILE".old"); - if (link (OLD_PASSWORDS_FILE, OLD_PASSWORDS_FILE".old") != 0 && + char opasswd_backup[PATH_MAX]; + if ((size_t) snprintf (opasswd_backup, sizeof (opasswd_backup), "%s.old", + opasswd_file) >= sizeof (opasswd_backup)) + { + retval = PAM_BUF_ERR; + goto error_opasswd; + } + + unlink (opasswd_backup); + if (link (opasswd_file, opasswd_backup) != 0 && errno != ENOENT) pam_syslog (pamh, LOG_ERR, "Cannot create backup file of %s: %m", - OLD_PASSWORDS_FILE); - rename (opasswd_tmp, OLD_PASSWORDS_FILE); + opasswd_file); + rename (opasswd_tmp, opasswd_file); error_opasswd: unlink (opasswd_tmp); + pam_overwrite_n(buf, buflen); free (buf); return retval; |