/* * Copyright (c) 1992, Brian Berliner and Jeff Polk * Copyright (c) 1989-1992, Brian Berliner * * You may distribute under the terms of the GNU General Public License as * specified in the README file that comes with the CVS 1.4 kit. * * passwd * * Changes the password of the caller * * Corey Minyard: Initial development * Tony Hoyle: 23/11/2001 Rewrite for cvsnt * */ #include "cvs.h" #include "getline.h" #if defined(_WIN32) && defined(SERVER_SUPPORT) /* We use this for sanity checking */ extern int isDomainMember(); #endif extern char *crypt (const char *, const char *); #define ascii_to_bin(c) ((c)>='a'?(c-59):(c)>='A'?((c)-53):(c)-'.') #define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.') static passwd_entry *passwd_list = NULL; static int passwd_list_size = 0; char *crypt_password(char *typed_password) { time_t tm; char salt[2]; if(typed_password) { time(&tm); salt[0] = bin_to_ascii(tm & 0x3f); salt[1] = bin_to_ascii((tm >> 5) & 0x3f); strcpy(typed_password,crypt(typed_password, salt)); } return typed_password; } void free_passwd_list() { if(passwd_list) { int u; for(u=0; udirectory) + strlen("/CVSROOT/passwd") + 1); strcpy (filename, current_parsed_root->directory); strcat (filename, "/CVSROOT/passwd"); init_passwd_list(); fp = CVS_FOPEN (filename, "r"); if (fp != NULL) { while (getline (&linebuf, &linebuf_len, fp) >= 0) { char *user; if(linebuf[strlen(linebuf)-1]=='\n') linebuf[strlen(linebuf)-1]='\0'; if(linebuf[0]=='#') continue; user = cvs_strtok(linebuf,":"); if(!user || !*user) continue; passnode = new_passwd_entry(); passnode->username=xstrdup(user); passnode->password=xstrdup(cvs_strtok(NULL,":")); passnode->real_username=xstrdup(cvs_strtok(NULL,":")); xfree (linebuf); linebuf = NULL; } if (ferror (fp)) { error (1, errno, "cannot read %s", filename); } if (fclose (fp) < 0) error (0, errno, "cannot close %s", filename); } return 0; } int write_passwd_list() { FILE *fp; char *filename; filename = (char*)xmalloc(strlen(current_parsed_root->directory) + strlen("/CVSROOT/passwd") + 1); strcpy (filename, current_parsed_root->directory); strcat (filename, "/CVSROOT/passwd"); fp = CVS_FOPEN (filename, "w"); if (fp == NULL) { error (0, errno, "cannot open %s for writing", filename); } else { int u; for(u=0; uisremote) { if (argc > 1) usage (passwd_usage); if (!supported_request ("passwd")) error (1, 0, "server does not support passwd"); if(!user && adduser) { error(1,0,"You cannot add yourself"); } if(!user && deluser) { error(1,0,"You cannot delete yourself"); } if(user || current_parsed_root->username || current_parsed_root->hostname) { printf ("%s %s@%s\n", (adduser) ? "Adding user" : (deluser) ? "Deleting user" : "Changing repository password for", user?user:current_parsed_root->username?current_parsed_root->username:getcaller(),current_parsed_root->hostname); } else { printf ("Changing repository password for %s\n",getcaller()); } fflush (stdout); if(!use_domain && !deluser && !disableuser) { CProtocolLibrary lib; if(!lib.PromptForPassword("New Password: ",typed_password,sizeof(typed_password))) error(1,0,"Aborted"); if(!lib.PromptForPassword("Verify Password: ",typed_password2,sizeof(typed_password2))) error(1,0,"Aborted"); if (strcmp(typed_password, typed_password2) != 0) { memset (typed_password, 0, strlen (typed_password)); memset (typed_password2, 0, strlen (typed_password2)); error (1, 0, "Passwords do not match, try again"); } memset (typed_password2, 0, strlen (typed_password2)); if(strlen(typed_password)) crypt_password(typed_password); } if (adduser) send_arg ("-a"); if (disableuser) send_arg ("-x"); if (deluser) send_arg ("-X"); if (realuser) { send_arg ("-r"); send_arg (real_user); } if (remove_realuser) send_arg ("-R"); if(use_domain) { send_arg ("-D"); send_arg (password_domain); } if (argc == 1) send_arg(user); else send_arg("*"); if(typed_password) { send_arg (typed_password); /* Send the new password */ memset (typed_password, 0, strlen (typed_password)); } send_to_server ("passwd\n", 0); return get_responses_and_close (); } if(!server_active) { if(argc!=0 && argc!=1) usage (passwd_usage); if(!user && adduser) { error(1,0,"You cannot add yourself"); } if(!user && deluser) { error(1,0,"You cannot delete yourself"); } if(user || current_parsed_root->username) { printf ("%s %s\n", (adduser) ? "Adding user" : (deluser) ? "Deleting user" : "Changing password for", user?user:current_parsed_root->username); } else { printf ("Changing repository password for %s\n",getcaller()); } fflush (stdout); if (argc == 0) username = CVS_Username; else { username = user; } if(!use_domain && !deluser && !disableuser) { CProtocolLibrary lib; if(!lib.PromptForPassword("New Password: ",typed_password,sizeof(typed_password))) error(1,0,"Aborted"); if(!lib.PromptForPassword("Verify Password: ",typed_password2,sizeof(typed_password2))) error(1,0,"Aborted"); if (strcmp(typed_password, typed_password2) != 0) { memset (typed_password, 0, strlen (typed_password)); memset (typed_password2, 0, strlen (typed_password2)); error (1, 0, "Passwords do not match, try again"); } memset (typed_password2, 0, strlen (typed_password2)); if(strlen(typed_password)) crypt_password(typed_password); } } #ifdef SERVER_SUPPORT if(server_active) { if ((argc != 1) && (argc != 2)) usage (passwd_usage); if(!strcmp(user,"*")) username = CVS_Username; else username = user; if(argc==2) strncpy(typed_password,argv[1],sizeof(typed_password)); } #endif if (typed_password[0] && (strcmp(username, CVS_Username) != 0) && (! verify_admin ())) error (1, 0, "Only administrators can add or change another's password"); read_passwd_list(); passnode = find_passwd_entry(username); if (passnode == NULL) { if (!adduser) error (1, 0, "Could not find %s in password file", username); if (! verify_admin()) { error (1, 0, "Only administrators can add users" ); } passnode = new_passwd_entry(); passnode->username=xstrdup(username); passnode->password=xstrdup(typed_password); passnode->real_username=NULL; } if(deluser) { if (! verify_admin()) { error (1, 0, "Only administrators can delete users" ); } xfree(passnode->username); passnode->username = NULL; } else if(disableuser) { if (! verify_admin()) { error (1, 0, "Only administrators can disable users" ); } xfree(passnode->password); passnode->password=xstrdup("#DISABLED#"); } else { xfree(passnode->password); #ifdef _WIN32 /* Unix servers can't make any sense of this */ if(use_domain) { passnode->password = (char*)xmalloc(strlen(password_domain)+2); strcpy(passnode->password,"!"); strcat(passnode->password,password_domain); } else #endif passnode->password = xstrdup(typed_password); if(realuser) { if(!getpwnam(real_user)) error(1, 0, "User '%s' is not a real user on the system.",real_user); xfree(passnode->real_username); passnode->real_username = xstrdup(real_user); } else if (remove_realuser) { xfree(passnode->real_username); passnode->real_username=NULL; } if(!runas_user && ((passnode->real_username && !getpwnam(passnode->real_username)) || (!passnode->real_username && passnode->username && !getpwnam(passnode->username)))) { error(0,0,"*WARNING* CVS user '%s' will not be able to log in until they are aliased to a valid system user.",username); } } write_passwd_list(); free_passwd_list(); xfree(real_user); xfree(password_domain); return (err); }