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);
}