[6380] | 1 | /* |
---|
[6384] | 2 | * This file replaces some of the routines in the Kerberos utilities. |
---|
| 3 | * It is based on the Kerberos library modules: |
---|
| 4 | * send_to_kdc.c |
---|
| 5 | * |
---|
| 6 | * Copyright 1987, 1988, 1992 by the Massachusetts Institute of Technology. |
---|
[6380] | 7 | * |
---|
| 8 | * For copying and distribution information, please see the file |
---|
| 9 | * <mit-copyright.h>. |
---|
| 10 | */ |
---|
| 11 | |
---|
| 12 | #ifndef lint |
---|
| 13 | static char rcsid_send_to_kdc_c[] = |
---|
[6386] | 14 | "$Header: /afs/dev.mit.edu/source/repository/athena/bin/aklog/krb_util.c,v 1.3 1992-12-11 13:48:32 probe Exp $"; |
---|
[6380] | 15 | #endif /* lint */ |
---|
| 16 | |
---|
| 17 | #include <mit-copyright.h> |
---|
| 18 | |
---|
| 19 | #include <krb.h> |
---|
| 20 | #include <stdio.h> |
---|
| 21 | #include <errno.h> |
---|
| 22 | #include <sys/time.h> |
---|
| 23 | #include <sys/types.h> |
---|
| 24 | #ifdef lint |
---|
| 25 | #include <sys/uio.h> /* struct iovec to make lint happy */ |
---|
| 26 | #endif /* lint */ |
---|
| 27 | #include <sys/socket.h> |
---|
| 28 | #include <netinet/in.h> |
---|
| 29 | #include <netdb.h> |
---|
| 30 | #include <strings.h> |
---|
| 31 | |
---|
[6384] | 32 | #include <afs/param.h> |
---|
| 33 | #include <afs/cellconfig.h> |
---|
| 34 | |
---|
[6380] | 35 | #define S_AD_SZ sizeof(struct sockaddr_in) |
---|
| 36 | |
---|
| 37 | extern int errno; |
---|
| 38 | extern int krb_debug; |
---|
| 39 | |
---|
| 40 | extern char *malloc(), *calloc(), *realloc(); |
---|
| 41 | |
---|
| 42 | int krb_udp_port = 0; |
---|
| 43 | |
---|
| 44 | /* CLIENT_KRB_TIMEOUT indicates the time to wait before |
---|
| 45 | * retrying a server. It's defined in "krb.h". |
---|
| 46 | */ |
---|
| 47 | static struct timeval timeout = { CLIENT_KRB_TIMEOUT, 0}; |
---|
| 48 | static char *prog = "send_to_kdc"; |
---|
| 49 | static send_recv(); |
---|
| 50 | |
---|
| 51 | /* |
---|
| 52 | * This file contains two routines, send_to_kdc() and send_recv(). |
---|
| 53 | * send_recv() is a static routine used by send_to_kdc(). |
---|
| 54 | */ |
---|
| 55 | |
---|
| 56 | /* |
---|
| 57 | * send_to_kdc() sends a message to the Kerberos authentication |
---|
| 58 | * server(s) in the given realm and returns the reply message. |
---|
| 59 | * The "pkt" argument points to the message to be sent to Kerberos; |
---|
| 60 | * the "rpkt" argument will be filled in with Kerberos' reply. |
---|
| 61 | * The "realm" argument indicates the realm of the Kerberos server(s) |
---|
| 62 | * to transact with. If the realm is null, the local realm is used. |
---|
| 63 | * |
---|
| 64 | * If more than one Kerberos server is known for a given realm, |
---|
| 65 | * different servers will be queried until one of them replies. |
---|
| 66 | * Several attempts (retries) are made for each server before |
---|
| 67 | * giving up entirely. |
---|
| 68 | * |
---|
| 69 | * If an answer was received from a Kerberos host, KSUCCESS is |
---|
| 70 | * returned. The following errors can be returned: |
---|
| 71 | * |
---|
| 72 | * SKDC_CANT - can't get local realm |
---|
| 73 | * - can't find "kerberos" in /etc/services database |
---|
| 74 | * - can't open socket |
---|
| 75 | * - can't bind socket |
---|
| 76 | * - all ports in use |
---|
| 77 | * - couldn't find any Kerberos host |
---|
| 78 | * |
---|
| 79 | * SKDC_RETRY - couldn't get an answer from any Kerberos server, |
---|
| 80 | * after several retries |
---|
| 81 | */ |
---|
| 82 | |
---|
| 83 | send_to_kdc(pkt,rpkt,realm) |
---|
| 84 | KTEXT pkt; |
---|
| 85 | KTEXT rpkt; |
---|
| 86 | char *realm; |
---|
| 87 | { |
---|
| 88 | int i, f; |
---|
| 89 | int no_host; /* was a kerberos host found? */ |
---|
| 90 | int retry; |
---|
| 91 | int n_hosts; |
---|
| 92 | int retval; |
---|
| 93 | struct sockaddr_in to; |
---|
| 94 | struct hostent *host, *hostlist; |
---|
| 95 | char *cp; |
---|
| 96 | char krbhst[MAX_HSTNM]; |
---|
| 97 | char lrealm[REALM_SZ]; |
---|
| 98 | |
---|
| 99 | /* |
---|
| 100 | * If "realm" is non-null, use that, otherwise get the |
---|
| 101 | * local realm. |
---|
| 102 | */ |
---|
| 103 | if (realm) |
---|
| 104 | (void) strcpy(lrealm, realm); |
---|
| 105 | else |
---|
| 106 | if (krb_get_lrealm(lrealm,1)) { |
---|
| 107 | if (krb_debug) |
---|
| 108 | fprintf(stderr, "%s: can't get local realm\n", prog); |
---|
| 109 | return(SKDC_CANT); |
---|
| 110 | } |
---|
| 111 | if (krb_debug) |
---|
| 112 | printf("lrealm is %s\n", lrealm); |
---|
| 113 | if (krb_udp_port == 0) { |
---|
| 114 | register struct servent *sp; |
---|
| 115 | if ((sp = getservbyname("kerberos","udp")) == 0) { |
---|
| 116 | if (krb_debug) |
---|
| 117 | fprintf(stderr, "%s: Can't get kerberos/udp service\n", |
---|
| 118 | prog); |
---|
| 119 | return(SKDC_CANT); |
---|
| 120 | } |
---|
| 121 | krb_udp_port = sp->s_port; |
---|
| 122 | if (krb_debug) |
---|
| 123 | printf("krb_udp_port is %d\n", krb_udp_port); |
---|
| 124 | } |
---|
| 125 | bzero((char *)&to, S_AD_SZ); |
---|
| 126 | hostlist = (struct hostent *) malloc(sizeof(struct hostent)); |
---|
| 127 | if (!hostlist) |
---|
| 128 | return (/*errno */SKDC_CANT); |
---|
| 129 | if ((f = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { |
---|
| 130 | if (krb_debug) |
---|
| 131 | fprintf(stderr,"%s: Can't open socket\n", prog); |
---|
| 132 | return(SKDC_CANT); |
---|
| 133 | } |
---|
| 134 | /* from now on, exit through rtn label for cleanup */ |
---|
| 135 | |
---|
| 136 | no_host = 1; |
---|
| 137 | /* get an initial allocation */ |
---|
| 138 | n_hosts = 0; |
---|
| 139 | for (i = 1; krb_get_krbhst(krbhst, lrealm, i) == KSUCCESS; ++i) { |
---|
| 140 | if (krb_debug) { |
---|
| 141 | printf("Getting host entry for %s...",krbhst); |
---|
| 142 | (void) fflush(stdout); |
---|
| 143 | } |
---|
| 144 | host = gethostbyname(krbhst); |
---|
| 145 | if (krb_debug) { |
---|
| 146 | printf("%s.\n", |
---|
| 147 | host ? "Got it" : "Didn't get it"); |
---|
| 148 | (void) fflush(stdout); |
---|
| 149 | } |
---|
| 150 | if (!host) |
---|
| 151 | continue; |
---|
| 152 | no_host = 0; /* found at least one */ |
---|
| 153 | n_hosts++; |
---|
| 154 | /* preserve host network address to check later |
---|
| 155 | * (would be better to preserve *all* addresses, |
---|
| 156 | * take care of that later) |
---|
| 157 | */ |
---|
| 158 | hostlist = (struct hostent *) |
---|
| 159 | realloc((char *)hostlist, |
---|
| 160 | (unsigned) |
---|
| 161 | sizeof(struct hostent)*(n_hosts+1)); |
---|
| 162 | if (!hostlist) |
---|
| 163 | return /*errno */SKDC_CANT; |
---|
| 164 | bcopy((char *)host, (char *)&hostlist[n_hosts-1], |
---|
| 165 | sizeof(struct hostent)); |
---|
| 166 | host = &hostlist[n_hosts-1]; |
---|
| 167 | cp = malloc((unsigned)host->h_length); |
---|
| 168 | if (!cp) { |
---|
| 169 | retval = /*errno */SKDC_CANT; |
---|
| 170 | goto rtn; |
---|
| 171 | } |
---|
| 172 | bcopy((char *)host->h_addr, cp, host->h_length); |
---|
| 173 | /* At least Sun OS version 3.2 (or worse) and Ultrix version 2.2 |
---|
| 174 | (or worse) only return one name ... */ |
---|
| 175 | #if !(defined(ULTRIX022) || (defined(SunOS) && SunOS < 40)) |
---|
| 176 | host->h_addr_list = (char **)malloc(sizeof(char *)); |
---|
| 177 | if (!host->h_addr_list) { |
---|
| 178 | retval = /*errno */SKDC_CANT; |
---|
| 179 | goto rtn; |
---|
| 180 | } |
---|
| 181 | #endif /* ULTRIX022 || SunOS */ |
---|
| 182 | host->h_addr = cp; |
---|
| 183 | bzero((char *)&hostlist[n_hosts], |
---|
| 184 | sizeof(struct hostent)); |
---|
| 185 | to.sin_family = host->h_addrtype; |
---|
| 186 | bcopy(host->h_addr, (char *)&to.sin_addr, |
---|
| 187 | host->h_length); |
---|
| 188 | to.sin_port = krb_udp_port; |
---|
| 189 | if (send_recv(pkt, rpkt, f, &to, hostlist)) { |
---|
| 190 | retval = KSUCCESS; |
---|
| 191 | goto rtn; |
---|
| 192 | } |
---|
| 193 | if (krb_debug) { |
---|
| 194 | printf("Timeout, error, or wrong descriptor\n"); |
---|
| 195 | (void) fflush(stdout); |
---|
| 196 | } |
---|
| 197 | } |
---|
| 198 | /* retry each host in sequence */ |
---|
| 199 | for (retry = 0; retry < CLIENT_KRB_RETRY; ++retry) { |
---|
[6386] | 200 | extern struct afsconf_cell ak_cellconfig; |
---|
[6384] | 201 | |
---|
| 202 | if (!no_host) { |
---|
| 203 | for (host = hostlist; host->h_name != (char *)NULL; host++) { |
---|
| 204 | to.sin_family = host->h_addrtype; |
---|
| 205 | bcopy(host->h_addr, (char *)&to.sin_addr, |
---|
| 206 | host->h_length); |
---|
| 207 | if (send_recv(pkt, rpkt, f, &to, hostlist)) { |
---|
| 208 | retval = KSUCCESS; |
---|
| 209 | goto rtn; |
---|
| 210 | } |
---|
| 211 | } |
---|
| 212 | } else { |
---|
[6386] | 213 | to.sin_port = krb_udp_port; |
---|
| 214 | for (i=0; i<ak_cellconfig.numServers; i++) { |
---|
| 215 | to.sin_family = ak_cellconfig.hostAddr[i].sin_family; |
---|
| 216 | to.sin_addr = ak_cellconfig.hostAddr[i].sin_addr; |
---|
[6384] | 217 | if (send_recv(pkt, rpkt, f, &to, (struct hostent *)0)) { |
---|
| 218 | retval = KSUCCESS; |
---|
| 219 | goto rtn; |
---|
| 220 | } |
---|
| 221 | } |
---|
| 222 | } |
---|
[6380] | 223 | } |
---|
| 224 | retval = SKDC_RETRY; |
---|
| 225 | rtn: |
---|
| 226 | (void) close(f); |
---|
| 227 | if (hostlist) { |
---|
| 228 | if (no_host) { |
---|
| 229 | free((char *)hostlist); |
---|
| 230 | } |
---|
| 231 | else { |
---|
| 232 | register struct hostent *hp; |
---|
| 233 | for (hp = hostlist; hp->h_name; hp++) |
---|
| 234 | #if !(defined(ULTRIX022) || (defined(SunOS) && SunOS < 40)) |
---|
| 235 | if (hp->h_addr_list) { |
---|
| 236 | #endif /* ULTRIX022 || SunOS */ |
---|
| 237 | if (hp->h_addr) |
---|
| 238 | free(hp->h_addr); |
---|
| 239 | #if !(defined(ULTRIX022) || (defined(SunOS) && SunOS < 40)) |
---|
| 240 | free((char *)hp->h_addr_list); |
---|
| 241 | } |
---|
| 242 | #endif /* ULTRIX022 || SunOS */ |
---|
| 243 | free((char *)hostlist); |
---|
| 244 | } |
---|
| 245 | } |
---|
| 246 | return(retval); |
---|
| 247 | } |
---|
| 248 | |
---|
| 249 | /* |
---|
| 250 | * try to send out and receive message. |
---|
| 251 | * return 1 on success, 0 on failure |
---|
| 252 | */ |
---|
| 253 | |
---|
| 254 | static send_recv(pkt,rpkt,f,_to,addrs) |
---|
| 255 | KTEXT pkt; |
---|
| 256 | KTEXT rpkt; |
---|
| 257 | int f; |
---|
| 258 | struct sockaddr_in *_to; |
---|
| 259 | struct hostent *addrs; |
---|
| 260 | { |
---|
| 261 | fd_set readfds; |
---|
| 262 | register struct hostent *hp; |
---|
| 263 | struct sockaddr_in from; |
---|
| 264 | int sin_size; |
---|
| 265 | int numsent; |
---|
| 266 | |
---|
| 267 | if (krb_debug) { |
---|
| 268 | if (_to->sin_family == AF_INET) |
---|
| 269 | printf("Sending message to %s...", |
---|
| 270 | inet_ntoa(_to->sin_addr)); |
---|
| 271 | else |
---|
| 272 | printf("Sending message..."); |
---|
| 273 | (void) fflush(stdout); |
---|
| 274 | } |
---|
| 275 | if ((numsent = sendto(f,(char *)(pkt->dat), pkt->length, 0, |
---|
| 276 | (struct sockaddr *)_to, |
---|
| 277 | S_AD_SZ)) != pkt->length) { |
---|
| 278 | if (krb_debug) |
---|
| 279 | printf("sent only %d/%d\n",numsent, pkt->length); |
---|
| 280 | return 0; |
---|
| 281 | } |
---|
| 282 | if (krb_debug) { |
---|
| 283 | printf("Sent\nWaiting for reply..."); |
---|
| 284 | (void) fflush(stdout); |
---|
| 285 | } |
---|
| 286 | FD_ZERO(&readfds); |
---|
| 287 | FD_SET(f, &readfds); |
---|
| 288 | errno = 0; |
---|
| 289 | /* select - either recv is ready, or timeout */ |
---|
| 290 | /* see if timeout or error or wrong descriptor */ |
---|
| 291 | if (select(f + 1, &readfds, (fd_set *)0, (fd_set *)0, &timeout) < 1 |
---|
| 292 | || !FD_ISSET(f, &readfds)) { |
---|
| 293 | if (krb_debug) { |
---|
| 294 | fprintf(stderr, "select failed: readfds=%x", |
---|
| 295 | readfds); |
---|
| 296 | perror(""); |
---|
| 297 | } |
---|
| 298 | return 0; |
---|
| 299 | } |
---|
| 300 | sin_size = sizeof(from); |
---|
| 301 | if (recvfrom(f, (char *)(rpkt->dat), sizeof(rpkt->dat), 0, |
---|
| 302 | (struct sockaddr *)&from, &sin_size) |
---|
| 303 | < 0) { |
---|
| 304 | if (krb_debug) |
---|
| 305 | perror("recvfrom"); |
---|
| 306 | return 0; |
---|
| 307 | } |
---|
| 308 | if (krb_debug) { |
---|
| 309 | printf("received packet from %s\n", inet_ntoa(from.sin_addr)); |
---|
| 310 | fflush(stdout); |
---|
| 311 | } |
---|
[6384] | 312 | if (addrs) { |
---|
| 313 | for (hp = addrs; hp->h_name != (char *)NULL; hp++) { |
---|
| 314 | if (!bcmp(hp->h_addr, (char *)&from.sin_addr.s_addr, |
---|
| 315 | hp->h_length)) { |
---|
| 316 | if (krb_debug) { |
---|
| 317 | printf("Received it\n"); |
---|
| 318 | (void) fflush(stdout); |
---|
| 319 | } |
---|
| 320 | return 1; |
---|
| 321 | } |
---|
| 322 | if (krb_debug) |
---|
| 323 | fprintf(stderr, |
---|
| 324 | "packet not from %x\n", |
---|
| 325 | hp->h_addr); |
---|
| 326 | } |
---|
| 327 | } else { |
---|
| 328 | /* Only permit a response from the host we sent the packet to, |
---|
| 329 | * since we have not specified any alternate addresses. */ |
---|
| 330 | if (!bcmp(&from.sin_addr.s_addr, &_to->sin_addr.s_addr, |
---|
| 331 | sizeof(from.sin_addr.s_addr))) { |
---|
| 332 | if (krb_debug) { |
---|
| 333 | printf("Received it\n"); |
---|
| 334 | (void) fflush(stdout); |
---|
| 335 | } |
---|
| 336 | return 1; |
---|
| 337 | } |
---|
[6380] | 338 | } |
---|
| 339 | if (krb_debug) |
---|
[6384] | 340 | fprintf(stderr, "%s: received packet from wrong host! (%x)\n", |
---|
| 341 | "send_to_kdc(send_rcv)", from.sin_addr.s_addr); |
---|
| 342 | |
---|
[6380] | 343 | return 0; |
---|
| 344 | } |
---|
[6386] | 345 | |
---|
| 346 | char *afs_realm_of_cell(cellconfig) |
---|
| 347 | struct afsconf_cell *cellconfig; |
---|
| 348 | { |
---|
| 349 | char krbhst[MAX_HSTNM]; |
---|
| 350 | static char krbrlm[REALM_SZ+1]; |
---|
| 351 | |
---|
| 352 | if (!cellconfig) |
---|
| 353 | return 0; |
---|
| 354 | |
---|
| 355 | strcpy(krbrlm, (char *)krb_realmofhost(cellconfig->hostName[0])); |
---|
| 356 | if (krb_get_krbhst(krbhst, krbrlm, 1) != KSUCCESS) { |
---|
| 357 | char *s = krbrlm; |
---|
| 358 | char *t = cellconfig->name; |
---|
| 359 | int c; |
---|
| 360 | |
---|
| 361 | while (c = *t++) { |
---|
| 362 | if (islower(c)) c=toupper(c); |
---|
| 363 | *s++ = c; |
---|
| 364 | } |
---|
| 365 | *s++ = 0; |
---|
| 366 | } |
---|
| 367 | return krbrlm; |
---|
| 368 | } |
---|
| 369 | |
---|