(root)/
Linux-PAM-1.5.3/
modules/
pam_unix/
unix_update.c
       1  /*
       2   * This program is designed to run with sufficient privilege
       3   * to read and write all of the unix password databases.
       4   * Its purpose is to allow updating the databases when
       5   * SELinux confinement of the caller domain prevents them to
       6   * do that themselves.
       7   *
       8   * The password is read from the standard input. The exit status of
       9   * this program indicates whether the password was updated or not.
      10   *
      11   * Copyright information is located at the end of the file.
      12   *
      13   */
      14  
      15  #include "config.h"
      16  
      17  #include <stdarg.h>
      18  #include <stdio.h>
      19  #include <stdlib.h>
      20  #include <string.h>
      21  #include <syslog.h>
      22  #include <unistd.h>
      23  #include <sys/types.h>
      24  #include <sys/stat.h>
      25  #include <pwd.h>
      26  #include <shadow.h>
      27  #include <signal.h>
      28  #include <time.h>
      29  #include <sys/time.h>
      30  
      31  #include <security/_pam_types.h>
      32  #include <security/_pam_macros.h>
      33  
      34  #include "passverify.h"
      35  #include "pam_inline.h"
      36  
      37  static int
      38  set_password(const char *forwho, const char *shadow, const char *remember)
      39  {
      40      struct passwd *pwd = NULL;
      41      int retval;
      42      char pass[PAM_MAX_RESP_SIZE + 1];
      43      char towhat[PAM_MAX_RESP_SIZE + 1];
      44      int npass = 0;
      45      /* we don't care about number format errors because the helper
      46         should be called internally only */
      47      int doshadow = atoi(shadow);
      48      int nremember = atoi(remember);
      49      char *passwords[] = { pass, towhat };
      50  
      51      /* read the password from stdin (a pipe from the pam_unix module) */
      52  
      53      npass = pam_read_passwords(STDIN_FILENO, 2, passwords);
      54  
      55      if (npass != 2) {	/* is it a valid password? */
      56        if (npass == 1) {
      57          helper_log_err(LOG_DEBUG, "no new password supplied");
      58          pam_overwrite_array(pass);
      59        } else {
      60          helper_log_err(LOG_DEBUG, "no valid passwords supplied");
      61        }
      62        return PAM_AUTHTOK_ERR;
      63      }
      64  
      65      if (lock_pwdf() != PAM_SUCCESS) {
      66  	pam_overwrite_array(pass);
      67  	pam_overwrite_array(towhat);
      68  	return PAM_AUTHTOK_LOCK_BUSY;
      69      }
      70  
      71      pwd = getpwnam(forwho);
      72  
      73      if (pwd == NULL) {
      74          retval = PAM_USER_UNKNOWN;
      75          goto done;
      76      }
      77  
      78      /* If real caller uid is not root we must verify that
      79         received old pass agrees with the current one.
      80         We always allow change from null pass. */
      81      if (getuid()) {
      82  	retval = helper_verify_password(forwho, pass, 1);
      83  	if (retval != PAM_SUCCESS) {
      84  	    goto done;
      85  	}
      86      }
      87  
      88      /* first, save old password */
      89      if (save_old_password(forwho, pass, nremember)) {
      90  	retval = PAM_AUTHTOK_ERR;
      91  	goto done;
      92      }
      93  
      94      if (doshadow || is_pwd_shadowed(pwd)) {
      95  	retval = unix_update_shadow(forwho, towhat);
      96  	if (retval == PAM_SUCCESS)
      97  	    if (!is_pwd_shadowed(pwd))
      98  		retval = unix_update_passwd(forwho, "x");
      99      } else {
     100  	retval = unix_update_passwd(forwho, towhat);
     101      }
     102  
     103  done:
     104      pam_overwrite_array(pass);
     105      pam_overwrite_array(towhat);
     106  
     107      unlock_pwdf();
     108  
     109      if (retval == PAM_SUCCESS) {
     110  	return PAM_SUCCESS;
     111      } else {
     112  	return PAM_AUTHTOK_ERR;
     113      }
     114  }
     115  
     116  int main(int argc, char *argv[])
     117  {
     118  	char *option;
     119  
     120  	/*
     121  	 * Catch or ignore as many signal as possible.
     122  	 */
     123  	setup_signals();
     124  
     125  	/*
     126  	 * we establish that this program is running with non-tty stdin.
     127  	 * this is to discourage casual use. It does *NOT* prevent an
     128  	 * intruder from repeatadly running this program to determine the
     129  	 * password of the current user (brute force attack, but one for
     130  	 * which the attacker must already have gained access to the user's
     131  	 * account).
     132  	 */
     133  
     134  	if (isatty(STDIN_FILENO) || argc != 5 ) {
     135  		helper_log_err(LOG_NOTICE
     136  		      ,"inappropriate use of Unix helper binary [UID=%d]"
     137  			 ,getuid());
     138  		fprintf(stderr
     139  		 ,"This binary is not designed for running in this way\n"
     140  		      "-- the system administrator has been informed\n");
     141  		sleep(10);	/* this should discourage/annoy the user */
     142  		return PAM_SYSTEM_ERR;
     143  	}
     144  
     145  	/* We must be root to read/update shadow.
     146  	 */
     147  	if (geteuid() != 0) {
     148  	    return PAM_CRED_INSUFFICIENT;
     149  	}
     150  
     151  	option = argv[2];
     152  
     153  	if (strcmp(option, "update") == 0) {
     154  	    /* Attempting to change the password */
     155  	    return set_password(argv[1], argv[3], argv[4]);
     156  	}
     157  
     158  	return PAM_SYSTEM_ERR;
     159  }
     160  
     161  /*
     162   * Copyright (c) Andrew G. Morgan, 1996. All rights reserved
     163   * Copyright (c) Red Hat, Inc., 2007, 2008. All rights reserved
     164   *
     165   * Redistribution and use in source and binary forms, with or without
     166   * modification, are permitted provided that the following conditions
     167   * are met:
     168   * 1. Redistributions of source code must retain the above copyright
     169   *    notice, and the entire permission notice in its entirety,
     170   *    including the disclaimer of warranties.
     171   * 2. Redistributions in binary form must reproduce the above copyright
     172   *    notice, this list of conditions and the following disclaimer in the
     173   *    documentation and/or other materials provided with the distribution.
     174   * 3. The name of the author may not be used to endorse or promote
     175   *    products derived from this software without specific prior
     176   *    written permission.
     177   *
     178   * ALTERNATIVELY, this product may be distributed under the terms of
     179   * the GNU Public License, in which case the provisions of the GPL are
     180   * required INSTEAD OF the above restrictions.  (This clause is
     181   * necessary due to a potential bad interaction between the GPL and
     182   * the restrictions contained in a BSD-style copyright.)
     183   *
     184   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
     185   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     186   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     187   * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
     188   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     189   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     190   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     191   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     192   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     193   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
     194   * OF THE POSSIBILITY OF SUCH DAMAGE.
     195   */