Having a bit of a problem trying to post to the list.  This is
the second try:

Hello all,

I was recently setting up my CVS server to add pserver access to it,
and when going through the documentation, it indicated that to set
up the cvs passwd file, you had to copy/paste the crypt'd password
into it.  It lamented the fact that there was no cvspasswd utility
and hoped that it might exist some day.

Assuming that the documentation is right and the utility does not
exist, I have taken the liberty of creating a small cvspasswd 
utility to cover this task.  It works much like the standard unix
system passwd utility.

I would like to donate this utility to the CVS community and will
agree to release it under whatever license is appropriate for this
group.

It is written in straight C and compiles with:

        gcc -Wall -o cvspasswd cvspasswd -lcrypt

Let me know if you have questions or comments.

Steven

-------------- Begin Code: cvspasswd.c
/* ********************************************************** */
/* This is the cvs passwd utility.  It functions in much the  */
/* same way that the normal unix passwd utility works.  The   */
/* cvs password file is expected to be:                       */
/*             $CVSROOT/CVSROOT/passwd                        */
/* If the effective user id of the caller is = 0 (i.e. root)  */
/* then the user is allowed to change any password without    */
/* checking the password first.  If the user is anyone else,  */
/* they must first know the password of the user that they are*/
/* trying to change, and then they will be allowed to change  */
/* the password.                                              */
/* Called with no arguments, the utility will assume that the */
/* current user is trying to change his/her own password.     */
/* Called with one argument, the argument is assumed to be the*/
/* name of the user whose password is to be changed.          */
/*                                                            */
/* Author: Steven M. Cherry                                   */
/* Revisions:                                                 */
/* 07/05/2000: SMC: Initial creation.                         */
/*                                                            */
/* ********************************************************** */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <pwd.h>
#include <unistd.h>
#include <sys/types.h>

#include <time.h>

#define SUCCESS 1
#define FAILURE 0

FILE  *glob_passwd_file;
char  **glob_passwd_contents;
int   glob_passwd_size;
char  *glob_username;
uid_t glob_userid;
char  *glob_cur_password;
char  glob_new_password[128];
int   glob_new_user_flag;
int   glob_line_count;

int find_and_open_passwd(void);
int who_am_i(void);
int check_args(int argc, char **argv);
int scan_to_user(void);
int do_password_check(void);
int get_new_password(void);
int update_passwd(void);
void free_mem(void);

int main (int argc, char **argv)
{
        /* ************************************************** */
        /* Check to find the passwd file:                     */
        /* ************************************************** */
        if(find_and_open_passwd() == FAILURE){
                printf("Error opening password file!\n");
                exit(1);
        }

        /* ************************************************** */
        /* Check to see who we are.                           */
        /* ************************************************** */
        if(who_am_i() == FAILURE){
                fclose(glob_passwd_file);
                printf("Unable to determine identity!\n");
                exit(2);
        }

        /* ************************************************** */
        /* Check our arguments.                               */
        /* ************************************************** */
        if(check_args(argc, argv) == FAILURE){
                fclose(glob_passwd_file);
                printf("Argument error.\n");
                exit(3);
        }


        /* ************************************************** */
        /* Find the correct user in the file.                 */
        /* Only the root user is allowed to add new people to */
        /* the passwd file.                                   */
        /* ************************************************** */
        if(scan_to_user() == FAILURE){
                fclose(glob_passwd_file);
                free_mem();
                printf("Error finding user in file.\n");
                exit(4);
        }

        /* ************************************************** */
        /* Perform password check first if necessary.         */
        /* ************************************************** */
        if(do_password_check() == FAILURE){
                fclose(glob_passwd_file);
                free_mem();
                printf("Invalid password.\n");  
                exit(5);
        }
        
        /* ************************************************** */
        /* Request new password, twice to confirm validity.   */
        /* Encrypt the password for storage in the file.      */
        /* ************************************************** */
        if(get_new_password() == FAILURE){
                fclose(glob_passwd_file);
                free_mem();
                printf("Passwords do not match!\n");
                exit(6);
        }

        /* ************************************************** */
        /* Store the (new) password in the file.              */
        /* ************************************************** */
        if(update_passwd() == FAILURE){
                fclose(glob_passwd_file);
                free_mem();
                printf("Error updating password file!\n");
                exit(7);
        }

        fclose(glob_passwd_file);

        free_mem();

        return 0;
}

/* ********************************************************** */
/* This function will use the env var $CVSROOT to find and    */
/* open the password file.  It should be $CVSROOT/CVSROOT/passwd */
/* ********************************************************** */
int find_and_open_passwd(void)
{
        char passwd_file[512];

        memset(passwd_file, 0, 512);

        if(getenv("CVSROOT") == NULL){
                printf("Envvar CVSROOT is not set.\n");
                return FAILURE;
        }
        
        sprintf(passwd_file, "%s/CVSROOT/passwd", getenv("CVSROOT"));

        if((glob_passwd_file = fopen(passwd_file, "r+")) == NULL){
                printf("Error opening file: %s\n", passwd_file);
                return FAILURE;
        }

        return SUCCESS;
}

