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