1 /*- 2 * Copyright (c) 1990, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)krb_passwd.c 8.3 (Berkeley) 04/02/94"; 10 #endif /* not lint */ 11 12 #ifdef KERBEROS 13 14 #include <sys/types.h> 15 #include <sys/socket.h> 16 #include <sys/time.h> 17 #include <sys/resource.h> 18 #include <netinet/in.h> 19 #include <kerberosIV/des.h> 20 #include <kerberosIV/krb.h> 21 22 #include <err.h> 23 #include <errno.h> 24 #include <netdb.h> 25 #include <pwd.h> 26 #include <signal.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <unistd.h> 31 32 #include "kpasswd_proto.h" 33 34 #include "extern.h" 35 36 #define PROTO "tcp" 37 38 static void send_update __P((int, char *, char *)); 39 static void recv_ack __P((int)); 40 static void cleanup __P((void)); 41 static void finish __P((void)); 42 43 static struct timeval timeout = { CLIENT_KRB_TIMEOUT, 0 }; 44 static struct kpasswd_data proto_data; 45 static des_cblock okey; 46 static Key_schedule osched; 47 static KTEXT_ST ticket; 48 static Key_schedule random_schedule; 49 static long authopts; 50 static char realm[REALM_SZ], krbhst[MAX_HSTNM]; 51 static int sock; 52 53 int 54 krb_passwd() 55 { 56 struct servent *se; 57 struct hostent *host; 58 struct sockaddr_in sin; 59 CREDENTIALS cred; 60 fd_set readfds; 61 int rval; 62 char pass[_PASSWORD_LEN], password[_PASSWORD_LEN]; 63 static void finish(); 64 65 static struct rlimit rl = { 0, 0 }; 66 67 (void)signal(SIGHUP, SIG_IGN); 68 (void)signal(SIGINT, SIG_IGN); 69 (void)signal(SIGTSTP, SIG_IGN); 70 71 if (setrlimit(RLIMIT_CORE, &rl) < 0) { 72 warn("setrlimit"); 73 return (1); 74 } 75 76 if ((se = getservbyname(SERVICE, PROTO)) == NULL) { 77 warnx("couldn't find entry for service %s/%s", 78 SERVICE, PROTO); 79 return (1); 80 } 81 82 if ((rval = krb_get_lrealm(realm,1)) != KSUCCESS) { 83 warnx("couldn't get local Kerberos realm: %s", 84 krb_err_txt[rval]); 85 return (1); 86 } 87 88 if ((rval = krb_get_krbhst(krbhst, realm, 1)) != KSUCCESS) { 89 warnx("couldn't get Kerberos host: %s", 90 krb_err_txt[rval]); 91 return (1); 92 } 93 94 if ((host = gethostbyname(krbhst)) == NULL) { 95 warnx("couldn't get host entry for krb host %s", 96 krbhst); 97 return (1); 98 } 99 100 sin.sin_family = host->h_addrtype; 101 memmove((char *) &sin.sin_addr, host->h_addr, host->h_length); 102 sin.sin_port = se->s_port; 103 104 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 105 warn("socket"); 106 return (1); 107 } 108 109 if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { 110 warn("connect"); 111 (void)close(sock); 112 return (1); 113 } 114 115 rval = krb_sendauth( 116 authopts, /* NOT mutual */ 117 sock, 118 &ticket, /* (filled in) */ 119 SERVICE, 120 krbhst, /* instance (krbhst) */ 121 realm, /* dest realm */ 122 (u_long) getpid(), /* checksum */ 123 NULL, /* msg data */ 124 NULL, /* credentials */ 125 NULL, /* schedule */ 126 NULL, /* local addr */ 127 NULL, /* foreign addr */ 128 "KPWDV0.1" 129 ); 130 131 if (rval != KSUCCESS) { 132 warnx("Kerberos sendauth error: %s", krb_err_txt[rval]); 133 return (1); 134 } 135 136 krb_get_cred("krbtgt", realm, realm, &cred); 137 138 (void)printf("Changing Kerberos password for %s.%s@%s.\n", 139 cred.pname, cred.pinst, realm); 140 141 if (des_read_pw_string(pass, 142 sizeof(pass)-1, "Old Kerberos password:", 0)) { 143 warnx("error reading old Kerberos password"); 144 return (1); 145 } 146 147 (void)des_string_to_key(pass, okey); 148 (void)des_key_sched(okey, osched); 149 (void)des_set_key(okey, osched); 150 151 /* wait on the verification string */ 152 153 FD_ZERO(&readfds); 154 FD_SET(sock, &readfds); 155 156 rval = 157 select(sock + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout); 158 159 if ((rval < 1) || !FD_ISSET(sock, &readfds)) { 160 if(rval == 0) { 161 warnx("timed out (aborted)"); 162 cleanup(); 163 return (1); 164 } 165 warnx("select failed (aborted)"); 166 cleanup(); 167 return (1); 168 } 169 170 /* read verification string */ 171 172 if (des_read(sock, &proto_data, sizeof(proto_data)) != 173 sizeof(proto_data)) { 174 warnx("couldn't read verification string (aborted)"); 175 cleanup(); 176 return (1); 177 } 178 179 (void)signal(SIGHUP, finish); 180 (void)signal(SIGINT, finish); 181 182 if (strcmp(SECURE_STRING, proto_data.secure_msg) != 0) { 183 cleanup(); 184 /* don't complain loud if user just hit return */ 185 if (pass == NULL || (!*pass)) 186 return (0); 187 (void)fprintf(stderr, "Sorry\n"); 188 return (1); 189 } 190 191 (void)des_key_sched(proto_data.random_key, random_schedule); 192 (void)des_set_key(proto_data.random_key, random_schedule); 193 (void)memset(pass, 0, sizeof(pass)); 194 195 if (des_read_pw_string(pass, 196 sizeof(pass)-1, "New Kerberos password:", 0)) { 197 warnx("error reading new Kerberos password (aborted)"); 198 cleanup(); 199 return (1); 200 } 201 202 if (des_read_pw_string(password, 203 sizeof(password)-1, "Retype new Kerberos password:", 0)) { 204 warnx("error reading new Kerberos password (aborted)"); 205 cleanup(); 206 return (1); 207 } 208 209 if (strcmp(password, pass) != 0) { 210 warnx("password mismatch (aborted)"); 211 cleanup(); 212 return (1); 213 } 214 215 if (strlen(pass) == 0) 216 (void)printf("using NULL password\n"); 217 218 send_update(sock, password, SECURE_STRING); 219 220 /* wait for ACK */ 221 222 FD_ZERO(&readfds); 223 FD_SET(sock, &readfds); 224 225 rval = 226 select(sock + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout); 227 if ((rval < 1) || !FD_ISSET(sock, &readfds)) { 228 if(rval == 0) { 229 warnx("timed out reading ACK (aborted)"); 230 cleanup(); 231 exit(1); 232 } 233 warnx("select failed (aborted)"); 234 cleanup(); 235 exit(1); 236 } 237 recv_ack(sock); 238 cleanup(); 239 return (0); 240 } 241 242 static void 243 send_update(dest, pwd, str) 244 int dest; 245 char *pwd, *str; 246 { 247 static struct update_data ud; 248 249 (void)strncpy(ud.secure_msg, str, _PASSWORD_LEN); 250 (void)strncpy(ud.pw, pwd, sizeof(ud.pw)); 251 if (des_write(dest, &ud, sizeof(ud)) != sizeof(ud)) { 252 warnx("couldn't write pw update (abort)"); 253 memset((char *)&ud, 0, sizeof(ud)); 254 cleanup(); 255 exit(1); 256 } 257 } 258 259 static void 260 recv_ack(remote) 261 int remote; 262 { 263 int cc; 264 char buf[BUFSIZ]; 265 266 cc = des_read(remote, buf, sizeof(buf)); 267 if (cc <= 0) { 268 warnx("error reading acknowledgement (aborted)"); 269 cleanup(); 270 exit(1); 271 } 272 (void)printf("%s", buf); 273 } 274 275 static void 276 cleanup() 277 { 278 279 (void)memset((char *)&proto_data, 0, sizeof(proto_data)); 280 (void)memset((char *)okey, 0, sizeof(okey)); 281 (void)memset((char *)osched, 0, sizeof(osched)); 282 (void)memset((char *)random_schedule, 0, sizeof(random_schedule)); 283 } 284 285 static void 286 finish() 287 { 288 289 (void)close(sock); 290 exit(1); 291 } 292 293 #endif /* KERBEROS */ 294