Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / kauth / user_nt.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <roken.h>
14
15 #include <afs/stds.h>
16
17 #include <windows.h>
18 #include <rpc.h>
19 #include <afs/kautils.h>
20 #include <afs/cm.h>
21 #include <afs/cm_config.h>
22 #include <afs/krb.h>
23 #include <afs/krb_prot.h>
24 #include <rx/rxkad.h>
25 #include <crypt.h>
26 #include <hcrypto/des.h>
27
28 int krb_add_host(struct sockaddr_in *server_list_p);
29 static void krb_set_port(long port);
30
31 static long
32 ka_AddHostProc(void *rockp, struct sockaddr_in *addrp, char *namep)
33 {
34 return krb_add_host(addrp);
35 }
36
37 static char bogusReason[100];
38
39 static char *
40 ka_MapKerberosError(int code)
41 {
42 switch (code) {
43 case INTK_BADPW:
44 return "password was incorrect";
45 case KERB_ERR_PRINCIPAL_UNKNOWN:
46 return "user doesn't exist";
47 case KERB_ERR_SERVICE_EXP:
48 return "server and client clocks are badly skewed";
49 case SKDC_RETRY:
50 return "Authentication Server was unavailable";
51 case RD_AP_TIME:
52 return "server and client clocks are badly skewed";
53 default:
54 sprintf(bogusReason, "unknown authentication error %d", code);
55 return bogusReason;
56 }
57 }
58
59 static int krb_get_in_tkt_ext(char *user, char *instance, char *realm,
60 char *service, char *sinstance, int life,
61 struct ktc_encryptionKey *key1,
62 struct ktc_encryptionKey *key2, char **ticketpp,
63 long *ticketLenp,
64 struct ktc_encryptionKey *outKeyp, long *kvnop,
65 long *expp, char **reasonp);
66
67
68 afs_int32
69 ka_UserAuthenticateGeneral(afs_int32 flags, char *name, char *instance,
70 char *realm, char *password, Date lifetime,
71 afs_int32 * password_expiresP, afs_int32 spare,
72 char **reasonP)
73 {
74 return ka_UserAuthenticateGeneral2(flags, name, instance, realm, password,
75 NULL, lifetime, password_expiresP,
76 spare, reasonP);
77 }
78
79 afs_int32
80 ka_UserAuthenticateGeneral2(afs_int32 flags, char *name, char *instance,
81 char *realm, char *password, char *smbname,
82 Date lifetime, afs_int32 * password_expiresP,
83 afs_int32 spare, char **reasonP)
84 {
85 int code;
86 struct ktc_encryptionKey key1, key2;
87 char *ticket = NULL;
88 int ticketLen;
89 struct ktc_encryptionKey sessionKey;
90 long kvno;
91 long expirationTime;
92 char fullRealm[256];
93 char upperRealm[256];
94 struct servent *sp;
95 int ttl;
96
97 struct ktc_principal server;
98 struct ktc_principal client;
99 struct ktc_token token;
100
101 if (instance == NULL)
102 instance = "";
103 if (lifetime == 0)
104 lifetime = MAXKTCTICKETLIFETIME;
105
106 code = cm_SearchCellRegistry(1, realm, fullRealm, NULL, ka_AddHostProc, NULL);
107 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
108 code = cm_SearchCellFile(realm, fullRealm, ka_AddHostProc, NULL);
109 if (code) {
110 code =
111 cm_SearchCellByDNS(realm, fullRealm, &ttl, ka_AddHostProc, NULL);
112 }
113 if (code) {
114 *reasonP = "specified realm is unknown";
115 return (code);
116 }
117
118 strcpy(upperRealm, fullRealm);
119 _strupr(upperRealm);
120
121 /* encrypt password, both ways */
122 ka_StringToKey(password, upperRealm, &key1);
123 DES_string_to_key(password, &key2);
124
125 /* set port number */
126 sp = getservbyname("kerberos4", "udp");
127 if (!sp)
128 sp = getservbyname("kerberos-iv", "udp");
129 if (!sp)
130 sp = getservbyname("kerberos", "udp");
131 if (sp)
132 krb_set_port(ntohs(sp->s_port));
133
134 *reasonP = NULL;
135 code =
136 krb_get_in_tkt_ext(name, instance, upperRealm, "afs", "", lifetime,
137 &key1, &key2, &ticket, &ticketLen, &sessionKey,
138 &kvno, &expirationTime, reasonP);
139
140 if (code && *reasonP == NULL)
141 *reasonP = ka_MapKerberosError(code);
142
143 if (code)
144 return code;
145
146 strcpy(server.name, "afs");
147 strcpy(server.instance, "");
148 strcpy(server.cell, fullRealm);
149
150 /* Would like to use Vice ID's; using raw names for now. */
151 strcpy(client.name, name);
152 strcpy(client.instance, instance);
153 strcpy(client.cell, upperRealm);
154 if (smbname)
155 strcpy(client.smbname, smbname);
156
157 token.startTime = 0; /* XXX */
158 token.endTime = expirationTime;
159 token.sessionKey = sessionKey;
160 token.kvno = (short)kvno;
161 token.ticketLen = ticketLen;
162 memcpy(token.ticket, ticket, ticketLen);
163
164 code =
165 ktc_SetToken(&server, &token, &client,
166 (flags & KA_USERAUTH_AUTHENT_LOGON) ? AFS_SETTOK_LOGON :
167 0);
168 if (code) {
169 if (code == KTC_NOCM || code == KTC_NOCMRPC)
170 *reasonP = "AFS service may not have started";
171 else if (code == KTC_RPC)
172 *reasonP = "RPC failure in AFS gateway";
173 else if (code == KTC_NOCELL)
174 *reasonP = "unknown cell";
175 else
176 *reasonP = "unknown error";
177 }
178
179 return code;
180 }
181
182 /*
183 * krb_get_in_tkt()
184 *
185 * This code is descended from kerberos files krb_get_in_tkt.c and
186 * send_to_kdc.c, and one.c.
187 */
188
189 /*
190 * definition of variable set to 1.
191 * used in krb_conf.h to determine host byte order.
192 */
193 static int krbONE = 1;
194
195 #define HOST_BYTE_ORDER (* (char *) &krbONE)
196 #define MSB_FIRST 0
197 #define LSB_FIRST 1
198
199 /*
200 * Copyright 1986, 1987, 1988 by the Massachusetts Institute
201 * of Technology.
202 *
203 * For copying and distribution information, please see the file
204 * <mit-cpyright.h>.
205 */
206
207 #include "krb.h"
208
209 static int swap_bytes;
210
211 /*
212 * The kaserver defines these error codes *privately*. So we redefine them
213 * here, with a slight name change to show that they really are kaserver
214 * errors.
215 */
216 #define KERB_KA_ERR_BAD_MSG_TYPE 99
217 #define KERB_KA_ERR_BAD_LIFETIME 98
218 #define KERB_KA_ERR_NONNULL_REALM 97
219 #define KERB_KA_ERR_PKT_LENGTH 96
220 #define KERB_KA_ERR_TEXT_LENGTH 95
221
222 static void
223 swap_u_int32(afs_uint32 * u)
224 {
225 *u = *u >> 24 | (*u & 0x00ff0000) >> 8 | (*u & 0x0000ff00) << 8 | *u <<
226 24;
227 }
228
229 static void
230 swap_u_int16(afs_uint16 * u)
231 {
232 *u = *u >> 8 | *u << 8;
233 }
234
235 int pkt_clen(KTEXT pkt);
236 KTEXT pkt_cipher(KTEXT packet);
237
238 /*
239 * The following routine has been hacked to make it work for two different
240 * possible string-to-key algorithms. This is a minimal displacement
241 * of the code.
242 */
243
244 /*
245 * krb_get_in_tkt() gets a ticket for a given principal to use a given
246 * service and stores the returned ticket and session key for future
247 * use.
248 *
249 * The "user", "instance", and "realm" arguments give the identity of
250 * the client who will use the ticket. The "service" and "sinstance"
251 * arguments give the identity of the server that the client wishes
252 * to use. (The realm of the server is the same as the Kerberos server
253 * to whom the request is sent.) The "life" argument indicates the
254 * desired lifetime of the ticket; the "key_proc" argument is a pointer
255 * to the routine used for getting the client's private key to decrypt
256 * the reply from Kerberos. The "decrypt_proc" argument is a pointer
257 * to the routine used to decrypt the reply from Kerberos; and "arg"
258 * is an argument to be passed on to the "key_proc" routine.
259 *
260 * If all goes well, krb_get_in_tkt() returns INTK_OK, otherwise it
261 * returns an error code: If an AUTH_MSG_ERR_REPLY packet is returned
262 * by Kerberos, then the error code it contains is returned. Other
263 * error codes returned by this routine include INTK_PROT to indicate
264 * wrong protocol version, INTK_BADPW to indicate bad password (if
265 * decrypted ticket didn't make sense), INTK_ERR if the ticket was for
266 * the wrong server or the ticket store couldn't be initialized.
267 *
268 * The format of the message sent to Kerberos is as follows:
269 *
270 * Size Variable Field
271 * ---- -------- -----
272 *
273 * 1 byte KRB_PROT_VERSION protocol version number
274 * 1 byte AUTH_MSG_KDC_REQUEST | message type
275 * HOST_BYTE_ORDER local byte order in lsb
276 * string user client's name
277 * string instance client's instance
278 * string realm client's realm
279 * 4 bytes tlocal.tv_sec timestamp in seconds
280 * 1 byte life desired lifetime
281 * string service service's name
282 * string sinstance service's instance
283 */
284
285 /*
286 * Check_response is a support routine for krb_get_in_tkt.
287 *
288 * Check the response with the supplied key. If the key is apparently
289 * wrong, return INTK_BADPW, otherwise zero.
290 */
291 static
292 check_response(KTEXT rpkt, KTEXT cip, char *service, char *instance,
293 char *realm, struct ktc_encryptionKey *key)
294 {
295 DES_key_schedule key_s;
296 char *ptr;
297 char s_service[SNAME_SZ];
298 char s_instance[INST_SZ];
299 char s_realm[REALM_SZ];
300 int ticket_len;
301
302 if (!key)
303 return -1;
304
305 /* copy information from return packet into "cip" */
306 cip->length = pkt_clen(rpkt);
307 memcpy((char *)(cip->dat), (char *)pkt_cipher(rpkt), cip->length);
308
309 /* decrypt ticket */
310 DES_key_sched((DES_cblock *)key, &key_s);
311 DES_pcbc_encrypt((DES_cblock *) cip->dat, (DES_cblock *) cip->dat,
312 (long)cip->length, &key_s, (DES_cblock *) key, 0);
313
314 /* Skip session key */
315 ptr = (char *)cip->dat + 8;
316
317 /* Check and extract server's name */
318 if ((strlen(ptr) + (ptr - (char *)cip->dat)) > cip->length) {
319 return (INTK_BADPW);
320 }
321
322 (void)strncpy(s_service, ptr, sizeof(s_service) - 1);
323 s_service[sizeof(s_service) - 1] = '\0';
324 ptr += strlen(s_service) + 1;
325
326 /* Check and extract server's instance */
327 if ((strlen(ptr) + (ptr - (char *)cip->dat)) > cip->length) {
328 return (INTK_BADPW);
329 }
330
331 (void)strncpy(s_instance, ptr, sizeof(s_instance) - 1);
332 s_instance[sizeof(s_instance) - 1] = '\0';
333 ptr += strlen(s_instance) + 1;
334
335 /* Check and extract server's realm */
336 if ((strlen(ptr) + (ptr - (char *)cip->dat)) > cip->length) {
337 return (INTK_BADPW);
338 }
339
340 (void)strncpy(s_realm, ptr, sizeof(s_realm));
341 s_realm[sizeof(s_realm) - 1] = '\0';
342 ptr += strlen(s_realm) + 1;
343
344 /* Ignore ticket lifetime, server key version */
345 ptr += 2;
346
347 /* Extract and check ticket length */
348 ticket_len = (unsigned char)*ptr++;
349
350 if ((ticket_len < 0)
351 || ((ticket_len + (ptr - (char *)cip->dat)) > (int)cip->length)) {
352 return (INTK_BADPW);
353 }
354
355 /* Check returned server name, instance, and realm fields */
356 /*
357 * 7/23/98 - Deleting realm check. This allows cell name to differ
358 * from realm name.
359 */
360 #ifdef REALMCHECK
361 if (strcmp(s_service, service) || strcmp(s_instance, instance)
362 || strcmp(s_realm, realm)) {
363 #else
364 if (strcmp(s_service, service) || strcmp(s_instance, instance)) {
365 #endif
366 /* not what we asked for: assume decryption failed */
367 return (INTK_BADPW);
368 }
369
370 return 0;
371 }
372
373 /*
374 * The old kaserver (pre 3.4) returned zero error codes sometimes, leaving
375 * the kaserver error code in a string in the text of the error message.
376 * The new one does the same, but returns KDC_GEN_ERR rather than zero.
377 * We try to extract the actual error code.
378 */
379 static char bogus_kaerror[100];
380 static int
381 kaserver_map_error_code(int code, char *etext, char **reasonP)
382 {
383 if (code == 0 || code == KDC_GEN_ERR) {
384 int mapcode;
385 if (sscanf(etext, "code =%u: ", &mapcode) == 1) {
386 code = mapcode;
387 strcpy(bogus_kaerror, etext);
388 *reasonP = bogus_kaerror;
389 }
390 }
391
392 if (code == 0) {
393 code = KDC_GEN_ERR;
394 }
395
396 return code;
397 }
398
399 static int
400 krb_get_in_tkt_ext(user, instance, realm, service, sinstance, life, key1,
401 key2, ticketpp, ticketLenp, outKeyp, kvnop, expp, reasonp)
402 char *user;
403 char *instance;
404 char *realm;
405 char *service;
406 char *sinstance;
407 int life;
408 struct ktc_encryptionKey *key1, *key2;
409 char **ticketpp;
410 long *ticketLenp;
411 struct ktc_encryptionKey *outKeyp;
412 long *kvnop;
413 long *expp;
414 char **reasonp;
415 {
416 KTEXT_ST pkt_st;
417 KTEXT pkt = &pkt_st; /* Packet to KDC */
418 KTEXT_ST rpkt_st;
419 KTEXT rpkt = &rpkt_st; /* Returned packet */
420 KTEXT_ST cip_st;
421 KTEXT cip = &cip_st; /* Returned Ciphertext */
422 KTEXT_ST tkt_st;
423 KTEXT tkt = &tkt_st; /* Current ticket */
424 DES_cblock ses; /* Session key for tkt */
425 int kvno; /* Kvno for session key */
426 unsigned char *v = pkt->dat; /* Prot vers no */
427 unsigned char *t = (pkt->dat + 1); /* Prot msg type */
428
429 char s_name[SNAME_SZ];
430 char s_instance[INST_SZ];
431 char rlm[REALM_SZ];
432 int lifetime;
433 char kerberos_life;
434 int msg_byte_order;
435 int kerror;
436 char *ptr;
437
438 unsigned long t_local;
439
440 afs_uint32 rep_err_code;
441 afs_uint32 exp_date;
442 afs_uint32 kdc_time;
443
444 /* BUILD REQUEST PACKET */
445
446 /* Set up the fixed part of the packet */
447 *v = (unsigned char)KRB_PROT_VERSION;
448 *t = (unsigned char)AUTH_MSG_KDC_REQUEST;
449 *t |= HOST_BYTE_ORDER;
450
451 /* Now for the variable info */
452 (void)strcpy((char *)(pkt->dat + 2), user); /* aname */
453 pkt->length = 3 + strlen(user);
454 (void)strcpy((char *)(pkt->dat + pkt->length), instance); /* instance */
455 pkt->length += 1 + strlen(instance);
456 (void)strcpy((char *)(pkt->dat + pkt->length), realm); /* realm */
457 pkt->length += 1 + strlen(realm);
458
459 #ifndef WIN32
460 (void)gettimeofday(&t_local, NULL);
461 #else /* WIN32 */
462 t_local = time((void *)0);
463 #endif /* WIN32 */
464 /* timestamp */
465 memcpy((char *)(pkt->dat + pkt->length), (char *)&(t_local), 4);
466 pkt->length += 4;
467
468 if (life == 0) {
469 kerberos_life = DEFAULT_TKT_LIFE;
470 } else {
471 kerberos_life = time_to_life(0, life);
472 if (kerberos_life == 0) {
473 kerberos_life = DEFAULT_TKT_LIFE;
474 }
475 }
476
477 *(pkt->dat + (pkt->length)++) = kerberos_life;
478 (void)strcpy((char *)(pkt->dat + pkt->length), service);
479 pkt->length += 1 + strlen(service);
480 (void)strcpy((char *)(pkt->dat + pkt->length), sinstance);
481
482 pkt->length += 1 + strlen(sinstance);
483
484 rpkt->length = 0;
485
486 /* SEND THE REQUEST AND RECEIVE THE RETURN PACKET */
487
488 if (kerror = send_to_kdc(pkt, rpkt)) {
489 return (kerror);
490 }
491
492 /* check packet version of the returned packet */
493 if (pkt_version(rpkt) != KRB_PROT_VERSION)
494 return (INTK_PROT);
495
496 /* Check byte order */
497 msg_byte_order = pkt_msg_type(rpkt) & 1;
498 swap_bytes = 0;
499 if (msg_byte_order != HOST_BYTE_ORDER) {
500 swap_bytes++;
501 }
502
503 switch (pkt_msg_type(rpkt) & ~1) {
504 case AUTH_MSG_KDC_REPLY:
505 break;
506 case AUTH_MSG_ERR_REPLY:
507 memcpy((char *)&rep_err_code, pkt_err_code(rpkt), 4);
508 if (swap_bytes)
509 swap_u_int32(&rep_err_code);
510 /* kaservers return bogus error codes in different ways, so map it
511 * from the error text if this is the case */
512 return kaserver_map_error_code(rep_err_code, pkt_err_text(rpkt),
513 reasonp);
514
515 default:
516 return (INTK_PROT);
517 }
518
519 /* get the principal's expiration date */
520 memcpy((char *)&exp_date, pkt_x_date(rpkt), sizeof(exp_date));
521 if (swap_bytes)
522 swap_u_int32(&exp_date);
523
524 /* Extract length. This will be re-extracted in check_response, below */
525 cip->length = pkt_clen(rpkt);
526
527 /* Length of zero seems to correspond to no principal (with kaserver) */
528 if (cip->length == 0) {
529 return (KERB_ERR_PRINCIPAL_UNKNOWN);
530 }
531
532 if ((cip->length < 0) || (cip->length > sizeof(cip->dat))) {
533 return (INTK_ERR); /* no appropriate error code
534 * currently defined for INTK_ */
535 }
536
537 /*
538 * Check the response against both possible keys, and use the one
539 * that works.
540 */
541 if (check_response(rpkt, cip, service, sinstance, realm, key1)
542 && check_response(rpkt, cip, service, sinstance, realm, key2)) {
543 return INTK_BADPW;
544 }
545
546 /*
547 * EXTRACT INFORMATION FROM RETURN PACKET
548 *
549 * Some of the fields, below are already checked for integrity by
550 * check_response.
551 */
552 ptr = (char *)cip->dat;
553
554 /* extract session key */
555 memcpy((char *)ses, ptr, 8);
556 ptr += 8;
557
558 /* extract server's name */
559 (void)strncpy(s_name, ptr, sizeof(s_name) - 1);
560 s_name[sizeof(s_name) - 1] = '\0';
561 ptr += strlen(s_name) + 1;
562
563 /* extract server's instance */
564 (void)strncpy(s_instance, ptr, sizeof(s_instance) - 1);
565 s_instance[sizeof(s_instance) - 1] = '\0';
566 ptr += strlen(s_instance) + 1;
567
568 /* extract server's realm */
569 (void)strncpy(rlm, ptr, sizeof(rlm));
570 rlm[sizeof(rlm) - 1] = '\0';
571 ptr += strlen(rlm) + 1;
572
573 /* extract ticket lifetime, server key version, ticket length */
574 /* be sure to avoid sign extension on lifetime! */
575 lifetime = (unsigned char)ptr[0];
576 kvno = (unsigned char)ptr[1];
577 tkt->length = (unsigned char)ptr[2];
578 ptr += 3;
579
580 /* extract ticket itself */
581 memcpy((char *)(tkt->dat), ptr, tkt->length);
582 ptr += tkt->length;
583
584 /* check KDC time stamp */
585 memcpy((char *)&kdc_time, ptr, 4); /* Time (coarse) */
586 if (swap_bytes)
587 swap_u_int32(&kdc_time);
588
589 ptr += 4;
590
591 t_local = time((void *)0);
592 if (abs((int)(t_local - kdc_time)) > CLOCK_SKEW) {
593 return (RD_AP_TIME); /* XXX should probably be better
594 * code */
595 }
596
597 /* copy out results; if *ticketpp is non-null, the caller has already
598 * allocated the buffer for us.
599 */
600 memcpy(outKeyp, ses, sizeof(struct ktc_encryptionKey));
601 if (*ticketpp == NULL) {
602 *ticketpp = malloc(tkt->length);
603 } else if (tkt->length > (unsigned long)*ticketLenp)
604 return -1;
605 *ticketLenp = tkt->length;
606 memcpy(*ticketpp, tkt->dat, tkt->length);
607 *kvnop = kvno;
608 if (expp)
609 *expp = life_to_time(kdc_time, (char)lifetime);
610
611 return (INTK_OK); /* this is zero */
612 }
613
614 /*
615 *
616 * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
617 *
618 * For copying and distribution information, please see the file
619 * <mit-cpyright.h>.
620 */
621
622 #define S_AD_SZ sizeof(struct sockaddr_in)
623
624 static int krb_debug;
625
626 /* CLIENT_KRB_TIMEOUT indicates the time to wait before
627 * retrying a server. It's defined in "krb.h".
628 */
629 static struct timeval timeout = { CLIENT_KRB_TIMEOUT, 0 };
630 static char *prog = "dm";
631 static send_recv();
632
633 /*
634 * This file contains two routines, send_to_kdc() and send_recv().
635 * send_recv() is a static routine used by send_to_kdc().
636 */
637
638 /*
639 * send_to_kdc() sends a message to the Kerberos authentication
640 * server(s) in the given realm and returns the reply message.
641 * The "pkt" argument points to the message to be sent to Kerberos;
642 * the "rpkt" argument will be filled in with Kerberos' reply.
643 * The "realm" argument indicates the realm of the Kerberos server(s)
644 * to transact with. If the realm is null, the local realm is used.
645 *
646 * If more than one Kerberos server is known for a given realm,
647 * different servers will be queried until one of them replies.
648 * Several attempts (retries) are made for each server before
649 * giving up entirely.
650 *
651 * If an answer was received from a Kerberos host, KSUCCESS is
652 * returned. The following errors can be returned:
653 *
654 * SKDC_CANT - can't get local realm
655 * - can't find "kerberos" in /etc/services database
656 * - can't open socket
657 * - can't bind socket
658 * - all ports in use
659 * - couldn't find any Kerberos host
660 *
661 * SKDC_RETRY - couldn't get an answer from any Kerberos server,
662 * after several retries
663 */
664
665 typedef struct krb_server {
666 struct krb_server *nextp;
667 struct sockaddr_in addr;
668 } krb_server_t;
669
670 static long krb_udp_port = KRB_PORT; /* In host byte order */
671 static krb_server_t *krb_hosts_p = NULL;
672 static int krb_nhosts = 0;
673
674 static void
675 krb_set_port(long port)
676 {
677 krb_udp_port = port;
678 }
679
680 int
681 krb_add_host(struct sockaddr_in *server_list_p)
682 {
683 krb_server_t *krb_host_p;
684
685 krb_host_p = malloc(sizeof(krb_server_t));
686
687 /* add host to list */
688 krb_host_p->nextp = krb_hosts_p;
689 krb_hosts_p = krb_host_p;
690 krb_nhosts++;
691
692 /* copy in the data */
693 memcpy(&krb_host_p->addr, server_list_p, sizeof(struct sockaddr_in));
694
695 return 0;
696 }
697
698 static
699 send_to_kdc(pkt, rpkt)
700 KTEXT pkt;
701 KTEXT rpkt;
702 {
703 SOCKET f;
704 int retry;
705 int retval;
706 krb_server_t *tsp;
707 struct sockaddr_in to;
708 int timeAvail, timePerIter, numIters;
709
710 memset(&to, 0, sizeof(to));
711 if ((f = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
712 if (krb_debug)
713 fprintf(stderr, "%s: Can't open socket\n", prog);
714 return (SKDC_CANT);
715 }
716 /* from now on, exit through rtn label for cleanup */
717
718 /* compute # of retries */
719 /* The SMB client seems to time out after 60 seconds. */
720 timeAvail = 60;
721 /* Leave ourselves some margin for fooling around
722 * timeAvail -= 10;
723 * /* How long does one iteration take? */
724 timePerIter = krb_nhosts * CLIENT_KRB_TIMEOUT;
725 /* How many iters? */
726 numIters = timeAvail / timePerIter;
727 /* No more than max */
728 if (numIters > CLIENT_KRB_RETRY)
729 numIters = CLIENT_KRB_RETRY;
730 /* At least one */
731 if (numIters < 1)
732 numIters = 1;
733
734 /* retry each host in sequence */
735 for (retry = 0; retry < numIters; ++retry) {
736 for (tsp = krb_hosts_p; tsp; tsp = tsp->nextp) {
737 to = tsp->addr;
738 to.sin_family = AF_INET;
739 to.sin_port = htons(((unsigned short)krb_udp_port));
740 if (send_recv(pkt, rpkt, f, &to)) {
741 retval = KSUCCESS;
742 goto rtn;
743 }
744 }
745 }
746
747 retval = SKDC_RETRY;
748
749 rtn:
750 (void)closesocket(f);
751
752 return (retval);
753 }
754
755 /*
756 * try to send out and receive message.
757 * return 1 on success, 0 on failure
758 */
759
760 static
761 send_recv(pkt, rpkt, f, _to)
762 KTEXT pkt;
763 KTEXT rpkt;
764 SOCKET f;
765 struct sockaddr_in *_to;
766 {
767 fd_set readfds;
768 struct sockaddr_in from;
769 int sin_size;
770 int numsent;
771 int code;
772
773 if (krb_debug) {
774 if (_to->sin_family == AF_INET)
775 printf("Sending message to %s...", inet_ntoa(_to->sin_addr));
776 else
777 printf("Sending message...");
778 (void)fflush(stdout);
779 }
780 if ((numsent =
781 sendto(f, (char *)(pkt->dat), pkt->length, 0, (struct sockaddr *)_to,
782 S_AD_SZ)) != (int)pkt->length) {
783 if (krb_debug)
784 printf("sent only %d/%d\n", numsent, pkt->length);
785 return 0;
786 }
787 if (krb_debug) {
788 printf("Sent\nWaiting for reply...");
789 (void)fflush(stdout);
790 }
791 FD_ZERO(&readfds);
792 FD_SET(f, &readfds);
793 errno = 0;
794 /* select - either recv is ready, or timeout */
795 /* see if timeout or error or wrong descriptor */
796 if (select(f + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout) < 1
797 || !FD_ISSET(f, &readfds)) {
798 if (krb_debug) {
799 fprintf(stderr, "select failed: readfds=%p", readfds);
800 perror("");
801 }
802 return 0;
803 }
804 sin_size = sizeof(from);
805 if ((code =
806 recvfrom(f, (char *)(rpkt->dat), sizeof(rpkt->dat), 0,
807 (struct sockaddr *)&from, &sin_size))
808 < 0) {
809 if (krb_debug)
810 perror("recvfrom");
811 return 0;
812 }
813 if (krb_debug) {
814 printf("received packet from %s\n", inet_ntoa(from.sin_addr));
815 fflush(stdout);
816 }
817 return 1;
818 }
819
820 /*
821 *
822 * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
823 * of Technology.
824 *
825 * For copying and distribution information, please see the file
826 * <mit-copyright.h>.
827 */
828
829 /*
830 * This routine takes a reply packet from the Kerberos ticket-granting
831 * service and returns a pointer to the beginning of the ciphertext in it.
832 *
833 * See "krb_prot.h" for packet format.
834 */
835
836 static KTEXT
837 pkt_cipher(KTEXT packet)
838 {
839 unsigned char *ptr =
840 pkt_a_realm(packet) + 6 + strlen((char *)pkt_a_realm(packet));
841 /* Skip a few more fields */
842 ptr += 3 + 4; /* add 4 for exp_date */
843
844 /* And return the pointer */
845 return ((KTEXT) ptr);
846 }
847
848 /*
849 *
850 * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
851 * of Technology.
852 *
853 * For copying and distribution information, please see the file
854 * <mit-copyright.h>.
855 */
856
857 /*
858 * Given a pointer to an AUTH_MSG_KDC_REPLY packet, return the length of
859 * its ciphertext portion. The external variable "swap_bytes" is assumed
860 * to have been set to indicate whether or not the packet is in local
861 * byte order. pkt_clen() takes this into account when reading the
862 * ciphertext length out of the packet.
863 */
864
865 static int
866 pkt_clen(KTEXT pkt)
867 {
868 afs_uint16 temp;
869
870 /* Start of ticket list */
871 unsigned char *ptr =
872 pkt_a_realm(pkt) + 10 + strlen((char *)pkt_a_realm(pkt));
873
874 /* Finally the length */
875 memcpy((char *)&temp, (char *)(++ptr), 2); /* alignment */
876 if (swap_bytes) {
877 swap_u_int16(&temp);
878 }
879
880 if (krb_debug) {
881 printf("Clen is %d\n", temp);
882 }
883
884 return (temp);
885 }
886
887 /* This defines the Andrew string_to_key function. It accepts a password
888 string as input and converts its via a one-way encryption algorithm to a DES
889 encryption key. It is compatible with the original Andrew authentication
890 service password database. */
891
892 static void
893 Andrew_StringToKey(str, cell, key)
894 char *str;
895 char *cell; /* cell for password */
896 struct ktc_encryptionKey *key;
897 {
898 char password[8 + 1]; /* crypt's limit is 8 chars anyway */
899 int i;
900 int passlen;
901
902 memset(key, 0, sizeof(struct ktc_encryptionKey));
903
904 strncpy(password, cell, 8);
905 passlen = strlen(str);
906 if (passlen > 8)
907 passlen = 8;
908
909 for (i = 0; i < passlen; i++)
910 password[i] ^= str[i];
911
912 for (i = 0; i < 8; i++)
913 if (password[i] == '\0')
914 password[i] = 'X';
915
916 /* crypt only considers the first 8 characters of password but for some
917 * reason returns eleven characters of result (plus the two salt chars). */
918 strncpy((char *)key, (char *)crypt(password, "p1") + 2,
919 sizeof(struct ktc_encryptionKey));
920
921 /* parity is inserted into the LSB so leftshift each byte up one bit. This
922 * allows ascii characters with a zero MSB to retain as much significance
923 * as possible. */
924 {
925 char *keybytes = (char *)key;
926 unsigned int temp;
927
928 for (i = 0; i < 8; i++) {
929 temp = (unsigned int)keybytes[i];
930 keybytes[i] = (unsigned char)(temp << 1);
931 }
932 }
933 DES_fixup_key_parity((DES_cblock *)key);
934 }
935
936
937 static void
938 StringToKey(str, cell, key)
939 char *str;
940 char *cell; /* cell for password */
941 struct ktc_encryptionKey *key;
942 {
943 DES_key_schedule schedule;
944 char temp_key[8];
945 char ivec[8];
946 char password[BUFSIZ];
947 int passlen;
948
949 strncpy(password, str, sizeof(password));
950 if ((passlen = strlen(password)) < sizeof(password) - 1)
951 strncat(password, cell, sizeof(password) - passlen);
952 if ((passlen = strlen(password)) > sizeof(password))
953 passlen = sizeof(password);
954
955 memcpy(ivec, "kerberos", 8);
956 memcpy(temp_key, "kerberos", 8);
957 DES_fixup_key_parity(temp_key);
958 DES_key_sched(temp_key, &schedule);
959 DES_cbc_cksum(password, ivec, passlen, &schedule, ivec);
960
961 memcpy(temp_key, ivec, 8);
962 DES_fixup_key_parity(temp_key);
963 DES_key_sched(temp_key, &schedule);
964 DES_cbc_cksum(password, (DES_cblock *)key, passlen, &schedule, ivec);
965
966 DES_fixup_key_parity((DES_cblock *)key);
967 }