123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564 |
- #if defined(HAVE_CONFIG_H)
- #include <config.h>
- #endif
- #include <pwd.h>
- #include <shadow.h>
- #include <time.h>
- #include <ctype.h>
- #include <errno.h>
- #include <fcntl.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>
- #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 "opasswd.h"
- #ifndef RANDOM_DEVICE
- #define RANDOM_DEVICE "/dev/urandom"
- #endif
- #define OLD_PASSWORDS_FILE "/etc/security/opasswd"
- #define TMP_PASSWORDS_FILE OLD_PASSWORDS_FILE".tmpXXXXXX"
- #define DEFAULT_BUFLEN 4096
- typedef struct {
- char *user;
- char *uid;
- int count;
- 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)
- {
- const char delimiters[] = ":";
- char *endptr;
- char *count;
- data->user = strsep (&line, delimiters);
- data->uid = strsep (&line, delimiters);
- count = strsep (&line, delimiters);
- if (count == NULL)
- return 1;
- data->count = strtol (count, &endptr, 10);
- if (endptr != NULL && *endptr != '\0')
- return 1;
- data->old_passwords = strsep (&line, delimiters);
- return 0;
- }
- static int
- compare_password(const char *newpass, const char *oldpass)
- {
- char *outval;
- #ifdef HAVE_CRYPT_R
- struct crypt_data output;
- output.initialized = 0;
- outval = crypt_r (newpass, oldpass, &output);
- #else
- outval = crypt (newpass, oldpass);
- #endif
- return outval != NULL && strcmp(outval, oldpass) == 0;
- }
- PAMH_ARG_DECL(int
- check_old_pass, const char *user, const char *newpass, int debug)
- {
- int retval = PAM_SUCCESS;
- FILE *oldpf;
- char *buf = NULL;
- size_t buflen = 0;
- opwd entry;
- int found = 0;
- #ifndef HELPER_COMPILE
- if (SELINUX_ENABLED)
- return PAM_PWHISTORY_RUN_HELPER;
- #endif
- if ((oldpf = fopen (OLD_PASSWORDS_FILE, "r")) == NULL)
- {
- if (errno != ENOENT)
- pam_syslog (pamh, LOG_ERR, "Cannot open %s: %m", OLD_PASSWORDS_FILE);
- return PAM_SUCCESS;
- }
- while (!feof (oldpf))
- {
- char *cp, *tmp;
- #if defined(HAVE_GETLINE)
- ssize_t n = getline (&buf, &buflen, oldpf);
- #elif defined (HAVE_GETDELIM)
- ssize_t n = getdelim (&buf, &buflen, '\n', oldpf);
- #else
- ssize_t n;
- if (buf == NULL)
- {
- buflen = DEFAULT_BUFLEN;
- buf = malloc (buflen);
- if (buf == NULL)
- return PAM_BUF_ERR;
- }
- buf[0] = '\0';
- fgets (buf, buflen - 1, oldpf);
- n = strlen (buf);
- #endif
- cp = buf;
- if (n < 1)
- break;
- tmp = strchr (cp, '#');
- if (tmp)
- *tmp = '\0';
- while (isspace ((int)*cp))
- ++cp;
- if (*cp == '\0')
- continue;
- if (cp[strlen (cp) - 1] == '\n')
- cp[strlen (cp) - 1] = '\0';
- if (strncmp (cp, user, strlen (user)) == 0 &&
- cp[strlen (user)] == ':')
- {
-
- if (parse_entry (cp, &entry) == 0)
- {
- found = 1;
- break;
- }
- }
- }
- fclose (oldpf);
- if (found && entry.old_passwords)
- {
- const char delimiters[] = ",";
- char *running;
- char *oldpass;
- running = entry.old_passwords;
- do {
- oldpass = strsep (&running, delimiters);
- if (oldpass && strlen (oldpass) > 0 &&
- compare_password(newpass, oldpass) )
- {
- if (debug)
- pam_syslog (pamh, LOG_DEBUG, "New password already used");
- retval = PAM_AUTHTOK_ERR;
- break;
- }
- } while (oldpass != NULL);
- }
- if (buf)
- free (buf);
- return retval;
- }
- PAMH_ARG_DECL(int
- save_old_pass, const char *user, int howmany, int debug UNUSED)
- {
- char opasswd_tmp[] = TMP_PASSWORDS_FILE;
- struct stat opasswd_stat;
- FILE *oldpf, *newpf;
- int newpf_fd;
- int do_create = 0;
- int retval = PAM_SUCCESS;
- char *buf = NULL;
- size_t buflen = 0;
- int found = 0;
- struct passwd *pwd;
- const char *oldpass;
- 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 (errno == ENOENT)
- {
- pam_syslog (pamh, LOG_NOTICE, "Creating %s",
- OLD_PASSWORDS_FILE);
- do_create = 1;
- }
- else
- {
- pam_syslog (pamh, LOG_ERR, "Cannot open %s: %m",
- OLD_PASSWORDS_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);
- fclose (oldpf);
- return PAM_AUTHTOK_ERR;
- }
-
- newpf_fd = mkstemp (opasswd_tmp);
- if (newpf_fd == -1)
- {
- pam_syslog (pamh, LOG_ERR, "Cannot create %s temp file: %m",
- OLD_PASSWORDS_FILE);
- if (oldpf)
- fclose (oldpf);
- return PAM_AUTHTOK_ERR;
- }
- if (do_create)
- {
- 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);
- if (fchown (newpf_fd, 0, 0) != 0)
- pam_syslog (pamh, LOG_ERR,
- "Cannot set owner/group of %s temp file: %m",
- OLD_PASSWORDS_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);
- 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);
- }
- newpf = fdopen (newpf_fd, "w+");
- if (newpf == NULL)
- {
- pam_syslog (pamh, LOG_ERR, "Cannot fdopen %s: %m", opasswd_tmp);
- if (oldpf)
- fclose (oldpf);
- close (newpf_fd);
- retval = PAM_AUTHTOK_ERR;
- goto error_opasswd;
- }
- if (!do_create)
- while (!feof (oldpf))
- {
- char *cp, *tmp, *save;
- #if defined(HAVE_GETLINE)
- ssize_t n = getline (&buf, &buflen, oldpf);
- #elif defined (HAVE_GETDELIM)
- ssize_t n = getdelim (&buf, &buflen, '\n', oldpf);
- #else
- ssize_t n;
- if (buf == NULL)
- {
- buflen = DEFAULT_BUFLEN;
- buf = malloc (buflen);
- if (buf == NULL)
- {
- fclose (oldpf);
- fclose (newpf);
- retval = PAM_BUF_ERR;
- goto error_opasswd;
- }
- }
- buf[0] = '\0';
- fgets (buf, buflen - 1, oldpf);
- n = strlen (buf);
- #endif
- if (n < 1)
- break;
- cp = buf;
- save = strdup (buf);
- if (save == NULL)
- {
- fclose (oldpf);
- fclose (newpf);
- retval = PAM_BUF_ERR;
- goto error_opasswd;
- }
- tmp = strchr (cp, '#');
- if (tmp)
- *tmp = '\0';
- while (isspace ((int)*cp))
- ++cp;
- if (*cp == '\0')
- goto write_old_data;
- if (cp[strlen (cp) - 1] == '\n')
- cp[strlen (cp) - 1] = '\0';
- if (strncmp (cp, user, strlen (user)) == 0 &&
- cp[strlen (user)] == ':')
- {
-
- opwd entry;
- if (parse_entry (cp, &entry) == 0)
- {
- char *out = NULL;
- found = 1;
-
- if (entry.old_passwords && entry.old_passwords[0] != '\0')
- {
- char *last = entry.old_passwords;
- cp = entry.old_passwords;
- entry.count = 1;
- while ((cp = strchr (cp, ',')) != NULL)
- {
- entry.count++;
- last = ++cp;
- }
-
- if (strcmp (last, oldpass) == 0)
- goto write_old_data;
- }
- else
- entry.count = 0;
-
- entry.count++;
-
- while (entry.count > howmany && entry.count > 1)
- {
- char *p = strpbrk (entry.old_passwords, ",");
- if (p != NULL)
- entry.old_passwords = ++p;
- entry.count--;
- }
- if (entry.count == 1)
- {
- if (asprintf (&out, "%s:%s:%d:%s\n",
- entry.user, entry.uid, entry.count,
- oldpass) < 0)
- {
- free (save);
- retval = PAM_AUTHTOK_ERR;
- fclose (oldpf);
- fclose (newpf);
- goto error_opasswd;
- }
- }
- else
- {
- if (asprintf (&out, "%s:%s:%d:%s,%s\n",
- entry.user, entry.uid, entry.count,
- entry.old_passwords, oldpass) < 0)
- {
- free (save);
- retval = PAM_AUTHTOK_ERR;
- fclose (oldpf);
- fclose (newpf);
- goto error_opasswd;
- }
- }
- if (fputs (out, newpf) < 0)
- {
- free (out);
- free (save);
- retval = PAM_AUTHTOK_ERR;
- fclose (oldpf);
- fclose (newpf);
- goto error_opasswd;
- }
- free (out);
- }
- }
- else
- {
- write_old_data:
- if (fputs (save, newpf) < 0)
- {
- free (save);
- retval = PAM_AUTHTOK_ERR;
- fclose (oldpf);
- fclose (newpf);
- goto error_opasswd;
- }
- }
- free (save);
- }
- if (!found)
- {
- char *out;
- if (asprintf (&out, "%s:%d:1:%s\n", user, pwd->pw_uid, oldpass) < 0)
- {
- retval = PAM_AUTHTOK_ERR;
- if (oldpf)
- fclose (oldpf);
- fclose (newpf);
- goto error_opasswd;
- }
- if (fputs (out, newpf) < 0)
- {
- free (out);
- retval = PAM_AUTHTOK_ERR;
- if (oldpf)
- fclose (oldpf);
- fclose (newpf);
- goto error_opasswd;
- }
- free (out);
- }
- if (oldpf)
- if (fclose (oldpf) != 0)
- {
- pam_syslog (pamh, LOG_ERR, "Error while closing old opasswd file: %m");
- retval = PAM_AUTHTOK_ERR;
- fclose (newpf);
- goto error_opasswd;
- }
- if (fflush (newpf) != 0 || fsync (fileno (newpf)) != 0)
- {
- pam_syslog (pamh, LOG_ERR,
- "Error while syncing temporary opasswd file: %m");
- retval = PAM_AUTHTOK_ERR;
- fclose (newpf);
- goto error_opasswd;
- }
- if (fclose (newpf) != 0)
- {
- pam_syslog (pamh, LOG_ERR,
- "Error while closing temporary opasswd file: %m");
- retval = PAM_AUTHTOK_ERR;
- goto error_opasswd;
- }
- unlink (OLD_PASSWORDS_FILE".old");
- if (link (OLD_PASSWORDS_FILE, OLD_PASSWORDS_FILE".old") != 0 &&
- errno != ENOENT)
- pam_syslog (pamh, LOG_ERR, "Cannot create backup file of %s: %m",
- OLD_PASSWORDS_FILE);
- rename (opasswd_tmp, OLD_PASSWORDS_FILE);
- error_opasswd:
- unlink (opasswd_tmp);
- free (buf);
- return retval;
- }
|