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