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