version 1.7, 1997/06/29 11:10:33 |
version 1.8, 1998/01/20 15:32:19 |
|
|
/* $OpenBSD$ */ |
/* $KTH: kpasswd.c,v 1.25 1997/05/02 14:28:51 assar Exp $ */ |
|
|
/*- |
/* |
* Copyright (c) 1990 The Regents of the University of California. |
Copyright (C) 1989 by the Massachusetts Institute of Technology |
* All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* 3. All advertising materials mentioning features or use of this software |
|
* must display the following acknowledgement: |
|
* This product includes software developed by the University of |
|
* California, Berkeley and its contributors. |
|
* 4. Neither the name of the University nor the names of its contributors |
|
* may be used to endorse or promote products derived from this software |
|
* without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
* SUCH DAMAGE. |
|
*/ |
|
|
|
#ifndef lint |
Export of this software from the United States of America is assumed |
/*static char sccsid[] = "from: @(#)krb_passwd.c 5.4 (Berkeley) 3/1/91";*/ |
to require a specific license from the United States Government. |
static char rcsid[] = "$OpenBSD$"; |
It is the responsibility of any person or organization contemplating |
#endif /* not lint */ |
export to obtain such a license before exporting. |
|
|
|
WITHIN THAT CONSTRAINT, permission to use, copy, modify, and |
|
distribute this software and its documentation for any purpose and |
|
without fee is hereby granted, provided that the above copyright |
|
notice appear in all copies and that both that copyright notice and |
|
this permission notice appear in supporting documentation, and that |
|
the name of M.I.T. not be used in advertising or publicity pertaining |
|
to distribution of the software without specific, written prior |
|
permission. M.I.T. makes no representations about the suitability of |
|
this software for any purpose. It is provided "as is" without express |
|
or implied warranty. |
|
|
|
*/ |
|
|
|
/* |
|
* change your password with kerberos |
|
*/ |
|
|
#ifdef KERBEROS |
#ifdef KERBEROS |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
|
|
#include <netinet/in.h> |
#include <netinet/in.h> |
#include <des.h> |
#include <des.h> |
#include <kerberosIV/krb.h> |
#include <kerberosIV/krb.h> |
|
#include <kerberosIV/kadm.h> |
|
#include <kerberosIV/kadm_err.h> |
#include <netdb.h> |
#include <netdb.h> |
#include <signal.h> |
#include <signal.h> |
#include <pwd.h> |
#include <pwd.h> |
#include <err.h> |
#include <err.h> |
#include <errno.h> |
#include <errno.h> |
#include <stdio.h> |
#include <stdio.h> |
#include "kpasswd_proto.h" |
|
#include <string.h> |
#include <string.h> |
#include <stdlib.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <unistd.h> |
|
|
#define PROTO "tcp" |
char realm[REALM_SZ]; |
|
|
static struct timeval timeout = { CLIENT_KRB_TIMEOUT, 0 }; |
extern void usage(int value); |
static struct kpasswd_data proto_data; |
|
static des_cblock okey; |
|
static Key_schedule osched; |
|
KTEXT_ST ticket; |
|
Key_schedule random_schedule; |
|
long authopts; |
|
char realm[REALM_SZ], krbhst[MAX_HSTNM]; |
|
int sock; |
|
|
|
krb_passwd() |
int |
|
krb_passwd(int argc, char **argv) |
{ |
{ |
struct servent *se; |
krb_principal principal; |
struct hostent *host; |
krb_principal default_principal; |
struct sockaddr_in sin; |
int realm_given = 0; /* True if realm was give on cmdline */ |
CREDENTIALS cred; |
int use_default = 1; /* True if we should use default name */ |
int fdsn; |
int status; /* return code */ |
fd_set *fdsp; |
char pword[MAX_KPW_LEN]; |
int rval; |
int c; |
char pass[_PASSWORD_LEN], password[_PASSWORD_LEN]; |
char tktstring[MAXPATHLEN]; |
static void finish(); |
|
|
memset (&principal, 0, sizeof(principal)); |
|
memset (&default_principal, 0, sizeof(default_principal)); |
|
|
|
krb_get_default_principal (default_principal.name, |
|
default_principal.instance, |
|
default_principal.realm); |
|
|
static struct rlimit rl = { 0, 0 }; |
while ((c = getopt(argc, argv, "u:n:i:r:h")) != EOF) { |
|
switch (c) { |
(void)signal(SIGHUP, SIG_IGN); |
case 'u': |
(void)signal(SIGINT, SIG_IGN); |
status = krb_parse_name (optarg, &principal); |
(void)signal(SIGTSTP, SIG_IGN); |
if (status != KSUCCESS) |
|
errx (2, "%s", krb_get_err_text(status)); |
if (setrlimit(RLIMIT_CORE, &rl) < 0) { |
if (principal.realm[0]) |
warn("setrlimit"); |
realm_given++; |
return(1); |
else if (krb_get_lrealm(principal.realm, 1) != KSUCCESS) |
|
errx (1, "Could not find default realm!"); |
|
break; |
|
case 'n': |
|
if (k_isname(optarg)) |
|
strncpy(principal.name, optarg, sizeof(principal.name) - 1); |
|
else { |
|
warnx("Bad name: %s", optarg); |
|
usage(1); |
|
} |
|
break; |
|
case 'i': |
|
if (k_isinst(optarg)) |
|
strncpy(principal.instance, |
|
optarg, |
|
sizeof(principal.instance) - 1); |
|
else { |
|
warnx("Bad instance: %s", optarg); |
|
usage(1); |
|
} |
|
break; |
|
case 'r': |
|
if (k_isrealm(optarg)) { |
|
strncpy(principal.realm, optarg, sizeof(principal.realm) - 1); |
|
realm_given++; |
|
} else { |
|
warnx("Bad realm: %s", optarg); |
|
usage(1); |
|
} |
|
break; |
|
case 'h': |
|
usage(0); |
|
break; |
|
default: |
|
usage(1); |
|
break; |
} |
} |
|
use_default = 0; |
|
} |
|
if (optind < argc) { |
|
use_default = 0; |
|
status = krb_parse_name (argv[optind], &principal); |
|
if(status != KSUCCESS) |
|
errx (1, "%s", krb_get_err_text (status)); |
|
} |
|
|
if ((se = getservbyname(SERVICE, PROTO)) == NULL) { |
if (use_default) { |
warnx("couldn't find entry for service %s/%s", SERVICE, PROTO); |
strncpy(principal.name, default_principal.name, ANAME_SZ - 1); |
return(1); |
principal.name[ANAME_SZ - 1] = '\0'; |
|
strncpy(principal.instance, default_principal.instance, INST_SZ - 1); |
|
principal.instance[INST_SZ - 1] = '\0'; |
|
strncpy(principal.realm, default_principal.realm, REALM_SZ - 1); |
|
principal.realm[REALM_SZ - 1] = '\0'; |
|
} else { |
|
if (!principal.name[0]) { |
|
strncpy(principal.name, default_principal.name, ANAME_SZ - 1); |
|
principal.name[ANAME_SZ - 1] = '\0'; |
} |
} |
|
if (!principal.realm[0]) { |
if ((rval = krb_get_lrealm(realm,1)) != KSUCCESS) { |
strncpy(principal.realm, default_principal.realm, REALM_SZ - 1); |
warnx("couldn't get local Kerberos realm: %s", krb_err_txt[rval]); |
principal.realm[REALM_SZ - 1] = '\0'; |
return(1); |
|
} |
} |
|
} |
|
|
if ((rval = krb_get_krbhst(krbhst, realm, 1)) != KSUCCESS) { |
snprintf(tktstring, sizeof(tktstring), |
warnx("couldn't get Kerberos host: %s", krb_err_txt[rval]); |
TKT_ROOT "_cpw_%u", (unsigned)getpid()); |
return(1); |
krb_set_tkt_string(tktstring); |
} |
|
|
if (get_pw_new_pwd(pword, sizeof(pword), &principal, |
|
realm_given)) { |
|
dest_tkt (); |
|
exit(1); |
|
} |
|
|
|
status = kadm_init_link (PWSERV_NAME, KRB_MASTER, principal.realm); |
|
if (status != KADM_SUCCESS) |
|
com_err(argv[0], status, "while initializing"); |
|
else { |
|
des_cblock newkey; |
|
char *pw_msg; /* message from server */ |
|
|
if ((host = gethostbyname(krbhst)) == NULL) { |
des_string_to_key(pword, &newkey); |
warnx("couldn't get host entry for krb host %s", krbhst); |
status = kadm_change_pw_plain((unsigned char*)&newkey, pword, &pw_msg); |
return(1); |
memset(newkey, 0, sizeof(newkey)); |
} |
|
|
if (status == KADM_INSECURE_PW) |
|
warnx ("Insecure password: %s", pw_msg); |
|
else if (status != KADM_SUCCESS) |
|
com_err(argv[0], status, " attempting to change password."); |
|
} |
|
memset(pword, 0, sizeof(pword)); |
|
|
sin.sin_family = host->h_addrtype; |
if (status != KADM_SUCCESS) |
bcopy(host->h_addr, (char *) &sin.sin_addr, host->h_length); |
fprintf(stderr,"Password NOT changed.\n"); |
sin.sin_port = se->s_port; |
else |
|
printf("Password changed.\n"); |
|
|
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { |
dest_tkt(); |
warn("socket"); |
if (status) |
return(1); |
return 2; |
} |
else |
|
return 0; |
if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { |
|
warn("connect"); |
|
(void)close(sock); |
|
return(1); |
|
} |
|
|
|
rval = krb_sendauth( |
|
authopts, /* NOT mutual */ |
|
sock, |
|
&ticket, /* (filled in) */ |
|
SERVICE, |
|
krbhst, /* instance (krbhst) */ |
|
realm, /* dest realm */ |
|
(u_long) getpid(), /* checksum */ |
|
NULL, /* msg data */ |
|
NULL, /* credentials */ |
|
NULL, /* schedule */ |
|
NULL, /* local addr */ |
|
NULL, /* foreign addr */ |
|
"KPWDV0.1" |
|
); |
|
|
|
if (rval != KSUCCESS) { |
|
warnx("Kerberos sendauth error: %s", krb_err_txt[rval]); |
|
return(1); |
|
} |
|
|
|
krb_get_cred("krbtgt", realm, realm, &cred); |
|
|
|
(void)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)) { |
|
warnx("error reading old Kerberos password"); |
|
return(1); |
|
} |
|
|
|
(void)des_string_to_key(pass, &okey); |
|
(void)des_key_sched(&okey, osched); |
|
(void)desrw_set_key(&okey, osched); |
|
|
|
/* wait on the verification string */ |
|
|
|
fdsn = howmany(sock+1, NFDBITS) * sizeof(fd_mask); |
|
if ((fdsp = (fd_set *)malloc(fdsn)) == NULL) |
|
err(1, "malloc"); |
|
memset(fdsp, 0, fdsn); |
|
FD_SET(sock, fdsp); |
|
|
|
rval = |
|
select(sock + 1, fdsp, (fd_set *) 0, (fd_set *) 0, &timeout); |
|
|
|
if ((rval < 1) || !FD_ISSET(sock, fdsp)) { |
|
free(fdsp); |
|
if(rval == 0) { |
|
warnx("timed out (aborted)"); |
|
cleanup(); |
|
return(1); |
|
} |
|
warnx("select failed (aborted)"); |
|
cleanup(); |
|
return(1); |
|
} |
|
free(fdsp); |
|
|
|
/* read verification string */ |
|
|
|
if (des_read(sock, &proto_data, sizeof(proto_data)) != |
|
sizeof(proto_data)) { |
|
warnx("couldn't read verification string (aborted)"); |
|
cleanup(); |
|
return(1); |
|
} |
|
|
|
(void)signal(SIGHUP, finish); |
|
(void)signal(SIGINT, finish); |
|
|
|
if (strcmp(SECURE_STRING, proto_data.secure_msg) != 0) { |
|
cleanup(); |
|
/* don't complain loud if user just hit return */ |
|
if (pass == NULL || (!*pass)) |
|
return(0); |
|
warnx("Sorry"); |
|
return(1); |
|
} |
|
|
|
(void)des_key_sched(&proto_data.random_key, random_schedule); |
|
(void)desrw_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)) { |
|
warnx("error reading new Kerberos password (aborted)"); |
|
cleanup(); |
|
return(1); |
|
} |
|
|
|
if (des_read_pw_string(password, |
|
sizeof(password)-1, "Retype new Kerberos password:", 0)) { |
|
warnx("error reading new Kerberos password (aborted)"); |
|
cleanup(); |
|
return(1); |
|
} |
|
|
|
if (strcmp(password, pass) != 0) { |
|
warnx("password mismatch (aborted)"); |
|
cleanup(); |
|
return(1); |
|
} |
|
|
|
if (strlen(pass) == 0) |
|
(void)printf("using NULL password\n"); |
|
|
|
send_update(sock, password, SECURE_STRING); |
|
|
|
/* wait for ACK */ |
|
|
|
fdsn = howmany(sock+1, NFDBITS) * sizeof(fd_mask); |
|
if ((fdsp = (fd_set *)malloc(fdsn)) == NULL) |
|
err(1, "malloc"); |
|
memset(fdsp, 0, fdsn); |
|
FD_SET(sock, fdsp); |
|
|
|
rval = |
|
select(sock + 1, fdsp, (fd_set *) 0, (fd_set *) 0, &timeout); |
|
if ((rval < 1) || !FD_ISSET(sock, fdsp)) { |
|
free(fdsp); |
|
if(rval == 0) { |
|
warnx("timed out reading ACK (aborted)"); |
|
cleanup(); |
|
exit(1); |
|
} |
|
warnx("select failed (aborted)"); |
|
cleanup(); |
|
exit(1); |
|
} |
|
free(fdsp); |
|
recv_ack(sock); |
|
cleanup(); |
|
exit(0); |
|
} |
|
|
|
send_update(dest, pwd, str) |
|
int dest; |
|
char *pwd, *str; |
|
{ |
|
static struct update_data ud; |
|
|
|
(void)strncpy(ud.secure_msg, str, _PASSWORD_LEN); |
|
(void)strncpy(ud.pw, pwd, sizeof(ud.pw)); |
|
if (des_write(dest, &ud, sizeof(ud)) != sizeof(ud)) { |
|
warnx("couldn't write pw update (abort)"); |
|
bzero((char *)&ud, sizeof(ud)); |
|
cleanup(); |
|
exit(1); |
|
} |
|
} |
|
|
|
recv_ack(remote) |
|
int remote; |
|
{ |
|
int cc; |
|
char buf[BUFSIZ]; |
|
|
|
cc = des_read(remote, buf, sizeof(buf)); |
|
if (cc <= 0) { |
|
warnx("error reading acknowledgement (aborted)"); |
|
cleanup(); |
|
exit(1); |
|
} |
|
(void)printf("%s", buf); |
|
} |
|
|
|
cleanup() |
|
{ |
|
(void)bzero((char *)&proto_data, sizeof(proto_data)); |
|
(void)bzero((char *)okey, sizeof(okey)); |
|
(void)bzero((char *)osched, sizeof(osched)); |
|
(void)bzero((char *)random_schedule, sizeof(random_schedule)); |
|
} |
|
|
|
static void |
|
finish() |
|
{ |
|
(void)close(sock); |
|
exit(1); |
|
} |
} |
|
|
#endif /* KERBEROS */ |
#endif /* KERBEROS */ |