(root)/
Linux-PAM-1.5.3/
modules/
pam_unix/
passverify.c
       1  /*
       2   * Copyright information at end of file.
       3   */
       4  #include "config.h"
       5  #include <security/_pam_macros.h>
       6  #include <security/pam_modules.h>
       7  #include "support.h"
       8  #include <stdio.h>
       9  #include <string.h>
      10  #include <sys/types.h>
      11  #include <unistd.h>
      12  #include <pwd.h>
      13  #include <shadow.h>
      14  #include <syslog.h>
      15  #include <stdarg.h>
      16  #include <signal.h>
      17  #include <errno.h>
      18  #include <time.h>
      19  #include <sys/time.h>
      20  #include <sys/stat.h>
      21  #include <fcntl.h>
      22  #ifdef HAVE_CRYPT_H
      23  #include <crypt.h>
      24  #endif
      25  
      26  #include "pam_cc_compat.h"
      27  #include "pam_inline.h"
      28  #include "md5.h"
      29  #include "bigcrypt.h"
      30  #include "passverify.h"
      31  
      32  #ifdef WITH_SELINUX
      33  #include <selinux/selinux.h>
      34  #define SELINUX_ENABLED (is_selinux_enabled()>0)
      35  #else
      36  #define SELINUX_ENABLED 0
      37  #endif
      38  
      39  #ifdef HELPER_COMPILE
      40  #define pam_modutil_getpwnam(h,n) getpwnam(n)
      41  #define pam_modutil_getspnam(h,n) getspnam(n)
      42  #define pam_syslog(h,a,b,c) helper_log_err(a,b,c)
      43  #else
      44  #include <security/pam_modutil.h>
      45  #include <security/pam_ext.h>
      46  #endif
      47  
      48  #if defined(USE_LCKPWDF) && !defined(HAVE_LCKPWDF)
      49  # include "./lckpwdf.-c"
      50  #endif
      51  
      52  static void
      53  strip_hpux_aging(char *hash)
      54  {
      55  	static const char valid[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
      56  		"abcdefghijklmnopqrstuvwxyz"
      57  		"0123456789./";
      58  	if ((*hash != '$') && (strlen(hash) > 13)) {
      59  		for (hash += 13; *hash != '\0'; hash++) {
      60  			if (strchr(valid, *hash) == NULL) {
      61  				*hash = '\0';
      62  				break;
      63  			}
      64  		}
      65  	}
      66  }
      67  
      68  PAMH_ARG_DECL(int verify_pwd_hash,
      69  	const char *p, char *hash, unsigned int nullok)
      70  {
      71  	size_t hash_len;
      72  	char *pp = NULL;
      73  	int retval;
      74  	D(("called"));
      75  
      76  	strip_hpux_aging(hash);
      77  	hash_len = strlen(hash);
      78  	if (!hash_len) {
      79  		/* the stored password is NULL */
      80  		if (nullok) { /* this means we've succeeded */
      81  			D(("user has empty password - access granted"));
      82  			retval = PAM_SUCCESS;
      83  		} else {
      84  			D(("user has empty password - access denied"));
      85  			retval = PAM_AUTH_ERR;
      86  		}
      87  	} else if (!p || *hash == '*' || *hash == '!') {
      88  		retval = PAM_AUTH_ERR;
      89  	} else {
      90  		if (pam_str_skip_prefix(hash, "$1$") != NULL) {
      91  			pp = Goodcrypt_md5(p, hash);
      92  			if (pp && strcmp(pp, hash) != 0) {
      93  				_pam_delete(pp);
      94  				pp = Brokencrypt_md5(p, hash);
      95  			}
      96  		} else if (*hash != '$' && hash_len >= 13) {
      97  			pp = bigcrypt(p, hash);
      98  			if (pp && hash_len == 13 && strlen(pp) > hash_len) {
      99  				pam_overwrite_string(pp + hash_len);
     100  			}
     101  		} else {
     102  			/*
     103  			 * Ok, we don't know the crypt algorithm, but maybe
     104  			 * libcrypt knows about it? We should try it.
     105  			 */
     106  #if defined(CRYPT_CHECKSALT_AVAILABLE) && CRYPT_CHECKSALT_AVAILABLE
     107  			/* Get the status of the hash from checksalt */
     108  			int retval_checksalt = crypt_checksalt(hash);
     109  
     110  			/*
     111  			 * Check for hashing methods that are disabled by
     112  			 * libcrypt configuration and/or system preset.
     113  			 */
     114  			if (retval_checksalt == CRYPT_SALT_METHOD_DISABLED) {
     115  				/*
     116  				 * pam_syslog() needs a pam handle,
     117  				 * but that's not available here.
     118  				 */
     119  				pam_syslog(pamh, LOG_ERR,
     120  				  "The support for password hash \"%.6s\" "
     121  				  "has been disabled in libcrypt "
     122  				  "configuration.",
     123  				  hash);
     124  			}
     125  			/*
     126  			 * Check for malformed hashes, like descrypt hashes
     127  			 * starting with "$2...", which might have been
     128  			 * generated by unsafe base64 encoding functions
     129  			 * as used in glibc <= 2.16.
     130  			 * Such hashes are likely to be rejected by many
     131  			 * recent implementations of libcrypt.
     132  			 */
     133  			if (retval_checksalt == CRYPT_SALT_INVALID) {
     134  				pam_syslog(pamh, LOG_ERR,
     135  				  "The password hash \"%.6s\" is unknown to "
     136  				  "libcrypt.",
     137  				  hash);
     138  			}
     139  #else
     140  #ifndef HELPER_COMPILE
     141  			(void)pamh;
     142  #endif
     143  #endif
     144  #ifdef HAVE_CRYPT_R
     145  			struct crypt_data *cdata;
     146  			cdata = malloc(sizeof(*cdata));
     147  			if (cdata != NULL) {
     148  				cdata->initialized = 0;
     149  				pp = x_strdup(crypt_r(p, hash, cdata));
     150  				pam_overwrite_object(cdata);
     151  				free(cdata);
     152  			}
     153  #else
     154  			pp = x_strdup(crypt(p, hash));
     155  #endif
     156  		}
     157  		p = NULL;		/* no longer needed here */
     158  
     159  		/* the moment of truth -- do we agree with the password? */
     160  		D(("comparing state of pp[%s] and hash[%s]", pp, hash));
     161  
     162  		if (pp && strcmp(pp, hash) == 0) {
     163  			retval = PAM_SUCCESS;
     164  		} else {
     165  			retval = PAM_AUTH_ERR;
     166  		}
     167  	}
     168  
     169  	if (pp)
     170  		_pam_delete(pp);
     171  	D(("done [%d].", retval));
     172  
     173  	return retval;
     174  }
     175  
     176  int
     177  is_pwd_shadowed(const struct passwd *pwd)
     178  {
     179  	if (pwd != NULL) {
     180  		if (strcmp(pwd->pw_passwd, "x") == 0) {
     181  			return 1;
     182  		}
     183  		if ((pwd->pw_passwd[0] == '#') &&
     184  		    (pwd->pw_passwd[1] == '#') &&
     185  		    (strcmp(pwd->pw_name, pwd->pw_passwd + 2) == 0)) {
     186  			return 1;
     187  		}
     188  	}
     189  	return 0;
     190  }
     191  
     192  PAMH_ARG_DECL(int get_account_info,
     193  	const char *name, struct passwd **pwd, struct spwd **spwdent)
     194  {
     195  	/* UNIX passwords area */
     196  	*pwd = pam_modutil_getpwnam(pamh, name);	/* Get password file entry... */
     197  	*spwdent = NULL;
     198  
     199  	if (*pwd != NULL) {
     200  		if (strcmp((*pwd)->pw_passwd, "*NP*") == 0)
     201  		{ /* NIS+ */
     202  #ifdef HELPER_COMPILE
     203  			uid_t save_euid, save_uid;
     204  
     205  			save_euid = geteuid();
     206  			save_uid = getuid();
     207  			if (save_uid == (*pwd)->pw_uid) {
     208  				if (setreuid(save_euid, save_uid))
     209  					return PAM_CRED_INSUFFICIENT;
     210  			} else  {
     211  				if (setreuid(0, -1))
     212  					return PAM_CRED_INSUFFICIENT;
     213  				if (setreuid(-1, (*pwd)->pw_uid)) {
     214  					if (setreuid(-1, 0)
     215  					    || setreuid(0, -1)
     216  					    || setreuid(-1, (*pwd)->pw_uid)) {
     217  						return PAM_CRED_INSUFFICIENT;
     218  					}
     219  				}
     220  			}
     221  
     222  			*spwdent = pam_modutil_getspnam(pamh, name);
     223  			if (save_uid == (*pwd)->pw_uid) {
     224  				if (setreuid(save_uid, save_euid))
     225  					return PAM_CRED_INSUFFICIENT;
     226  			} else {
     227  				if (setreuid(-1, 0)
     228  				    || setreuid(save_uid, -1)
     229  				    || setreuid(-1, save_euid))
     230  					return PAM_CRED_INSUFFICIENT;
     231  			}
     232  
     233  			if (*spwdent == NULL || (*spwdent)->sp_pwdp == NULL)
     234  				return PAM_AUTHINFO_UNAVAIL;
     235  #else
     236  			/* we must run helper for NIS+ passwords */
     237  			return PAM_UNIX_RUN_HELPER;
     238  #endif
     239  		} else if (is_pwd_shadowed(*pwd)) {
     240  			/*
     241  			 * ...and shadow password file entry for this user,
     242  			 * if shadowing is enabled
     243  			 */
     244  			*spwdent = pam_modutil_getspnam(pamh, name);
     245  			if (*spwdent == NULL) {
     246  #ifndef HELPER_COMPILE
     247  				/* still a chance the user can authenticate */
     248  				return PAM_UNIX_RUN_HELPER;
     249  #endif
     250  				return PAM_AUTHINFO_UNAVAIL;
     251  			}
     252  			if ((*spwdent)->sp_pwdp == NULL)
     253  				return PAM_AUTHINFO_UNAVAIL;
     254  		}
     255  	} else {
     256  		return PAM_USER_UNKNOWN;
     257  	}
     258  	return PAM_SUCCESS;
     259  }
     260  
     261  PAMH_ARG_DECL(int get_pwd_hash,
     262  	const char *name, struct passwd **pwd, char **hash)
     263  {
     264  	int retval;
     265  	struct spwd *spwdent = NULL;
     266  
     267  	retval = get_account_info(PAMH_ARG(name, pwd, &spwdent));
     268  	if (retval != PAM_SUCCESS) {
     269  		return retval;
     270  	}
     271  
     272  	if (spwdent)
     273  		*hash = x_strdup(spwdent->sp_pwdp);
     274  	else
     275  		*hash = x_strdup((*pwd)->pw_passwd);
     276  	if (*hash == NULL)
     277  		return PAM_BUF_ERR;
     278  
     279  	return PAM_SUCCESS;
     280  }
     281  
     282  PAMH_ARG_DECL(int check_shadow_expiry,
     283  	struct spwd *spent, int *daysleft)
     284  {
     285  	long int curdays;
     286  	*daysleft = -1;
     287  	curdays = (long int)(time(NULL) / (60 * 60 * 24));
     288  	D(("today is %d, last change %d", curdays, spent->sp_lstchg));
     289  	if ((curdays >= spent->sp_expire) && (spent->sp_expire != -1)) {
     290  		D(("account expired"));
     291  		return PAM_ACCT_EXPIRED;
     292  	}
     293  	if (spent->sp_lstchg == 0) {
     294  		D(("need a new password"));
     295  		*daysleft = 0;
     296  		return PAM_NEW_AUTHTOK_REQD;
     297  	}
     298  	if (curdays < spent->sp_lstchg) {
     299  		pam_syslog(pamh, LOG_DEBUG,
     300  			 "account %s has password changed in future",
     301  			 spent->sp_namp);
     302  		return PAM_SUCCESS;
     303  	}
     304  	if ((curdays - spent->sp_lstchg > spent->sp_max)
     305  	    && (curdays - spent->sp_lstchg > spent->sp_inact)
     306  	    && (curdays - spent->sp_lstchg > spent->sp_max + spent->sp_inact)
     307  	    && (spent->sp_max != -1) && (spent->sp_inact != -1)) {
     308  		*daysleft = (int)((spent->sp_lstchg + spent->sp_max) - curdays);
     309  		D(("authtok expired"));
     310  		return PAM_AUTHTOK_EXPIRED;
     311  	}
     312  	if ((curdays - spent->sp_lstchg > spent->sp_max) && (spent->sp_max != -1)) {
     313  		D(("need a new password 2"));
     314  		return PAM_NEW_AUTHTOK_REQD;
     315  	}
     316  	if ((curdays - spent->sp_lstchg > spent->sp_max - spent->sp_warn)
     317  	    && (spent->sp_max != -1) && (spent->sp_warn != -1)) {
     318  		*daysleft = (int)((spent->sp_lstchg + spent->sp_max) - curdays);
     319  		D(("warn before expiry"));
     320  	}
     321  	if ((curdays - spent->sp_lstchg < spent->sp_min)
     322  	    && (spent->sp_min != -1)) {
     323  		/*
     324  		 * The last password change was too recent. This error will be ignored
     325  		 * if no password change is attempted.
     326  		 */
     327  		D(("password change too recent"));
     328  		return PAM_AUTHTOK_ERR;
     329  	}
     330  	return PAM_SUCCESS;
     331  }
     332  
     333  /* passwd/salt conversion macros */
     334  
     335  #define PW_TMPFILE              "/etc/npasswd"
     336  #define SH_TMPFILE              "/etc/nshadow"
     337  #define OPW_TMPFILE             SCONFIGDIR "/nopasswd"
     338  
     339  /*
     340   * i64c - convert an integer to a radix 64 character
     341   */
     342  static int
     343  i64c(int i)
     344  {
     345          if (i < 0)
     346                  return ('.');
     347          else if (i > 63)
     348                  return ('z');
     349          if (i == 0)
     350                  return ('.');
     351          if (i == 1)
     352                  return ('/');
     353          if (i >= 2 && i <= 11)
     354                  return ('0' - 2 + i);
     355          if (i >= 12 && i <= 37)
     356                  return ('A' - 12 + i);
     357          if (i >= 38 && i <= 63)
     358                  return ('a' - 38 + i);
     359          return ('\0');
     360  }
     361  
     362  /* <where> must point to a buffer of at least <length>+1 length */
     363  static void
     364  crypt_make_salt(char *where, int length)
     365  {
     366          struct timeval tv;
     367          MD5_CTX ctx;
     368          unsigned char tmp[16];
     369          unsigned char *src = (unsigned char *)where;
     370          int i;
     371  #ifdef PAM_PATH_RANDOMDEV
     372  	int fd;
     373  	int rv;
     374  
     375  	if ((rv = fd = open(PAM_PATH_RANDOMDEV, O_RDONLY)) != -1) {
     376  		while ((rv = read(fd, where, length)) != length && errno == EINTR);
     377  		close (fd);
     378  	}
     379  	if (rv != length) {
     380  #endif
     381          /*
     382           * Code lifted from Marek Michalkiewicz's shadow suite. (CG)
     383           * removed use of static variables (AGM)
     384           *
     385  	 * will work correctly only for length <= 16 */
     386  	src = tmp;
     387          GoodMD5Init(&ctx);
     388          gettimeofday(&tv, (struct timezone *) 0);
     389          GoodMD5Update(&ctx, (void *) &tv, sizeof tv);
     390          i = getpid();
     391          GoodMD5Update(&ctx, (void *) &i, sizeof i);
     392          i = clock();
     393          GoodMD5Update(&ctx, (void *) &i, sizeof i);
     394          GoodMD5Update(&ctx, src, length);
     395          GoodMD5Final(tmp, &ctx);
     396  #ifdef PAM_PATH_RANDOMDEV
     397  	}
     398  #endif
     399          for (i = 0; i < length; i++)
     400                  *where++ = i64c(src[i] & 077);
     401          *where = '\0';
     402  }
     403  
     404  char *
     405  crypt_md5_wrapper(const char *pass_new)
     406  {
     407          unsigned char result[16];
     408          char *cp = (char *) result;
     409  
     410          cp = stpcpy(cp, "$1$");      /* magic for the MD5 */
     411  	crypt_make_salt(cp, 8);
     412  
     413          /* no longer need cleartext */
     414          cp = Goodcrypt_md5(pass_new, (const char *) result);
     415  	pass_new = NULL;
     416  
     417          return cp;
     418  }
     419  
     420  PAMH_ARG_DECL(char * create_password_hash,
     421  	const char *password, unsigned long long ctrl, int rounds)
     422  {
     423  	const char *algoid;
     424  #if defined(CRYPT_GENSALT_OUTPUT_SIZE) && CRYPT_GENSALT_OUTPUT_SIZE > 64
     425  	/* Strings returned by crypt_gensalt_rn will be no longer than this. */
     426  	char salt[CRYPT_GENSALT_OUTPUT_SIZE];
     427  #else
     428  	char salt[64]; /* contains rounds number + max 16 bytes of salt + algo id */
     429  #endif
     430  	char *sp, *ret;
     431  #ifdef HAVE_CRYPT_R
     432  	struct crypt_data *cdata = NULL;
     433  #endif
     434  
     435  	if (on(UNIX_MD5_PASS, ctrl)) {
     436  		/* algoid = "$1" */
     437  		return crypt_md5_wrapper(password);
     438  	} else if (on(UNIX_YESCRYPT_PASS, ctrl)) {
     439  		algoid = "$y$";
     440  	} else if (on(UNIX_GOST_YESCRYPT_PASS, ctrl)) {
     441  		algoid = "$gy$";
     442  	} else if (on(UNIX_BLOWFISH_PASS, ctrl)) {
     443  		algoid = "$2b$";
     444  	} else if (on(UNIX_SHA256_PASS, ctrl)) {
     445  		algoid = "$5$";
     446  	} else if (on(UNIX_SHA512_PASS, ctrl)) {
     447  		algoid = "$6$";
     448  	} else { /* must be crypt/bigcrypt */
     449  		char tmppass[9];
     450  		char *hashed;
     451  
     452  		crypt_make_salt(salt, 2);
     453  		if (off(UNIX_BIGCRYPT, ctrl) && strlen(password) > 8) {
     454  			strncpy(tmppass, password, sizeof(tmppass)-1);
     455  			tmppass[sizeof(tmppass)-1] = '\0';
     456  			password = tmppass;
     457  		}
     458  		hashed = bigcrypt(password, salt);
     459  		pam_overwrite_array(tmppass);
     460  		password = NULL;
     461  		return hashed;
     462  	}
     463  
     464  #if defined(CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY) && CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY
     465  	/*
     466  	 * Any version of libcrypt supporting auto entropy is
     467  	 * guaranteed to have crypt_gensalt_rn().
     468  	 */
     469  	sp = crypt_gensalt_rn(algoid, rounds, NULL, 0, salt, sizeof(salt));
     470  #else
     471  	sp = stpcpy(salt, algoid);
     472  	if (on(UNIX_ALGO_ROUNDS, ctrl)) {
     473  		sp += snprintf(sp, sizeof(salt) - (16 + 1 + (sp - salt)), "rounds=%u$", rounds);
     474  	}
     475  	crypt_make_salt(sp, 16);
     476  #endif /* CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY */
     477  #ifdef HAVE_CRYPT_R
     478  	sp = NULL;
     479  	cdata = malloc(sizeof(*cdata));
     480  	if (cdata != NULL) {
     481  		cdata->initialized = 0;
     482  		sp = crypt_r(password, salt, cdata);
     483  	}
     484  #else
     485  	sp = crypt(password, salt);
     486  #endif
     487  	if (!sp || strncmp(algoid, sp, strlen(algoid)) != 0) {
     488  		/* libxcrypt/libc doesn't know the algorithm, error out */
     489  		pam_syslog(pamh, LOG_ERR,
     490  			   "Algo %s not supported by the crypto backend.\n",
     491  			   on(UNIX_YESCRYPT_PASS, ctrl) ? "yescrypt" :
     492  			   on(UNIX_GOST_YESCRYPT_PASS, ctrl) ? "gost_yescrypt" :
     493  			   on(UNIX_BLOWFISH_PASS, ctrl) ? "blowfish" :
     494  			   on(UNIX_SHA256_PASS, ctrl) ? "sha256" :
     495  			   on(UNIX_SHA512_PASS, ctrl) ? "sha512" : algoid);
     496  		if(sp) {
     497  		   pam_overwrite_string(sp);
     498  		}
     499  #ifdef HAVE_CRYPT_R
     500  		pam_overwrite_object(cdata);
     501  		free(cdata);
     502  #endif
     503  		return NULL;
     504  	}
     505  	ret = strdup(sp);
     506  	pam_overwrite_string(sp);
     507  #ifdef HAVE_CRYPT_R
     508  	pam_overwrite_object(cdata);
     509  	free(cdata);
     510  #endif
     511  	return ret;
     512  }
     513  
     514  #ifdef WITH_SELINUX
     515  int
     516  unix_selinux_confined(void)
     517  {
     518      static int confined = -1;
     519      int fd;
     520      char tempfile[]="/etc/.pwdXXXXXX";
     521  
     522      if (confined != -1)
     523  	return confined;
     524  
     525      /* cannot be confined without SELinux enabled */
     526      if (!SELINUX_ENABLED){
     527  	confined = 0;
     528  	return confined;
     529      }
     530  
     531      /* let's try opening shadow read only */
     532      if ((fd=open("/etc/shadow", O_RDONLY)) != -1) {
     533          close(fd);
     534          confined = 0;
     535          return confined;
     536      }
     537  
     538      if (errno == EACCES) {
     539  	confined = 1;
     540  	return confined;
     541      }
     542  
     543      /* shadow opening failed because of other reasons let's try
     544         creating a file in /etc */
     545      if ((fd=mkstemp(tempfile)) != -1) {
     546          unlink(tempfile);
     547          close(fd);
     548          confined = 0;
     549          return confined;
     550      }
     551  
     552      confined = 1;
     553      return confined;
     554  }
     555  
     556  #else
     557  int
     558  unix_selinux_confined(void)
     559  {
     560      return 0;
     561  }
     562  #endif
     563  
     564  #ifdef USE_LCKPWDF
     565  int
     566  lock_pwdf(void)
     567  {
     568          int i;
     569          int retval;
     570  
     571  #ifndef HELPER_COMPILE
     572          if (unix_selinux_confined()) {
     573                  return PAM_SUCCESS;
     574          }
     575  #endif
     576          /* These values for the number of attempts and the sleep time
     577             are, of course, completely arbitrary.
     578             My reading of the PAM docs is that, once pam_chauthtok() has been
     579             called with PAM_UPDATE_AUTHTOK, we are obliged to take any
     580             reasonable steps to make sure the token is updated; so retrying
     581             for 1/10 sec. isn't overdoing it. */
     582          i=0;
     583          while((retval = lckpwdf()) != 0 && i < 100) {
     584                  usleep(1000);
     585                  i++;
     586          }
     587          if(retval != 0) {
     588                  return PAM_AUTHTOK_LOCK_BUSY;
     589          }
     590          return PAM_SUCCESS;
     591  }
     592  
     593  void
     594  unlock_pwdf(void)
     595  {
     596  #ifndef HELPER_COMPILE
     597          if (unix_selinux_confined()) {
     598                  return;
     599          }
     600  #endif
     601          ulckpwdf();
     602  }
     603  #else
     604  int
     605  lock_pwdf(void)
     606  {
     607  	return PAM_SUCCESS;
     608  }
     609  
     610  void
     611  unlock_pwdf(void)
     612  {
     613  	return;
     614  }
     615  #endif
     616  
     617  #ifdef HELPER_COMPILE
     618  int
     619  save_old_password(const char *forwho, const char *oldpass,
     620  		  int howmany)
     621  #else
     622  int
     623  save_old_password(pam_handle_t *pamh, const char *forwho, const char *oldpass,
     624  		  int howmany)
     625  #endif
     626  {
     627      static char buf[16384];
     628      static char nbuf[16384];
     629      char *s_luser, *s_uid, *s_npas, *s_pas, *pass;
     630      int npas;
     631      FILE *pwfile, *opwfile;
     632      int err = 0;
     633      int oldmask;
     634      int found = 0;
     635      struct passwd *pwd = NULL;
     636      struct stat st;
     637      size_t len = strlen(forwho);
     638  #ifdef WITH_SELINUX
     639      char *prev_context_raw = NULL;
     640  #endif
     641  
     642      if (howmany < 0) {
     643  	return PAM_SUCCESS;
     644      }
     645  
     646      if (oldpass == NULL) {
     647  	return PAM_SUCCESS;
     648      }
     649  
     650      oldmask = umask(077);
     651  
     652  #ifdef WITH_SELINUX
     653      if (SELINUX_ENABLED) {
     654        char *passwd_context_raw = NULL;
     655        if (getfilecon_raw("/etc/passwd",&passwd_context_raw)<0) {
     656          return PAM_AUTHTOK_ERR;
     657        };
     658        if (getfscreatecon_raw(&prev_context_raw)<0) {
     659          freecon(passwd_context_raw);
     660          return PAM_AUTHTOK_ERR;
     661        }
     662        if (setfscreatecon_raw(passwd_context_raw)) {
     663          freecon(passwd_context_raw);
     664          freecon(prev_context_raw);
     665          return PAM_AUTHTOK_ERR;
     666        }
     667        freecon(passwd_context_raw);
     668      }
     669  #endif
     670      pwfile = fopen(OPW_TMPFILE, "w");
     671      umask(oldmask);
     672      if (pwfile == NULL) {
     673        err = 1;
     674        goto done;
     675      }
     676  
     677      opwfile = fopen(OLD_PASSWORDS_FILE, "r");
     678      if (opwfile == NULL) {
     679  	fclose(pwfile);
     680        err = 1;
     681        goto done;
     682      }
     683  
     684      if (fstat(fileno(opwfile), &st) == -1) {
     685  	fclose(opwfile);
     686  	fclose(pwfile);
     687  	err = 1;
     688  	goto done;
     689      }
     690  
     691      if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
     692  	fclose(opwfile);
     693  	fclose(pwfile);
     694  	err = 1;
     695  	goto done;
     696      }
     697      if (fchmod(fileno(pwfile), st.st_mode) == -1) {
     698  	fclose(opwfile);
     699  	fclose(pwfile);
     700  	err = 1;
     701  	goto done;
     702      }
     703  
     704      while (fgets(buf, 16380, opwfile)) {
     705  	if (!strncmp(buf, forwho, len) && strchr(":,\n", buf[len]) != NULL) {
     706  	    char *sptr = NULL;
     707  	    found = 1;
     708  	    if (howmany == 0)
     709  		continue;
     710  	    buf[strlen(buf) - 1] = '\0';
     711  	    s_luser = strtok_r(buf, ":", &sptr);
     712  	    if (s_luser == NULL) {
     713  		found = 0;
     714  		continue;
     715  	    }
     716  	    s_uid = strtok_r(NULL, ":", &sptr);
     717  	    if (s_uid == NULL) {
     718  		found = 0;
     719  		continue;
     720  	    }
     721  	    s_npas = strtok_r(NULL, ":", &sptr);
     722  	    if (s_npas == NULL) {
     723  		found = 0;
     724  		continue;
     725  	    }
     726  	    s_pas = strtok_r(NULL, ":", &sptr);
     727  	    npas = strtol(s_npas, NULL, 10) + 1;
     728  	    while (npas > howmany && s_pas != NULL) {
     729  		s_pas = strpbrk(s_pas, ",");
     730  		if (s_pas != NULL)
     731  		    s_pas++;
     732  		npas--;
     733  	    }
     734  	    pass = crypt_md5_wrapper(oldpass);
     735  	    if (s_pas == NULL)
     736  		snprintf(nbuf, sizeof(nbuf), "%s:%s:%d:%s\n",
     737  			 s_luser, s_uid, npas, pass);
     738  	    else
     739  		snprintf(nbuf, sizeof(nbuf),"%s:%s:%d:%s,%s\n",
     740  			 s_luser, s_uid, npas, s_pas, pass);
     741  	    _pam_delete(pass);
     742  	    if (fputs(nbuf, pwfile) < 0) {
     743  		err = 1;
     744  		break;
     745  	    }
     746  	} else if (fputs(buf, pwfile) < 0) {
     747  	    err = 1;
     748  	    break;
     749  	}
     750      }
     751      fclose(opwfile);
     752  
     753      if (!found) {
     754  	pwd = pam_modutil_getpwnam(pamh, forwho);
     755  	if (pwd == NULL) {
     756  	    err = 1;
     757  	} else {
     758  	    pass = crypt_md5_wrapper(oldpass);
     759  	    snprintf(nbuf, sizeof(nbuf), "%s:%lu:1:%s\n",
     760  		     forwho, (unsigned long)pwd->pw_uid, pass);
     761  	    _pam_delete(pass);
     762  	    if (fputs(nbuf, pwfile) < 0) {
     763  		err = 1;
     764  	    }
     765  	}
     766      }
     767  
     768      if (fflush(pwfile) || fsync(fileno(pwfile))) {
     769  	D(("fflush or fsync error writing entries to old passwords file: %m"));
     770  	err = 1;
     771      }
     772  
     773      if (fclose(pwfile)) {
     774  	D(("fclose error writing entries to old passwords file: %m"));
     775  	err = 1;
     776      }
     777  
     778  done:
     779      if (!err) {
     780  	if (rename(OPW_TMPFILE, OLD_PASSWORDS_FILE))
     781  	    err = 1;
     782      }
     783  #ifdef WITH_SELINUX
     784      if (SELINUX_ENABLED) {
     785        if (setfscreatecon_raw(prev_context_raw)) {
     786          err = 1;
     787        }
     788        if (prev_context_raw)
     789          freecon(prev_context_raw);
     790        prev_context_raw = NULL;
     791      }
     792  #endif
     793      if (!err) {
     794  	return PAM_SUCCESS;
     795      } else {
     796  	unlink(OPW_TMPFILE);
     797  	return PAM_AUTHTOK_ERR;
     798      }
     799  }
     800  
     801  PAMH_ARG_DECL(int unix_update_passwd,
     802  	const char *forwho, const char *towhat)
     803  {
     804      struct passwd *tmpent = NULL;
     805      struct stat st;
     806      FILE *pwfile, *opwfile;
     807      int err = 1;
     808      int oldmask;
     809  #ifdef WITH_SELINUX
     810      char *prev_context_raw = NULL;
     811  #endif
     812  
     813      oldmask = umask(077);
     814  #ifdef WITH_SELINUX
     815      if (SELINUX_ENABLED) {
     816        char *passwd_context_raw = NULL;
     817        if (getfilecon_raw("/etc/passwd",&passwd_context_raw)<0) {
     818  	return PAM_AUTHTOK_ERR;
     819        };
     820        if (getfscreatecon_raw(&prev_context_raw)<0) {
     821  	freecon(passwd_context_raw);
     822  	return PAM_AUTHTOK_ERR;
     823        }
     824        if (setfscreatecon_raw(passwd_context_raw)) {
     825  	freecon(passwd_context_raw);
     826  	freecon(prev_context_raw);
     827  	return PAM_AUTHTOK_ERR;
     828        }
     829        freecon(passwd_context_raw);
     830      }
     831  #endif
     832      pwfile = fopen(PW_TMPFILE, "w");
     833      umask(oldmask);
     834      if (pwfile == NULL) {
     835        err = 1;
     836        goto done;
     837      }
     838  
     839      opwfile = fopen("/etc/passwd", "r");
     840      if (opwfile == NULL) {
     841  	fclose(pwfile);
     842  	err = 1;
     843  	goto done;
     844      }
     845  
     846      if (fstat(fileno(opwfile), &st) == -1) {
     847  	fclose(opwfile);
     848  	fclose(pwfile);
     849  	err = 1;
     850  	goto done;
     851      }
     852  
     853      if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
     854  	fclose(opwfile);
     855  	fclose(pwfile);
     856  	err = 1;
     857  	goto done;
     858      }
     859      if (fchmod(fileno(pwfile), st.st_mode) == -1) {
     860  	fclose(opwfile);
     861  	fclose(pwfile);
     862  	err = 1;
     863  	goto done;
     864      }
     865  
     866      tmpent = fgetpwent(opwfile);
     867      while (tmpent) {
     868  	if (!strcmp(tmpent->pw_name, forwho)) {
     869  	    /* To shut gcc up */
     870  	    union {
     871  		const char *const_charp;
     872  		char *charp;
     873  	    } assigned_passwd;
     874  	    assigned_passwd.const_charp = towhat;
     875  
     876  	    tmpent->pw_passwd = assigned_passwd.charp;
     877  	    err = 0;
     878  	}
     879  	if (putpwent(tmpent, pwfile)) {
     880  	    D(("error writing entry to password file: %m"));
     881  	    err = 1;
     882  	    break;
     883  	}
     884  	tmpent = fgetpwent(opwfile);
     885      }
     886      fclose(opwfile);
     887  
     888      if (fflush(pwfile) || fsync(fileno(pwfile))) {
     889  	D(("fflush or fsync error writing entries to password file: %m"));
     890  	err = 1;
     891      }
     892  
     893      if (fclose(pwfile)) {
     894  	D(("fclose error writing entries to password file: %m"));
     895  	err = 1;
     896      }
     897  
     898  done:
     899      if (!err) {
     900  	if (!rename(PW_TMPFILE, "/etc/passwd"))
     901  	    pam_syslog(pamh,
     902  		LOG_NOTICE, "password changed for %s", forwho);
     903  	else
     904  	    err = 1;
     905      }
     906  #ifdef WITH_SELINUX
     907      if (SELINUX_ENABLED) {
     908        if (setfscreatecon_raw(prev_context_raw)) {
     909  	err = 1;
     910        }
     911        if (prev_context_raw)
     912  	freecon(prev_context_raw);
     913        prev_context_raw = NULL;
     914      }
     915  #endif
     916      if (!err) {
     917  	return PAM_SUCCESS;
     918      } else {
     919  	unlink(PW_TMPFILE);
     920  	return PAM_AUTHTOK_ERR;
     921      }
     922  }
     923  
     924  PAMH_ARG_DECL(int unix_update_shadow,
     925  	const char *forwho, char *towhat)
     926  {
     927      struct spwd spwdent, *stmpent = NULL;
     928      struct stat st;
     929      FILE *pwfile, *opwfile;
     930      int err = 0;
     931      int oldmask;
     932      int wroteentry = 0;
     933  #ifdef WITH_SELINUX
     934      char *prev_context_raw = NULL;
     935  #endif
     936  
     937      oldmask = umask(077);
     938  
     939  #ifdef WITH_SELINUX
     940      if (SELINUX_ENABLED) {
     941        char *shadow_context_raw = NULL;
     942        if (getfilecon_raw("/etc/shadow",&shadow_context_raw)<0) {
     943  	return PAM_AUTHTOK_ERR;
     944        };
     945        if (getfscreatecon_raw(&prev_context_raw)<0) {
     946  	freecon(shadow_context_raw);
     947  	return PAM_AUTHTOK_ERR;
     948        }
     949        if (setfscreatecon_raw(shadow_context_raw)) {
     950  	freecon(shadow_context_raw);
     951  	freecon(prev_context_raw);
     952  	return PAM_AUTHTOK_ERR;
     953        }
     954        freecon(shadow_context_raw);
     955      }
     956  #endif
     957      pwfile = fopen(SH_TMPFILE, "w");
     958      umask(oldmask);
     959      if (pwfile == NULL) {
     960  	err = 1;
     961  	goto done;
     962      }
     963  
     964      opwfile = fopen("/etc/shadow", "r");
     965      if (opwfile == NULL) {
     966  	fclose(pwfile);
     967  	err = 1;
     968  	goto done;
     969      }
     970  
     971      if (fstat(fileno(opwfile), &st) == -1) {
     972  	fclose(opwfile);
     973  	fclose(pwfile);
     974  	err = 1;
     975  	goto done;
     976      }
     977  
     978      if (fchown(fileno(pwfile), st.st_uid, st.st_gid) == -1) {
     979  	fclose(opwfile);
     980  	fclose(pwfile);
     981  	err = 1;
     982  	goto done;
     983      }
     984      if (fchmod(fileno(pwfile), st.st_mode) == -1) {
     985  	fclose(opwfile);
     986  	fclose(pwfile);
     987  	err = 1;
     988  	goto done;
     989      }
     990  
     991      stmpent = fgetspent(opwfile);
     992      while (stmpent) {
     993  
     994  	if (!strcmp(stmpent->sp_namp, forwho)) {
     995  	    stmpent->sp_pwdp = towhat;
     996  	    stmpent->sp_lstchg = time(NULL) / (60 * 60 * 24);
     997  	    if (stmpent->sp_lstchg == 0)
     998  	        stmpent->sp_lstchg = -1; /* Don't request passwort change
     999  					    only because time isn't set yet. */
    1000  	    wroteentry = 1;
    1001  	    D(("Set password %s for %s", stmpent->sp_pwdp, forwho));
    1002  	}
    1003  
    1004  	if (putspent(stmpent, pwfile)) {
    1005  	    D(("error writing entry to shadow file: %m"));
    1006  	    err = 1;
    1007  	    break;
    1008  	}
    1009  
    1010  	stmpent = fgetspent(opwfile);
    1011      }
    1012  
    1013      fclose(opwfile);
    1014  
    1015      if (!wroteentry && !err) {
    1016  	DIAG_PUSH_IGNORE_CAST_QUAL;
    1017  	spwdent.sp_namp = (char *)forwho;
    1018  	DIAG_POP_IGNORE_CAST_QUAL;
    1019  	spwdent.sp_pwdp = towhat;
    1020  	spwdent.sp_lstchg = time(NULL) / (60 * 60 * 24);
    1021  	if (spwdent.sp_lstchg == 0)
    1022  	    spwdent.sp_lstchg = -1; /* Don't request passwort change
    1023  				       only because time isn't set yet. */
    1024  	spwdent.sp_min = spwdent.sp_max = spwdent.sp_warn = spwdent.sp_inact =
    1025  	    spwdent.sp_expire = -1;
    1026  	spwdent.sp_flag = (unsigned long)-1l;
    1027  	if (putspent(&spwdent, pwfile)) {
    1028  	    D(("error writing entry to shadow file: %m"));
    1029  	    err = 1;
    1030  	}
    1031      }
    1032  
    1033      if (fflush(pwfile) || fsync(fileno(pwfile))) {
    1034  	D(("fflush or fsync error writing entries to shadow file: %m"));
    1035  	err = 1;
    1036      }
    1037  
    1038      if (fclose(pwfile)) {
    1039  	D(("fclose error writing entries to shadow file: %m"));
    1040  	err = 1;
    1041      }
    1042  
    1043   done:
    1044      if (!err) {
    1045  	if (!rename(SH_TMPFILE, "/etc/shadow"))
    1046  	    pam_syslog(pamh,
    1047  		LOG_NOTICE, "password changed for %s", forwho);
    1048  	else
    1049  	    err = 1;
    1050      }
    1051  
    1052  #ifdef WITH_SELINUX
    1053      if (SELINUX_ENABLED) {
    1054        if (setfscreatecon_raw(prev_context_raw)) {
    1055  	err = 1;
    1056        }
    1057        if (prev_context_raw)
    1058  	freecon(prev_context_raw);
    1059        prev_context_raw = NULL;
    1060      }
    1061  #endif
    1062  
    1063      if (!err) {
    1064  	return PAM_SUCCESS;
    1065      } else {
    1066  	unlink(SH_TMPFILE);
    1067  	return PAM_AUTHTOK_ERR;
    1068      }
    1069  }
    1070  
    1071  #ifdef HELPER_COMPILE
    1072  
    1073  int
    1074  helper_verify_password(const char *name, const char *p, int nullok)
    1075  {
    1076  	struct passwd *pwd = NULL;
    1077  	char *hash = NULL;
    1078  	int retval;
    1079  
    1080  	retval = get_pwd_hash(name, &pwd, &hash);
    1081  
    1082  	if (pwd == NULL || hash == NULL) {
    1083  		helper_log_err(LOG_NOTICE, "check pass; user unknown");
    1084  		retval = PAM_USER_UNKNOWN;
    1085  	} else if (p[0] == '\0' && nullok) {
    1086  		if (hash[0] == '\0') {
    1087  			retval = PAM_SUCCESS;
    1088  		} else {
    1089  			retval = PAM_AUTH_ERR;
    1090  		}
    1091  	} else {
    1092  		retval = verify_pwd_hash(p, hash, nullok);
    1093  	}
    1094  
    1095  	if (hash) {
    1096  		pam_overwrite_string(hash);
    1097  		_pam_drop(hash);
    1098  	}
    1099  
    1100  	p = NULL;		/* no longer needed here */
    1101  
    1102  	return retval;
    1103  }
    1104  
    1105  void
    1106  PAM_FORMAT((printf, 2, 3))
    1107  helper_log_err(int err, const char *format, ...)
    1108  {
    1109  	va_list args;
    1110  
    1111  	va_start(args, format);
    1112  	openlog(HELPER_COMPILE, LOG_CONS | LOG_PID, LOG_AUTHPRIV);
    1113  	vsyslog(err, format, args);
    1114  	va_end(args);
    1115  	closelog();
    1116  }
    1117  
    1118  static void
    1119  su_sighandler(int sig)
    1120  {
    1121  #ifndef SA_RESETHAND
    1122          /* emulate the behaviour of the SA_RESETHAND flag */
    1123          if ( sig == SIGILL || sig == SIGTRAP || sig == SIGBUS || sig = SIGSERV ) {
    1124  		struct sigaction sa;
    1125  		memset(&sa, '\0', sizeof(sa));
    1126  		sa.sa_handler = SIG_DFL;
    1127                  sigaction(sig, &sa, NULL);
    1128  	}
    1129  #endif
    1130          if (sig > 0) {
    1131                  _exit(sig);
    1132          }
    1133  }
    1134  
    1135  void
    1136  setup_signals(void)
    1137  {
    1138          struct sigaction action;        /* posix signal structure */
    1139  
    1140          /*
    1141           * Setup signal handlers
    1142           */
    1143          (void) memset((void *) &action, 0, sizeof(action));
    1144          action.sa_handler = su_sighandler;
    1145  #ifdef SA_RESETHAND
    1146          action.sa_flags = SA_RESETHAND;
    1147  #endif
    1148          (void) sigaction(SIGILL, &action, NULL);
    1149          (void) sigaction(SIGTRAP, &action, NULL);
    1150          (void) sigaction(SIGBUS, &action, NULL);
    1151          (void) sigaction(SIGSEGV, &action, NULL);
    1152          action.sa_handler = SIG_IGN;
    1153          action.sa_flags = 0;
    1154          (void) sigaction(SIGTERM, &action, NULL);
    1155          (void) sigaction(SIGHUP, &action, NULL);
    1156          (void) sigaction(SIGINT, &action, NULL);
    1157          (void) sigaction(SIGQUIT, &action, NULL);
    1158  }
    1159  
    1160  char *
    1161  getuidname(uid_t uid)
    1162  {
    1163          struct passwd *pw;
    1164          static char username[256];
    1165  
    1166          pw = getpwuid(uid);
    1167          if (pw == NULL)
    1168                  return NULL;
    1169  
    1170          strncpy(username, pw->pw_name, sizeof(username));
    1171          username[sizeof(username) - 1] = '\0';
    1172  
    1173          return username;
    1174  }
    1175  
    1176  #endif
    1177  /* ****************************************************************** *
    1178   * Copyright (c) Jan Rękorajski 1999.
    1179   * Copyright (c) Andrew G. Morgan 1996-8.
    1180   * Copyright (c) Alex O. Yuriev, 1996.
    1181   * Copyright (c) Cristian Gafton 1996.
    1182   * Copyright (c) Red Hat, Inc. 1996, 2007, 2008.
    1183   *
    1184   * Redistribution and use in source and binary forms, with or without
    1185   * modification, are permitted provided that the following conditions
    1186   * are met:
    1187   * 1. Redistributions of source code must retain the above copyright
    1188   *    notice, and the entire permission notice in its entirety,
    1189   *    including the disclaimer of warranties.
    1190   * 2. Redistributions in binary form must reproduce the above copyright
    1191   *    notice, this list of conditions and the following disclaimer in the
    1192   *    documentation and/or other materials provided with the distribution.
    1193   * 3. The name of the author may not be used to endorse or promote
    1194   *    products derived from this software without specific prior
    1195   *    written permission.
    1196   *
    1197   * ALTERNATIVELY, this product may be distributed under the terms of
    1198   * the GNU Public License, in which case the provisions of the GPL are
    1199   * required INSTEAD OF the above restrictions.  (This clause is
    1200   * necessary due to a potential bad interaction between the GPL and
    1201   * the restrictions contained in a BSD-style copyright.)
    1202   *
    1203   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
    1204   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    1205   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    1206   * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
    1207   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    1208   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    1209   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    1210   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    1211   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    1212   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
    1213   * OF THE POSSIBILITY OF SUCH DAMAGE.
    1214   */