static char sccsid
[] = "@(#)passwd.c 4.1 (Berkeley) %G%";
* enter a password in the password file
* this program should be suid with owner
* with an owner with write permission on /etc/passwd
char passwd
[] = "/etc/passwd";
char temp
[] = "/etc/ptmp";
struct passwd
*getpwent();
if ((uname
= getlogin()) == NULL
) {
printf ("Usage: passwd user\n");
printf("Changing password for %s\n", uname
);
while (((pwd
= getpwent()) != NULL
) && strcmp(pwd
->pw_name
, uname
))
if (pwd
== NULL
|| (u
!= 0 && u
!= pwd
->pw_uid
)) {
printf("Permission denied.\n");
if (pwd
->pw_passwd
[0] && u
!= 0) {
strcpy(pwbuf
, getpass("Old password:"));
pw
= crypt(pwbuf
, pwd
->pw_passwd
);
if (strcmp(pw
, pwd
->pw_passwd
) != 0) {
strcpy(pwbuf
, getpass("New password:"));
printf("Password unchanged.\n");
* Insure password is of reasonable length and
* composition. If we really wanted to make things
* sticky, we could check the dictionary for common
* words, but then things would really be slow.
if (c
>= 'a' && c
<= 'z')
else if (c
>= 'A' && c
<= 'Z')
else if (c
>= '0' && c
<= '9')
if (flags
>= 7 && pwlen
>= 4)
if ((flags
== 2 || flags
== 4) && pwlen
>= 6)
if ((flags
== 3 || flags
== 5 || flags
== 6) && pwlen
>= 5)
printf("Please use %s.\n", flags
== 1 ?
"at least one non-numeric character" :
if (strcmp(pwbuf
, getpass("Retype new password:")) != 0) {
printf("Mismatch - password unchanged.\n");
saltc
[1] = (salt
>>6) & 077;
for (i
= 0; i
< 2; i
++) {
pw
= crypt(pwbuf
, saltc
);
signal(SIGQUIT
, SIG_IGN
);
* The mode here could be 644 except then old versions
* of passwd that don't honor the advisory locks might
* sneak in and mess things up. If we could believe the
* locking were honored, then we could also eliminate the
* chmod below after the rename.
fd
= open(temp
, FWRONLY
|FCREATE
|FEXLOCK
|FNBLOCK
, 0600);
fprintf(stderr
, "passwd: ");
fprintf(stderr
, "password file busy - try again.\n");
signal(SIGTSTP
, SIG_IGN
);
if ((tf
= fdopen(fd
, "w")) == NULL
) {
fprintf(stderr
, "passwd: fdopen failed?\n");
* Copy passwd to temp, replacing matching lines
while ((pwd
= getpwent()) != NULL
) {
if (strcmp(pwd
->pw_name
,uname
) == 0) {
if (u
&& u
!= pwd
->pw_uid
) {
fprintf(stderr
, "passwd: permission denied.\n");
if (pwd
->pw_gecos
[0] == '*')
fprintf(tf
,"%s:%s:%d:%d:%s:%s:%s\n",
if (rename(temp
, passwd
) < 0) {
fprintf(stderr
, "passwd: "); perror("rename");