/* ********************************************************** */
/* This function will determine the current user effective id */
/* and from that determine the user name.  The user name can  */
/* be overridden with arguments to this utility, but this is  */
/* where the default comes from.                              */
/* ********************************************************** */
int who_am_i(void)
{
        struct passwd *curr_user;       
        int len;

        /* ID is easy: */
        glob_userid = getuid();

        /* Now figure out the name: */
        curr_user = getpwuid(glob_userid);
        if(curr_user == NULL){
                printf("Could not locate the user info for uid: %d\n",
                        glob_userid);
                return FAILURE;
        }

        len = strlen(curr_user->pw_passwd) + 1;
        glob_username = (char *)malloc(len);
        memset(glob_username, 0, len);
        strncpy(glob_username, curr_user->pw_passwd, len - 1 );

        return SUCCESS;

}

/* ************************************************************ */
/* This function is mainly a sainity check on the arguments     */
/* provided.  We only accept one argument, and if given it is   */
/* the target user in the passwd file.                          */
/* ************************************************************ */
int check_args(int argc, char **argv)
{
        int len;

        if(argc > 2){
                printf("Usage:\n\t%s \n--or--\n\t%s username\n",
                        argv[0], argv[0]);
                return FAILURE;
        }

        if(argc > 1) {
                /* ******************************************* */
                /* We allow anyone to specify the target name  */
                /* in the password file because usually these  */
                /* are not real users on the system.  If we    */
                /* only allowed root to specify the target name*/
                /* to find in the file, then only root would   */
                /* be able to maintain the cvs passwd file.    */
                /* This way a cvs maintainer does not have to  */
                /* be root to handle this.                     */
                /* ******************************************* */
                free(glob_username);
                len = strlen(argv[1]) + 1;
                glob_username = (char *)malloc(len);
                memset(glob_username, 0, len);
                strncpy(glob_username, argv[1], len - 1 );
        }

        return SUCCESS;

}

/* *********************************************************** */
/* This will scan the whole password file into a character     */
/* array that we will manipulate and then write back out to    */
/* the password file.  As the file is scanned in, we will look */
/* for the line for the current user.  If that user doesn't    */
/* exist and the caller is root then will will add it to the   */
/* end of the file.                                            */
/* *********************************************************** */
int scan_to_user(void)
{
        char buffer[512];
        char *ptr1, *ptr2;
        int i;


        glob_new_user_flag = 0;

        /* *************************************************** */
        /* Count how many lines are in the file for array size */
        /* purposes.                                           */
        /* *************************************************** */
        glob_passwd_size = 0;
        while(!feof(glob_passwd_file)){
                memset(buffer, 0, 512);
                fgets(buffer, 511, glob_passwd_file);
                glob_passwd_size ++;
        }
                
        /* *************************************************** */
        /* Allocate memory for the file:                       */
        /* *************************************************** */
        glob_passwd_contents = (char **)malloc(glob_passwd_size * sizeof(char *));
        for(i=0;i<glob_passwd_size;i++){
                glob_passwd_contents[i] = (char *)malloc(512);
        }       

        /* *************************************************** */
        /* Rewind the file and re-read into the array.         */
        /* *************************************************** */
        fseek(glob_passwd_file, 0L, SEEK_SET);

        glob_line_count = -1;
        i = 0;
        while(!feof(glob_passwd_file)){
                memset(glob_passwd_contents[i], 0, 512);
                fgets(glob_passwd_contents[i], 511, glob_passwd_file);
                if(strncmp(glob_passwd_contents[i], glob_username, 
                        strlen(glob_username))==0)
                {
                        if(glob_passwd_contents[i][strlen(glob_username)] 
                                == ':')
                        {
                                /* Grab the password entry out of the file */
                                ptr1 = strchr(glob_passwd_contents[i], ':');
                                ptr1++;
                                ptr2 = strchr(ptr1, ':');
                                if(ptr2 == NULL){
                                        ptr2 = strchr(ptr1, '\n');
                                        if(ptr2 == NULL){
                                                ptr2 = strchr(ptr1, '\0');
                                        }
                                }
                                glob_cur_password = (char *)malloc(
                                        ptr2-ptr1+1);
                                memset(glob_cur_password, 0, ptr2-ptr1+1);
                                strncpy(glob_cur_password, ptr1, ptr2-ptr1);
                                
                                glob_line_count = i;
                        }
                }

                i ++;
        }
        /* ************************************************** */
        /* When we get to here, check to see what the value   */
        /* of glob_line_count is.  If it is -1 then we have   */
        /* not found the user and must be adding a new user.  */
        /* Make sure we are root, and set the appropriate     */
        /* flags.  Otherwise we are just updating an existing */
        /* user with new info.                                */
        /* ************************************************** */
        if(glob_line_count == -1){
                /* Did not find the user. */
                if(glob_userid != 0){
                        printf("Only root may add new users.\n");
                        return FAILURE;
                } else {
                        glob_new_user_flag = 1;
                        return SUCCESS;
                }
        }
        return SUCCESS;
}

