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 copyright[] = 10 "@(#) Copyright (c) 1990, 1993\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)kpasswdd.c 8.1 (Berkeley) 06/04/93"; 16 #endif /* not lint */ 17 18 /* 19 * kpasswdd - update a principal's passwd field in the Kerberos 20 * database. Called from inetd. 21 * K. Fall 22 * 12-Dec-88 23 */ 24 25 #include <sys/types.h> 26 #include <sys/time.h> 27 #include <sys/resource.h> 28 #include <sys/signal.h> 29 #include <netinet/in.h> 30 #include <pwd.h> 31 #include <syslog.h> 32 #include <kerberosIV/des.h> 33 #include <kerberosIV/krb.h> 34 #include <kerberosIV/krb_db.h> 35 #include <stdio.h> 36 #include "kpasswd_proto.h" 37 38 static struct kpasswd_data kpwd_data; 39 static des_cblock master_key, key; 40 static Key_schedule master_key_schedule, 41 key_schedule, random_sched; 42 long mkeyversion; 43 AUTH_DAT kdata; 44 static Principal principal_data; 45 static struct update_data ud_data; 46 47 char inst[INST_SZ]; 48 char version[9]; 49 KTEXT_ST ticket; 50 51 char *progname; /* for the library */ 52 53 main() 54 { 55 struct sockaddr_in foreign; 56 int foreign_len = sizeof(foreign); 57 int rval, more; 58 static char name[] = "kpasswdd"; 59 60 static struct rlimit rl = { 0, 0 }; 61 62 progname = name; 63 openlog("kpasswdd", LOG_CONS | LOG_PID, LOG_AUTH); 64 65 signal(SIGHUP, SIG_IGN); 66 signal(SIGINT, SIG_IGN); 67 signal(SIGTSTP, SIG_IGN); 68 if (setrlimit(RLIMIT_CORE, &rl) < 0) { 69 syslog(LOG_ERR, "setrlimit: %m"); 70 exit(1); 71 } 72 73 if (getpeername(0, &foreign, &foreign_len) < 0) { 74 syslog(LOG_ERR,"getpeername: %m"); 75 exit(1); 76 } 77 78 strcpy(inst, "*"); 79 rval = krb_recvauth( 80 0L, /* options--!MUTUAL */ 81 0, /* file desc */ 82 &ticket, /* client's ticket */ 83 SERVICE, /* expected service */ 84 inst, /* expected instance */ 85 &foreign, /* foreign addr */ 86 (struct sockaddr_in *) 0, /* local addr */ 87 &kdata, /* returned krb data */ 88 "", /* service keys file */ 89 (bit_64 *) NULL, /* returned key schedule */ 90 version 91 ); 92 93 94 if (rval != KSUCCESS) { 95 syslog(LOG_NOTICE, "krb_recvauth: %s", krb_err_txt[rval]); 96 cleanup(); 97 exit(1); 98 } 99 100 if (*version == '\0') { 101 /* indicates error on client's side (no tickets, etc.) */ 102 cleanup(); 103 exit(0); 104 } else if (strcmp(version, "KPWDV0.1") != 0) { 105 syslog(LOG_NOTICE, 106 "kpasswdd version conflict (recv'd %s)", 107 version); 108 cleanup(); 109 exit(1); 110 } 111 112 113 /* get master key */ 114 if (kdb_get_master_key(0, master_key, master_key_schedule) != 0) { 115 syslog(LOG_ERR, "couldn't get master key"); 116 cleanup(); 117 exit(1); 118 } 119 120 mkeyversion = kdb_get_master_key(NULL, master_key, master_key_schedule); 121 122 if (mkeyversion < 0) { 123 syslog(LOG_NOTICE, "couldn't verify master key"); 124 cleanup(); 125 exit(1); 126 } 127 128 /* get principal info */ 129 rval = kerb_get_principal( 130 kdata.pname, 131 kdata.pinst, 132 &principal_data, 133 1, 134 &more 135 ); 136 137 if (rval < 0) { 138 syslog(LOG_NOTICE, 139 "error retrieving principal record for %s.%s", 140 kdata.pname, kdata.pinst); 141 cleanup(); 142 exit(1); 143 } 144 145 if (rval != 1 || (more != 0)) { 146 syslog(LOG_NOTICE, "more than 1 dbase entry for %s.%s", 147 kdata.pname, kdata.pinst); 148 cleanup(); 149 exit(1); 150 } 151 152 /* get the user's key */ 153 154 bcopy(&principal_data.key_low, key, 4); 155 bcopy(&principal_data.key_high, ((long *) key) + 1, 4); 156 kdb_encrypt_key(key, key, master_key, master_key_schedule, 157 DECRYPT); 158 key_sched(key, key_schedule); 159 des_set_key(key, key_schedule); 160 161 162 /* get random key and send it over {random} Kperson */ 163 164 random_key(kpwd_data.random_key); 165 strcpy(kpwd_data.secure_msg, SECURE_STRING); 166 if (des_write(0, &kpwd_data, sizeof(kpwd_data)) != sizeof(kpwd_data)) { 167 syslog(LOG_NOTICE, "error writing initial data"); 168 cleanup(); 169 exit(1); 170 } 171 172 bzero(key, sizeof(key)); 173 bzero(key_schedule, sizeof(key_schedule)); 174 175 /* now read update info: { info }Krandom */ 176 177 key_sched(kpwd_data.random_key, random_sched); 178 des_set_key(kpwd_data.random_key, random_sched); 179 if (des_read(0, &ud_data, sizeof(ud_data)) != sizeof(ud_data)) { 180 syslog(LOG_NOTICE, "update aborted"); 181 cleanup(); 182 exit(1); 183 } 184 185 /* validate info string by looking at the embedded string */ 186 187 if (strcmp(ud_data.secure_msg, SECURE_STRING) != 0) { 188 syslog(LOG_NOTICE, "invalid update from %s", 189 inet_ntoa(foreign.sin_addr)); 190 cleanup(); 191 exit(1); 192 } 193 194 /* produce the new key entry in the database { key }Kmaster */ 195 string_to_key(ud_data.pw, key); 196 kdb_encrypt_key(key, key, 197 master_key, master_key_schedule, 198 ENCRYPT); 199 bcopy(key, &principal_data.key_low, 4); 200 bcopy(((long *) key) + 1, 201 &principal_data.key_high, 4); 202 bzero(key, sizeof(key)); 203 principal_data.key_version++; 204 if (kerb_put_principal(&principal_data, 1)) { 205 syslog(LOG_ERR, "couldn't write new record for %s.%s", 206 principal_data.name, principal_data.instance); 207 cleanup(); 208 exit(1); 209 } 210 211 syslog(LOG_NOTICE,"wrote new password field for %s.%s from %s", 212 principal_data.name, 213 principal_data.instance, 214 inet_ntoa(foreign.sin_addr) 215 ); 216 217 send_ack(0, "Update complete.\n"); 218 cleanup(); 219 exit(0); 220 } 221 222 cleanup() 223 { 224 bzero(&kpwd_data, sizeof(kpwd_data)); 225 bzero(master_key, sizeof(master_key)); 226 bzero(master_key_schedule, sizeof(master_key_schedule)); 227 bzero(key, sizeof(key)); 228 bzero(key_schedule, sizeof(key_schedule)); 229 bzero(random_sched, sizeof(random_sched)); 230 bzero(&principal_data, sizeof(principal_data)); 231 bzero(&ud_data, sizeof(ud_data)); 232 } 233 234 send_ack(remote, msg) 235 int remote; 236 char *msg; 237 { 238 int cc; 239 cc = des_write(remote, msg, strlen(msg) + 1); 240 if (cc <= 0) { 241 syslog(LOG_NOTICE, "error writing ack"); 242 cleanup(); 243 exit(1); 244 } 245 } 246