/* ============================================================================= // RCSfile: setpasswd.c,v // Revision: 1.5 // Date: 1995/07/24 20:35:36 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // This programs sets the a user's password. The login name and cleartext // password are taken on the command line. A backup of the password file // is made. For now, the salt is constant. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // LICENSE // This source code is hereby released to the public domain and is unsupported. // You are encouraged to copy and modify this file. Please clearly document // modifications with authorship and motivation. Bug reports, code // contributions, and suggestions are appreciated. // // SOURCE // New versions of this file may be obtained from (as of 1999/01/31) // http://www.in-machina.com/~reece/src/setpasswd.c // ftp://in-machina.com/pub/reece/src/setpasswd.c // // AUTHOR // Reece Hart, http://www.in-machina.com/~reece/, PGP:0xD178AAF9 // Do not send unsolicited bulk email. Boycott companies which do so. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Wish List: // * optional randomized salts // * optionally take arguments from stdin for security // * check _pw_stayopen on certain systems // * setpwfile only available on certain systems... work around this // * preserve mode of /etc/passwd // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Log: setpasswd.c,v // Revision 1.5 1995/07/24 20:35:36 reece // * supports shadow passwords on SGI (only) by calling pwconv after // passwd is updated // // Revision 1.3 1995/06/20 21:58:10 reece // * IRIX define for IRIX-compatibility // * miscellaneous cleanup // // Revision 1.2 1995/06/20 21:19:25 reece // * created setpasswd function to move password setting outside main loop // * now processes multiple login and password argument pairs // * now correctly uses appropriate testing file for source (setpwfile) // =========================================|=================================*/ static const char RCSId[]="Id: setpasswd.c,v 1.5 1995/07/24 20:35:36 reece Exp"; #include #include #include #include #ifdef IRIX #include #endif #ifdef TESTING #define PASSWDFN "passwd" #define SHADOWFN "shadow" #else #define PASSWDFN "/etc/passwd" #define SHADOWFN "/etc/shadow" #endif #define FALSE 0 #define TRUE !FALSE /* Prototypes */ int setpasswd(FILE* ofp, char* login, char* passwd, char* salt); int fileexists(const char* filename); int main(int argc, char* argv[]) { FILE* ofp; int arg; #ifndef TESTING if (geteuid()!=0) { fprintf(stderr,"%s: must be priveleged user.\n", argv[0]); exit(1); } #endif argc--; if (argc < 2) { fprintf(stderr,"%s: usage: %s [ ...]\n", argv[0],argv[0]); fprintf(stderr,"%s: at least one pair is expected."); exit(1); } ofp=fopen(PASSWDFN".new","w"); if (ofp==NULL) { fprintf(stderr,"%s: couldn't open temporary file.\n",argv[0]); exit(1); } #ifdef TESTING /* works in Digital UNIX 3.2 doesn't work in IRIX 5.3 */ #ifdef IRIX setpwfile is not available in IRIX; testing there is unsupported #else setpwfile(PASSWDFN); #endif #endif /* process arguments in (login,password) pairs */ for (arg=1; arg<=argc-1; arg+=2) { char* login=argv[arg]; char* passwd=argv[arg+1]; char* salt="mk"; /* the salt for crypt */ if (setpasswd(ofp, login, passwd, salt)==1) { fprintf(stderr,"%s: %s: no such user.\n",argv[0],login); fprintf(stderr,"%s: all changes reverted.\n",argv[0]); unlink(PASSWDFN".new"); exit(1); } } if (arg==argc) { fprintf(stderr,"%s: WARNING: remaining argument \"%s\" ignored.",argv[0], argv[arg]); } /* clean up */ setpasswd(ofp,NULL,NULL,NULL); /* finish copying passwd file */ fclose(ofp); /* close the output file */ endpwent(); /* tell system we're done */ rename(PASSWDFN,PASSWDFN".bak"); /* rename to preserve backups */ rename(PASSWDFN".new",PASSWDFN); #ifndef TESTING if (fileexists(SHADOWFN) == TRUE) { #ifdef IRIX if (system("umask 077; cp " SHADOWFN " " SHADOWFN ".bak; pwconv")) { fprintf(stderr,"%s: couldn't convert to shadow file!\n", argv[0]); exit(1); } #else fprintf(stderr, "%s: "SHADOWFN" exists, only "PASSWDFN" changed!\n",argv[0]); #endif } #endif exit(0); } int setpasswd(FILE* ofp, char* login, char* passwd, char* salt) /* Scroll through the pw file and copy individual records to ofp. If the entry for login is found, the passwd is crypt'd with salt, the record is written to ofp, and 0 is returned with the remainder of the file left uncopied. If login isn't found or login is NULL, the remaining records are copied and 0 or 1 is returned; 1 if login wasn't found, 0 otherwise. */ { struct passwd* pwent; while ( (pwent=getpwent()) != NULL) { if ( (login!=NULL) && (strcmp(pwent->pw_name,login)==0) ) { pwent->pw_passwd=crypt(passwd,salt); putpwent(pwent,ofp); return(0); } putpwent(pwent,ofp); } if (login!=NULL) /* caller was looking for a */ return(1); /* login that wasn't found */ return(0); } int fileexists(const char* filename) { FILE* fp; if ( (fp=fopen(filename,"r")) != NULL ) { fclose(fp); return TRUE; } else return FALSE; }