summaryrefslogtreecommitdiffstats
path: root/login-utils/passwd.c
diff options
context:
space:
mode:
Diffstat (limited to 'login-utils/passwd.c')
-rw-r--r--login-utils/passwd.c318
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);
}