Changing Passwords Source File

Filename: cs_password.c
Project Name: Pluggable Authentication Module (PAM)
Language: C
Description:

Code:

/************************************************************
** Library functions to interact with the Linux-PAM        **
** modules in order to update a user's password on         **
** the system.                                             **
**                                                         **
** Make sure you add the following lines to the            **
** pam.conf file (ore equivalent):                         **
** cs_password auth     required                           **
**                          /lib/security/pam_unix_auth.so **
** cs_password account  required                           **
**                          /lib/security/pam_unix_acct.so **
** cs_password password required                           **
**                        /lib/security/pam_unix_passwd.so **
** cs_password session  required                           **
**                          /lib/security/pam_unix_acct.so **
**                                                         **
** Author:      Daryle Niedermayer (dpn)                   **
**              daryle@niedermayer.ca                      **
** Date:        2002-06-17                                 **
**                                                         **
** $Id: cs_password.c,v 1.2 2002/06/20 19:51:24 root Exp root $
** $Log: cs_password.c,v $
** Revision 1.2  2002/06/20 19:51:24  root
** Fully documented and debugged test of how to change a password.
**
** Revision 1.1  2002/06/19 16:26:19  root
** Initial revision
**:
************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include <crack.h>


#define CS_WEAK_PASSWORD 	-3
#define CS_BAD_DATA  		-2
#define CS_BAD_USAGE 		-1
#define CS_SUCCESS    		0

#define COPY_STRING(s) (s) ? strdup(s) : NULL

/* DEFINE STATIC EXTERNAL STRUCTURES AND VARIABLES SO THAT
   THEY ONLY HAVE SCOPE WITHIN THE METHODS AND FUNCTIONS OF
   THIS SOURCE FILE */
static char*        service_name = "cs_password";
static char*        user;
static char*        old_password;
static char*        new_password;
static int PAM_conv (int, const struct pam_message**, 
                     struct pam_response**, void*); 
static struct pam_conv PAM_converse = {PAM_conv, NULL};

/*************************************************
** PAM Conversation function                    **
*************************************************/

static int PAM_conv (int num_msg, const struct pam_message **msg,
                     struct pam_response **resp, void *appdata_ptr) {
   int replies = 0;
   struct pam_response *reply = NULL;

   reply = malloc(sizeof(struct pam_response) * num_msg);
   if (!reply) return PAM_CONV_ERR;

   for (replies = 0; replies < num_msg; replies++) {
      printf("***Message from PAM is: |%s|\n", msg[replies]->msg);
      printf("***Msg_style to PAM is: |%d|\n", msg[replies]->msg_style);
      if (! strcmp(msg[replies]->msg,"Password: ")) {
         printf("***Sending old password\n");
         reply[replies].resp = COPY_STRING(old_password);
      }
      if (! strcmp(msg[replies]->msg,"Enter new UNIX password: ")) {
         printf("***Sending new password\n");
         reply[replies].resp = COPY_STRING(new_password);
      }
      if (! strcmp(msg[replies]->msg,"Retype new UNIX password: ")) {
         printf("***Sending new password again\n");
         reply[replies].resp = COPY_STRING(new_password);
      }
      printf("***Response to PAM is: |%s|\n", reply[replies].resp);
   }
   *resp = reply;
   return PAM_SUCCESS;
}
   

/*************************************************
** MAIN PROCEDURE                               **
*************************************************/
int main(int argc, char *argv[]) {

/* DEFINITIONS */
   pam_handle_t*    pamh = NULL;
   int              retval;
   char*            pw_check;
   char*            dict_path = "/usr/lib/cracklib_dict";


/* DETERMINE IF VARIABLE COUNT IS CORRECT */
   if (argc != 4) {
      printf("Usage: pam_passwd <USER> <OLD_PASSWORD> <NEW_PASSWORD>\n");
      exit (CS_BAD_USAGE);
   }

/* PARSE PARAMETERS FROM INPUTS */
   user         = argv[1];         
   old_password = argv[2];
   new_password = argv[3];

   if (!(user && old_password && strlen(user) && strlen(old_password))) {
      printf("Incorrect/invalid username or old password");
      exit (CS_BAD_DATA);
   }

/* SEE IF THE NEW PASSWORD IS SUITABLY TOUGH */
/* This should be preprocessed outside of this function. */
   printf("Testing for weak passwords...\n");
   pw_check = FascistCheck(new_password, dict_path);
   if (pw_check != NULL) {
      printf("***Weak Password!: |%s|\n",pw_check);
      exit(CS_WEAK_PASSWORD);
   }
   
/* GET A HANDLE TO A PAM INSTANCE */
   printf("Trying to get a handle to the PAM service...\n");
   retval = pam_start(service_name, user, &PAM_converse, &pamh);

/* IS THE USER REALLY A USER? */
   if (retval == PAM_SUCCESS) {
      printf("...Service handle was created.\n");
      printf("Trying to see if the user is a valid system user...\n");
      retval = pam_authenticate(pamh, 0);
   }
   else {
      printf("...Call to create service handle failed with error: %d\n",retval);
   }

/* IS USER PERMITTED ACCESS? */
   if (retval == PAM_SUCCESS) {
      printf("...User %s is a real user.\n",user);
      printf("Trying to pass info to the pam_acct_mgmt function...\n");
      retval = pam_acct_mgmt(pamh, 0);
   }
   else {
      if (retval == PAM_USER_UNKNOWN) 
         printf("...Failed to find user %s with error: %d\n",user,retval);
      else printf("...Failed to authenticate for an unknown error: %d\n",retval);
   }

   if (retval == PAM_SUCCESS) {
      printf("...User %s is permitted access.\n",user);
   }
   else {
      printf("...cs_password error: User %s is not authenticated\n",user);
      printf("...Call returned with error: %d\n",retval);
   }

/* TRYING TO CHANGE THE PASSWORD AUTHENTICATION TOKEN */
   if (retval == PAM_SUCCESS) {
      printf("Trying to update the password token...\n");
      retval = pam_chauthtok(pamh, PAM_SILENT); 
   }

   if (retval == PAM_SUCCESS) {
      printf("...Successfully updated password!\n");
   }
   else {
      printf("...Failed to update password: error %d\n",retval);
      printf("...%s\n",pam_strerror(pamh, retval));
   }

/* CLEAN UP OUR HANDLES AND VARIABLES */
   if (pam_end(pamh, retval) != PAM_SUCCESS) {
      pamh = NULL;
      fprintf(stderr, "cs_password error: Failed to release authenticator\n");
   }
   
   exit (CS_SUCCESS);
}