/* *********************************************************** */
/* This function will force the user to enter the current pass */
/* if they are not root.  If the pass check fails we will exit */
/* If the pass check succeeds we will allow the change.        */
/* *********************************************************** */
int do_password_check(void)
{
        char *typed_ptr;
        char msg[128];

        if(glob_userid != 0){
                memset(msg, 0, 128);
                sprintf(msg, "Please enter the current password for %s >>",
                        glob_username);
                typed_ptr = getpass(msg);
                
                if(strcmp(
                        (const char *) crypt(typed_ptr, glob_cur_password), 
                        glob_cur_password
                        ) != 0)
                {
                        printf("Invalid password!\n");
                        return FAILURE;
                }
        }
        return SUCCESS;

}

/* *********************************************************** */
/* This function will actually ask the user for the new pass   */
/* twice to make sure that they typed it correctly.            */
/* *********************************************************** */
int get_new_password(void)
{
        char *typed_ptr;
        char typed_passwd1[128];
        char typed_passwd2[128];
        char salt_choices[] = 
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
        char salt[3];

        
        typed_ptr = getpass("Enter the new password >>");
        memset(typed_passwd1, 0, 128);
        strcpy(typed_passwd1, typed_ptr);

        typed_ptr = getpass("Again >>");
        memset(typed_passwd2, 0, 128);
        strcpy(typed_passwd2, typed_ptr);

        if(strcmp(typed_passwd1, typed_passwd2) != 0){
                printf("Passwords don't match!\n");     
                return FAILURE;
        }

        memset( glob_new_password, 0, 128);
        memset( salt, 0, 3);
        srand(time(NULL));
        salt[0] = salt_choices[(int)(64.0*rand()/(RAND_MAX+1.0))];      
        salt[1] = salt_choices[(int)(64.0*rand()/(RAND_MAX+1.0))];      
        strcpy(glob_new_password, (const char *)crypt(typed_passwd2, salt));

        return SUCCESS;

}
int update_passwd(void)
{
        char *ptr1, *ptr2, *ptr3;
        char tmp[128];
        int i;


        if(glob_new_user_flag != 1){
                ptr3 = glob_passwd_contents[glob_line_count];
                ptr1 = strchr(ptr3, ':');
                ptr1++;
                ptr2 = strchr(ptr1, ':');
                if(ptr2 == NULL){
                        ptr2 = strchr(ptr1, '\n');
                        if(ptr2 == NULL){
                                ptr2 = strchr(ptr1, '\0');
                        }
                }
                memset(tmp, 0, 128);
                strcpy(tmp, ptr2);
                memset(ptr3, 0, 512);
                sprintf(ptr3, "%s:%s%s", glob_username, glob_new_password,
                        tmp);

                /* ******************************************** */
                /* Rewind the file back to the beginning and    */
                /* print the new data to the file.              */      
                /* ******************************************** */
                fseek(glob_passwd_file, 0L, SEEK_SET);

                for(i=0;i<glob_passwd_size;i++)
                        fprintf(glob_passwd_file, "%s", glob_passwd_contents[i]);
                
        }  else {
                /* ******************************************** */
                /* Rewind the file and print all of the old     */
                /* stuff to it.  Then add the new line at the   */
                /* end.                                         */
                /* ******************************************** */


                fseek(glob_passwd_file, 0L, SEEK_SET);

                for(i=0;i<glob_passwd_size;i++)
                        fprintf(glob_passwd_file, "%s", glob_passwd_contents[i]);

                fprintf(glob_passwd_file, "%s:%s\n", glob_username,
                        glob_new_password);
        }

        return SUCCESS;

}

/* ************************************************************ */
/* This method does the necessary memory cleanups and stuff to  */
/* do prior to exiting.                                         */
/* ************************************************************ */

void free_mem(void)
{
        int i;

        for(i=0;i<glob_passwd_size;i++)
                free(glob_passwd_contents[i]);

        free(glob_passwd_contents);

        free(glob_username);
        free(glob_cur_password);

}

----------------------End Code.

-- 
==================================================================
== Steven M. Cherry                       [EMAIL PROTECTED]  ==
==                       http://216.59.115.58/steven/home.html  ==
==================================================================


----- End forwarded message -----

-- 
==================================================================
== Steven M. Cherry                       [EMAIL PROTECTED]  ==
==                       http://216.59.115.58/steven/home.html  ==
==================================================================

Reply via email to