(root)/
Linux-PAM-1.5.3/
modules/
pam_unix/
unix_chkpwd.c
       1  /*
       2   * This program is designed to run setuid(root) or with sufficient
       3   * privilege to read all of the unix password databases. It is designed
       4   * to provide a mechanism for the current user (defined by this
       5   * process's uid) to verify their own password.
       6   *
       7   * The password is read from the standard input. The exit status of
       8   * this program indicates whether the user is authenticated or not.
       9   *
      10   * Copyright information is located at the end of the file.
      11   *
      12   */
      13  
      14  #include "config.h"
      15  
      16  #include <stdio.h>
      17  #include <stdlib.h>
      18  #include <string.h>
      19  #include <syslog.h>
      20  #include <unistd.h>
      21  #include <sys/types.h>
      22  #include <sys/stat.h>
      23  #include <pwd.h>
      24  #include <shadow.h>
      25  #include <signal.h>
      26  #include <time.h>
      27  #include <errno.h>
      28  #ifdef HAVE_LIBAUDIT
      29  #include <libaudit.h>
      30  #endif
      31  
      32  #include <security/_pam_types.h>
      33  #include <security/_pam_macros.h>
      34  
      35  #include "passverify.h"
      36  #include "pam_inline.h"
      37  
      38  static int _check_expiry(const char *uname)
      39  {
      40  	struct spwd *spent;
      41  	struct passwd *pwent;
      42  	int retval;
      43  	int daysleft;
      44  
      45  	retval = get_account_info(uname, &pwent, &spent);
      46  	if (retval != PAM_SUCCESS) {
      47  		helper_log_err(LOG_ERR, "could not obtain user info (%s)", uname);
      48  		printf("-1\n");
      49  		return retval;
      50  	}
      51  
      52  	if (spent == NULL) {
      53  		printf("-1\n");
      54  		return retval;
      55  	}
      56  
      57  	retval = check_shadow_expiry(spent, &daysleft);
      58  	printf("%d\n", daysleft);
      59  	return retval;
      60  }
      61  
      62  #ifdef HAVE_LIBAUDIT
      63  static int _audit_log(int type, const char *uname, int rc)
      64  {
      65  	int audit_fd;
      66  
      67  	audit_fd = audit_open();
      68  	if (audit_fd < 0) {
      69  		/* You get these error codes only when the kernel doesn't have
      70  		 * audit compiled in. */
      71  		if (errno == EINVAL || errno == EPROTONOSUPPORT ||
      72  			errno == EAFNOSUPPORT)
      73  			return PAM_SUCCESS;
      74  
      75  		helper_log_err(LOG_CRIT, "audit_open() failed: %m");
      76  		return PAM_AUTH_ERR;
      77  	}
      78  
      79  	rc = audit_log_acct_message(audit_fd, type, NULL, "PAM:unix_chkpwd",
      80  		uname, -1, NULL, NULL, NULL, rc == PAM_SUCCESS);
      81  	if (rc == -EPERM && geteuid() != 0) {
      82  		rc = 0;
      83  	}
      84  
      85  	audit_close(audit_fd);
      86  
      87  	return rc < 0 ? PAM_AUTH_ERR : PAM_SUCCESS;
      88  }
      89  #endif
      90  
      91  int main(int argc, char *argv[])
      92  {
      93  	char pass[PAM_MAX_RESP_SIZE + 1];
      94  	char *option;
      95  	int npass, nullok;
      96  	int blankpass = 0;
      97  	int retval = PAM_AUTH_ERR;
      98  	char *user;
      99  	char *passwords[] = { pass };
     100  
     101  	/*
     102  	 * Catch or ignore as many signal as possible.
     103  	 */
     104  	setup_signals();
     105  
     106  	/*
     107  	 * we establish that this program is running with non-tty stdin.
     108  	 * this is to discourage casual use. It does *NOT* prevent an
     109  	 * intruder from repeatadly running this program to determine the
     110  	 * password of the current user (brute force attack, but one for
     111  	 * which the attacker must already have gained access to the user's
     112  	 * account).
     113  	 */
     114  
     115  	if (isatty(STDIN_FILENO) || argc != 3 ) {
     116  		helper_log_err(LOG_NOTICE
     117  		      ,"inappropriate use of Unix helper binary [UID=%d]"
     118  			 ,getuid());
     119  #ifdef HAVE_LIBAUDIT
     120  		_audit_log(AUDIT_ANOM_EXEC, getuidname(getuid()), PAM_SYSTEM_ERR);
     121  #endif
     122  		fprintf(stderr
     123  		 ,"This binary is not designed for running in this way\n"
     124  		      "-- the system administrator has been informed\n");
     125  		sleep(10);	/* this should discourage/annoy the user */
     126  		return PAM_SYSTEM_ERR;
     127  	}
     128  
     129  	/*
     130  	 * Determine what the current user's name is.
     131  	 * We must thus skip the check if the real uid is 0.
     132  	 */
     133  	if (getuid() == 0) {
     134  	  user=argv[1];
     135  	}
     136  	else {
     137  	  user = getuidname(getuid());
     138  	  /* if the caller specifies the username, verify that user
     139  	     matches it */
     140  	  if (user == NULL || strcmp(user, argv[1])) {
     141  	    user = argv[1];
     142  	    /* no match -> permanently change to the real user and proceed */
     143  	    if (setuid(getuid()) != 0)
     144  		return PAM_AUTH_ERR;
     145  	  }
     146  	}
     147  
     148  	option=argv[2];
     149  
     150  	if (strcmp(option, "chkexpiry") == 0)
     151  	  /* Check account information from the shadow file */
     152  	  return _check_expiry(argv[1]);
     153  	/* read the nullok/nonull option */
     154  	else if (strcmp(option, "nullok") == 0)
     155  	  nullok = 1;
     156  	else if (strcmp(option, "nonull") == 0)
     157  	  nullok = 0;
     158  	else {
     159  #ifdef HAVE_LIBAUDIT
     160  	  _audit_log(AUDIT_ANOM_EXEC, getuidname(getuid()), PAM_SYSTEM_ERR);
     161  #endif
     162  	  return PAM_SYSTEM_ERR;
     163  	}
     164  	/* read the password from stdin (a pipe from the pam_unix module) */
     165  
     166  	npass = pam_read_passwords(STDIN_FILENO, 1, passwords);
     167  
     168  	if (npass != 1) {	/* is it a valid password? */
     169  		helper_log_err(LOG_DEBUG, "no password supplied");
     170  		*pass = '\0';
     171  	}
     172  
     173  	if (*pass == '\0') {
     174  		blankpass = 1;
     175  	}
     176  
     177  	retval = helper_verify_password(user, pass, nullok);
     178  
     179  	pam_overwrite_array(pass);	/* clear memory of the password */
     180  
     181  	/* return pass or fail */
     182  
     183  	if (retval != PAM_SUCCESS) {
     184  		if (!nullok || !blankpass) {
     185  			/* no need to log blank pass test */
     186  #ifdef HAVE_LIBAUDIT
     187  			if (getuid() != 0)
     188  				_audit_log(AUDIT_USER_AUTH, user, PAM_AUTH_ERR);
     189  #endif
     190  			helper_log_err(LOG_NOTICE, "password check failed for user (%s)", user);
     191  		}
     192  		/* if helper_verify_password() returned PAM_USER_UNKNOWN, the
     193  		   most appropriate error to propagate to
     194  		   _unix_verify_password() is PAM_AUTHINFO_UNAVAIL; otherwise
     195  		   return general failure */
     196  		if (retval == PAM_USER_UNKNOWN)
     197  			return PAM_AUTHINFO_UNAVAIL;
     198  		else
     199  			return PAM_AUTH_ERR;
     200  	} else {
     201  	        if (getuid() != 0) {
     202  #ifdef HAVE_LIBAUDIT
     203  			return _audit_log(AUDIT_USER_AUTH, user, PAM_SUCCESS);
     204  #else
     205  		        return PAM_SUCCESS;
     206  #endif
     207  	        }
     208  		return PAM_SUCCESS;
     209  	}
     210  }
     211  
     212  /*
     213   * Copyright (c) Andrew G. Morgan, 1996. All rights reserved
     214   * Copyright (c) Red Hat, Inc., 2007,2008. All rights reserved
     215   *
     216   * Redistribution and use in source and binary forms, with or without
     217   * modification, are permitted provided that the following conditions
     218   * are met:
     219   * 1. Redistributions of source code must retain the above copyright
     220   *    notice, and the entire permission notice in its entirety,
     221   *    including the disclaimer of warranties.
     222   * 2. Redistributions in binary form must reproduce the above copyright
     223   *    notice, this list of conditions and the following disclaimer in the
     224   *    documentation and/or other materials provided with the distribution.
     225   * 3. The name of the author may not be used to endorse or promote
     226   *    products derived from this software without specific prior
     227   *    written permission.
     228   *
     229   * ALTERNATIVELY, this product may be distributed under the terms of
     230   * the GNU Public License, in which case the provisions of the GPL are
     231   * required INSTEAD OF the above restrictions.  (This clause is
     232   * necessary due to a potential bad interaction between the GPL and
     233   * the restrictions contained in a BSD-style copyright.)
     234   *
     235   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
     236   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     237   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     238   * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     239   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     240   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     241   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     242   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     243   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     244   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     245   * OF THE POSSIBILITY OF SUCH DAMAGE.
     246   */