diff options
Diffstat (limited to 'login-utils/passwd.c')
-rw-r--r-- | login-utils/passwd.c | 318 |
1 files changed, 191 insertions, 127 deletions
diff --git a/login-utils/passwd.c b/login-utils/passwd.c index 5bd6d3abd..1c786e94e 100644 --- a/login-utils/passwd.c +++ b/login-utils/passwd.c @@ -5,16 +5,26 @@ /* Hacked by Alvaro Martinez Echevarria, alvaro@enano.etsit.upm.es, to allow peaceful coexistence with yp. Nov 94. */ +/* Hacked to allow root to set passwd from command line. + by Arpad Magossanyi (mag@tas.vein.hu) */ +/* + * Usage: passwd [username [password]] + * Only root may use the one and two argument forms. + */ + #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <unistd.h> #include <termios.h> +#include <fcntl.h> #include <pwd.h> #include <ctype.h> #include <time.h> #include <string.h> +#include <errno.h> +#include <sys/resource.h> extern int is_local(char *); @@ -23,171 +33,225 @@ extern int is_local(char *); #define MAX_LENGTH 1024 +static void +pexit(str) + char *str; +{ + perror(str); + exit(1); +} + int main(argc, argv) - int argc; - char *argv[]; + int argc; + char *argv[]; { - struct passwd *pe; - uid_t gotuid = getuid(); - char *pwdstr, *cryptstr; - char pwdstr1[10]; - int ucase, lcase, other; - char *p, *q, *user; - time_t tm; - char salt[2]; - FILE *fd_in, *fd_out; - char line[MAX_LENGTH]; - int error=0; - int r; - - umask(022); + struct passwd *pe; + uid_t gotuid = getuid(); + char *pwdstr = NULL, *cryptstr, *oldstr; + char pwdstr1[10]; + int ucase, lcase, other; + char *p, *q, *user; + time_t tm; + char salt[2]; + FILE *fd_in, *fd_out; + char line[MAX_LENGTH]; + char colonuser[16]; + int error=0; + int r; + int ptmp; +#ifndef USE_SETPWNAM + struct rlimit rlim; +#endif - if(argc > 2) { - puts("Too many arguments"); - exit(1); - } else if(argc == 2) { - if(gotuid) { - puts("Only root can change the password for others"); - exit(1); - } - user = argv[1]; - } else { - if (!(user = getlogin())) { - if (!(pe = getpwuid( getuid() ))) { - puts("Cannot find login name"); - exit(1); - } else - user = pe->pw_name; - } + if(argc > 3) { + puts("Too many arguments"); + exit(1); + } else if(argc >= 2) { + if(gotuid) { + puts("Only root can change the password for others"); + exit(1); } - - if(!(pe = getpwnam(user))) { - puts("Can't find username anywhere. Are you really a user?"); - exit(1); + user = argv[1]; + + if (argc == 3) pwdstr = argv[2]; + + } else { + if (!(user = getlogin())) { + if (!(pe = getpwuid( getuid() ))) { + pexit("Cannot find login name"); + } else + user = pe->pw_name; } + } - if (!(is_local(user))) { - puts("Sorry, I can only change local passwords. Use yppasswd instead."); - exit(1); - } +#ifndef USE_SETPWNAM + umask(022); - /* if somebody got into changing utmp... */ - if(gotuid && gotuid != pe->pw_uid) { - puts("UID and username does not match, imposter!"); + rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; + setrlimit(RLIMIT_CPU, &rlim); + setrlimit(RLIMIT_FSIZE, &rlim); + setrlimit(RLIMIT_STACK, &rlim); + setrlimit(RLIMIT_DATA, &rlim); + setrlimit(RLIMIT_RSS, &rlim); + rlim.rlim_cur = rlim.rlim_max = 0; + setrlimit(RLIMIT_CORE, &rlim); +#endif + + if(!(pe = getpwnam(user))) { + pexit("Can't find username anywhere. Are you really a user?"); + } + + if (!(is_local(user))) { + puts("Sorry, I can only change local passwords. Use yppasswd instead."); + exit(1); + } + + /* if somebody got into changing utmp... */ + if(gotuid && gotuid != pe->pw_uid) { + puts("UID and username does not match, imposter!"); + exit(1); + } + + printf( "Changing password for %s\n", user ); + + if(gotuid && pe->pw_passwd && pe->pw_passwd[0]) { + oldstr = getpass("Enter old password: "); + if(strncmp(pe->pw_passwd, crypt(oldstr, pe->pw_passwd), 13)) { + puts("Illegal password, imposter."); exit(1); } + } - printf( "Changing password for %s\n", user ); - - if(gotuid && pe->pw_passwd && pe->pw_passwd[0]) { - pwdstr = getpass("Enter old password: "); - if(strncmp(pe->pw_passwd, crypt(pwdstr, pe->pw_passwd), 13)) { - puts("Illegal password, imposter."); - exit(1); - } - } + if (!pwdstr) { + /* password not set on command line by root, ask for it ... */ -redo_it: + redo_it: pwdstr = getpass("Enter new password: "); - strncpy(pwdstr1, pwdstr, 9); - pwdstr = getpass("Re-type new password: "); - - if(strncmp(pwdstr, pwdstr1, 8)) { - puts("You misspelled it. Password not changed."); - exit(0); + if (pwdstr[0] == '\0') { + puts("Password not changed."); + exit(1); } if((strlen(pwdstr) < 6) && gotuid) { - puts("The password must have at least 6 characters, try again."); - goto redo_it; + puts("The password must have at least 6 characters, try again."); + goto redo_it; } other = ucase = lcase = 0; for(p = pwdstr; *p; p++) { - ucase = ucase || isupper(*p); - lcase = lcase || islower(*p); - other = other || !isalpha(*p); + ucase = ucase || isupper(*p); + lcase = lcase || islower(*p); + other = other || !isalpha(*p); } if((!ucase || !lcase) && !other && gotuid) { - puts("The password must have both upper- and lowercase"); - puts("letters, or non-letters; try again."); - goto redo_it; + puts("The password must have both upper- and lowercase"); + puts("letters, or non-letters; try again."); + goto redo_it; + } + + if (pe->pw_passwd[0] + && !strncmp(pe->pw_passwd, crypt(pwdstr, pe->pw_passwd), 13) + && gotuid) { + puts("You cannot reuse the old password."); + goto redo_it; } r = 0; for(p = pwdstr, q = pe->pw_name; *q && *p; q++, p++) { - if(tolower(*p) != tolower(*q)) { - r = 1; - break; - } + if(tolower(*p) != tolower(*q)) { + r = 1; + break; + } } - + for(p = pwdstr + strlen(pwdstr)-1, q = pe->pw_name; *q && p >= pwdstr; q++, p--) { - if(tolower(*p) != tolower(*q)) { - r += 2; - break; - } + if(tolower(*p) != tolower(*q)) { + r += 2; + break; + } } - + if(gotuid && r != 3) { - puts("Please don't use something like your username as password!"); - goto redo_it; + puts("Please don't use something like your username as password!"); + goto redo_it; } - + /* do various other checks for stupid passwords here... */ - - time(&tm); - salt[0] = bin_to_ascii(tm & 0x3f); - salt[1] = bin_to_ascii((tm >> 5) & 0x3f); - cryptstr = crypt(pwdstr, salt); - if(access("/etc/ptmp", F_OK) == 0) { - puts("/etc/ptmp exists, can't change password"); - exit(1); - } + strncpy(pwdstr1, pwdstr, 9); + pwdstr = getpass("Re-type new password: "); - if(!(fd_out = fopen("/etc/ptmp", "w"))) { - puts("Can't open /etc/ptmp, can't update password"); - exit(1); + if(strncmp(pwdstr, pwdstr1, 8)) { + puts("You misspelled it. Password not changed."); + exit(1); } + } /* pwdstr != argv[2] i.e. password set on command line */ + + time(&tm); + salt[0] = bin_to_ascii(tm & 0x3f); + salt[1] = bin_to_ascii((tm >> 6) & 0x3f); + cryptstr = crypt(pwdstr, salt); + + if (pwdstr[0] == 0) cryptstr = ""; - if(!(fd_in = fopen("/etc/passwd", "r"))) { - puts("Can't read /etc/passwd, can't update password"); - exit(1); +#ifdef USE_SETPWNAM + pe->pw_passwd = cryptstr; + if (setpwnam( pe ) < 0) { + perror( "setpwnam" ); + printf( "Password *NOT* changed. Try again later.\n" ); + exit( 1 ); + } +#else + if ((ptmp = open("/etc/ptmp", O_CREAT|O_EXCL|O_WRONLY, 0600)) < 0) { + pexit("Can't exclusively open /etc/ptmp, can't update password"); + } + fd_out = fdopen(ptmp, "w"); + + if(!(fd_in = fopen("/etc/passwd", "r"))) { + pexit("Can't read /etc/passwd, can't update password"); + } + + strcpy(colonuser, user); + strcat(colonuser, ":"); + while(fgets(line, sizeof(line), fd_in)) { + if(!strncmp(line,colonuser,strlen(colonuser))) { + pe->pw_passwd = cryptstr; + if(putpwent(pe, fd_out) < 0) { + error = 1; + } + } else { + if(fputs(line,fd_out) < 0) { + error = 1; + } } - while(fgets(line, sizeof(line), fd_in)) { - if(!strncmp(line,user,strlen(user))) { - pe->pw_passwd = cryptstr; - if(putpwent(pe, fd_out) < 0) { - error = 1; - } - } else { - if(fputs(line,fd_out) < 0) { - error = 1; - } - } - if(error) { - puts("Error while writing new password file, password not changed."); - fclose(fd_out); - endpwent(); - unlink("/etc/ptmp"); - exit(1); - } + if(error) { + puts("Error while writing new password file, password not changed."); + fclose(fd_out); + endpwent(); + unlink("/etc/ptmp"); + exit(1); } - fclose(fd_in); - fclose(fd_out); - - unlink("/etc/passwd.OLD"); - link("/etc/passwd", "/etc/passwd.OLD"); - unlink("/etc/passwd"); - link("/etc/ptmp", "/etc/passwd"); - unlink("/etc/ptmp"); - chmod("/etc/passwd", 0644); - chown("/etc/passwd", 0, 0); - - puts("Password changed."); - exit(0); + } + fclose(fd_in); + fclose(fd_out); + + unlink("/etc/passwd.OLD"); /* passwd.OLD not required */ + if (link("/etc/passwd", "/etc/passwd.OLD")) + pexit("link(/etc/passwd, /etc/passwd.OLD) failed: no change"); + if (unlink("/etc/passwd") < 0) + pexit("unlink(/etc/passwd) failed: no change"); + if (link("/etc/ptmp", "/etc/passwd") < 0) + pexit("link(/etc/ptmp, /etc/passwd) failed: PASSWD file DROPPED!!"); + if (unlink("/etc/ptmp") < 0) + pexit("unlink(/etc/ptmp) failed: /etc/ptmp still exists"); + + chmod("/etc/passwd", 0644); + chown("/etc/passwd", 0, 0); +#endif + + puts("Password changed."); + exit(0); } |