* Copyright (c) 1988 The Regents of the University of California.
* %sccs.include.redist.c%
"@(#) Copyright (c) 1988 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)passwd.c 4.41 (Berkeley) %G%";
#include <sys/resource.h>
#include <kerberosIV/des.h>
#include <kerberosIV/krb.h>
#include "kpasswd_proto.h"
extern int errno
, optind
;
char *fend
, *np
, *passwd
, *temp
, *tend
, *uname
;
char from
[MAXPATHLEN
], to
[MAXPATHLEN
];
char *getnewpasswd(), *getlogin();
while ((ch
= getopt(argc
, argv
, ARGSTR
)) != EOF
)
/* change local password file */
if (use_kerberos
&& (strcmp(argv
[1],uname
) != 0)) {
"must kinit to change another's password\n");
if (!(pw
= getpwnam(uname
))) {
fprintf(stderr
, "passwd: unknown user %s.\n", uname
);
if (uid
&& uid
!= pw
->pw_uid
) {
fprintf(stderr
, "passwd: %s\n", strerror(EACCES
));
(void)signal(SIGHUP
, SIG_IGN
);
(void)signal(SIGINT
, SIG_IGN
);
(void)signal(SIGQUIT
, SIG_IGN
);
(void)signal(SIGTSTP
, SIG_IGN
);
rlim
.rlim_cur
= rlim
.rlim_max
= RLIM_INFINITY
;
(void)setrlimit(RLIMIT_CPU
, &rlim
);
(void)setrlimit(RLIMIT_FSIZE
, &rlim
);
if ((fd
= open(temp
, O_WRONLY
|O_CREAT
|O_EXCL
, 0600)) < 0) {
"passwd: password file busy -- try again later.\n");
fprintf(stderr
, "passwd: %s: %s", temp
, strerror(errno
));
if (!(temp_fp
= fdopen(fd
, "w"))) {
fprintf(stderr
, "passwd: can't write %s", temp
);
passwd
= _PATH_MASTERPASSWD
;
if (!freopen(passwd
, "r", stdin
)) {
fprintf(stderr
, "passwd: can't read %s", passwd
);
printf("Changing password for %s.\n", pw
->pw_name
);
np
= getnewpasswd(pw
, temp
);
if (!copy(pw
->pw_name
, np
, temp_fp
, pw
))
fprintf(stderr
, "passwd: can't fork");
fprintf(stderr
, "passwd: mkpasswd failed");
bad
: fprintf(stderr
, "; password unchanged.\n");
* possible race; have to rename four files, and someone could slip
* in between them. LOCK_EX and rename the ``passwd.dir'' file first
* so that getpwent(3) can't slip in; the lock should never fail and
* it's unclear what to do if it does. Rename ``ptmp'' last so that
* passwd/vipw/chpass can't slip in.
(void)setpriority(PRIO_PROCESS
, 0, -20);
fend
= strcpy(from
, temp
) + strlen(temp
);
tend
= strcpy(to
, _PATH_PASSWD
) + strlen(_PATH_PASSWD
);
if ((fd
= open(from
, O_RDONLY
, 0)) >= 0)
(void)flock(fd
, LOCK_EX
);
(void)rename(from
, _PATH_PASSWD
);
(void)rename(temp
, passwd
);
for (done
= 0; fgets(buf
, sizeof(buf
), stdin
);) {
/* skip lines that are too big */
fprintf(stderr
, "passwd: line too long.\n");
if (!(p
= index(buf
, ':'))) {
fprintf(stderr
, "passwd: corrupted entry.\n");
if (!(p
= index(++p
, ':'))) {
fprintf(stderr
, "passwd: corrupted entry.\n");
* reset change time to zero; when classes are implemented,
* go and get the "offset" value for this class and reset
fprintf(fp
, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
pw
->pw_name
, np
, pw
->pw_uid
, pw
->pw_gid
,
pw
->pw_class
, 0L, pw
->pw_expire
, pw
->pw_gecos
,
pw
->pw_dir
, pw
->pw_shell
);
register struct passwd
*pw
;
char buf
[_PASSWORD_LEN
+1], salt
[2], *crypt(), *getpass();
if (uid
&& pw
->pw_passwd
&&
strcmp(crypt(getpass("Old password:"), pw
->pw_passwd
),
(void)printf("passwd: %s.\n", strerror(EACCES
));
p
= getpass("New password:");
(void)printf("Password unchanged.\n");
if (strlen(p
) <= 5 && (uid
!= 0 || tries
++ < 2)) {
printf("Please enter a longer password.\n");
for (t
= p
; *t
&& islower(*t
); ++t
);
if (!*t
&& (uid
!= 0 || tries
++ < 2)) {
printf("Please don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested.\n");
if (!strcmp(buf
, getpass("Retype new password:")))
printf("Mismatch; try again, EOF to quit.\n");
/* grab a random printable character that isn't a colon */
(void)srandom((int)time((time_t *)NULL
));
to64(&salt
[1], (long)(29*25), 4);
to64(&salt
[5], (long)random(), 4);
to64(&salt
[0], (long)random(), 2);
return(crypt(buf
, salt
));
static unsigned char itoa64
[] = /* 0..63 => ascii-64 */
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
execl(_PATH_MKPASSWD
, "mkpasswd", "-p", file
, NULL
);
return(waitpid(pid
, &pstat
, 0) == -1 ? -1 : pstat
.w_status
);
fprintf(stderr
, "usage: passwd [-l] user\n");
fprintf(stderr
, "usage: passwd user\n");
Key_schedule random_schedule
;
char realm
[REALM_SZ
], krbhst
[MAX_HSTNM
];
static struct kpasswd_data proto_data
;
static Key_schedule osched
;
static struct timeval timeout
= { CLIENT_KRB_TIMEOUT
, 0 };
char pass
[MAX_PW_LEN
], password
[MAX_PW_LEN
];
static struct rlimit rl
= { 0, 0 };
(void)signal(SIGHUP
, SIG_IGN
);
(void)signal(SIGINT
, SIG_IGN
);
(void)signal(SIGTSTP
, SIG_IGN
);
if (setrlimit(RLIMIT_CORE
, &rl
) < 0) {
if ((se
= getservbyname(SERVICE
, PROTO
)) == NULL
) {
fprintf(stderr
, "couldn't find entry for service %s/%s\n",
if ((rval
= krb_get_lrealm(realm
,1)) != KSUCCESS
) {
fprintf(stderr
, "couldn't get local Kerberos realm: %s\n",
if ((rval
= krb_get_krbhst(krbhst
, realm
, 1)) != KSUCCESS
) {
fprintf(stderr
, "couldn't get Kerberos host: %s\n",
if ((host
= gethostbyname(krbhst
)) == NULL
) {
fprintf(stderr
, "couldn't get host entry for krb host %s\n",
sin
.sin_family
= host
->h_addrtype
;
bcopy(host
->h_addr
, (char *) &sin
.sin_addr
, host
->h_length
);
sin
.sin_port
= se
->s_port
;
if ((sock
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
)) < 0) {
if (connect(sock
, (struct sockaddr
*) &sin
, sizeof(sin
)) < 0) {
authopts
, /* NOT mutual */
&ticket
, /* (filled in) */
krbhst
, /* instance (krbhst) */
(u_long
) getpid(), /* checksum */
fprintf(stderr
, "Kerberos sendauth error: %s\n",
krb_get_cred("krbtgt", realm
, realm
, &cred
);
printf("Changing Kerberos password for %s.%s@%s.\n",
cred
.pname
, cred
.pinst
, realm
);
if (des_read_pw_string(pass
,
sizeof(pass
)-1, "Old Kerberos password:", 0)) {
"error reading old Kerberos password\n");
(void)des_string_to_key(pass
, okey
);
(void)des_key_sched(okey
, osched
);
(void)des_set_key(okey
, osched
);
/* wait on the verification string */
select(sock
+ 1, &readfds
, (fd_set
*) 0, (fd_set
*) 0, &timeout
);
if ((rval
< 1) || !FD_ISSET(sock
, &readfds
)) {
fprintf(stderr
, "timed out (aborted)\n");
fprintf(stderr
, "select failed (aborted)\n");
/* read verification string */
if (des_read(sock
, &proto_data
, sizeof(proto_data
)) !=
"couldn't read verification string (aborted)\n");
(void)signal(SIGHUP
, finish
);
(void)signal(SIGINT
, finish
);
if (strcmp(SECURE_STRING
, proto_data
.secure_msg
) != 0) {
/* don't complain loud if user just hit return */
if (pass
== NULL
|| (!*pass
))
fprintf(stderr
, "Sorry\n");
(void)des_key_sched(proto_data
.random_key
, random_schedule
);
(void)des_set_key(proto_data
.random_key
, random_schedule
);
(void)bzero(pass
, sizeof(pass
));
if (des_read_pw_string(pass
,
sizeof(pass
)-1, "New Kerberos password:", 0)) {
"error reading new Kerberos password (aborted)\n");
if (des_read_pw_string(password
,
sizeof(password
)-1, "Retype new Kerberos password:", 0)) {
"error reading new Kerberos password (aborted)\n");
if (strcmp(password
, pass
) != 0) {
fprintf(stderr
, "password mismatch (aborted)\n");
printf("using NULL password\n");
send_update(sock
, password
, SECURE_STRING
);
select(sock
+ 1, &readfds
, (fd_set
*) 0, (fd_set
*) 0, &timeout
);
if ((rval
< 1) || !FD_ISSET(sock
, &readfds
)) {
fprintf(stderr
, "timed out reading ACK (aborted)\n");
fprintf(stderr
, "select failed (aborted)\n");
send_update(dest
, pwd
, str
)
static struct update_data ud
;
strncpy(ud
.secure_msg
, str
, MAX_PW_LEN
);
strncpy(ud
.pw
, pwd
, sizeof(ud
.pw
));
if (des_write(dest
, &ud
, sizeof(ud
)) != sizeof(ud
)) {
fprintf(stderr
, "couldn't write pw update (abort)\n");
cc
= des_read(remote
, buf
, sizeof(buf
));
fprintf(stderr
, "error reading acknowledgement (aborted)\n");
(void)bzero(&proto_data
, sizeof(proto_data
));
(void)bzero(okey
, sizeof(okey
));
(void)bzero(osched
, sizeof(osched
));
(void)bzero(random_schedule
, sizeof(random_schedule
));