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