2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
21 #include <stdio.h> /* sprintf */
23 #include <afs/kautils.h>
25 #include <afs/cm_config.h>
27 #include <afs/krb_prot.h>
30 #include <hcrypto/des.h>
32 int krb_add_host(struct sockaddr_in *server_list_p);
33 static void krb_set_port(long port);
36 ka_AddHostProc(void *rockp, struct sockaddr_in *addrp, char *namep)
38 return krb_add_host(addrp);
41 static char bogusReason[100];
44 ka_MapKerberosError(int code)
48 return "password was incorrect";
49 case KERB_ERR_PRINCIPAL_UNKNOWN:
50 return "user doesn't exist";
51 case KERB_ERR_SERVICE_EXP:
52 return "server and client clocks are badly skewed";
54 return "Authentication Server was unavailable";
56 return "server and client clocks are badly skewed";
58 sprintf(bogusReason, "unknown authentication error %d", code);
63 static int krb_get_in_tkt_ext(char *user, char *instance, char *realm,
64 char *service, char *sinstance, int life,
65 struct ktc_encryptionKey *key1,
66 struct ktc_encryptionKey *key2, char **ticketpp,
68 struct ktc_encryptionKey *outKeyp, long *kvnop,
69 long *expp, char **reasonp);
73 ka_UserAuthenticateGeneral(afs_int32 flags, char *name, char *instance,
74 char *realm, char *password, Date lifetime,
75 afs_int32 * password_expiresP, afs_int32 spare,
78 return ka_UserAuthenticateGeneral2(flags, name, instance, realm, password,
79 NULL, lifetime, password_expiresP,
84 ka_UserAuthenticateGeneral2(afs_int32 flags, char *name, char *instance,
85 char *realm, char *password, char *smbname,
86 Date lifetime, afs_int32 * password_expiresP,
87 afs_int32 spare, char **reasonP)
90 struct ktc_encryptionKey key1, key2;
93 struct ktc_encryptionKey sessionKey;
101 struct ktc_principal server;
102 struct ktc_principal client;
103 struct ktc_token token;
105 if (instance == NULL)
108 lifetime = MAXKTCTICKETLIFETIME;
110 code = cm_SearchCellRegistry(1, realm, fullRealm, NULL, ka_AddHostProc, NULL);
111 if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
112 code = cm_SearchCellFile(realm, fullRealm, ka_AddHostProc, NULL);
115 cm_SearchCellByDNS(realm, fullRealm, &ttl, ka_AddHostProc, NULL);
118 *reasonP = "specified realm is unknown";
122 strcpy(upperRealm, fullRealm);
125 /* encrypt password, both ways */
126 ka_StringToKey(password, upperRealm, &key1);
127 DES_string_to_key(password, &key2);
129 /* set port number */
130 sp = getservbyname("kerberos", "udp");
132 krb_set_port(ntohs(sp->s_port));
136 krb_get_in_tkt_ext(name, instance, upperRealm, "afs", "", lifetime,
137 &key1, &key2, &ticket, &ticketLen, &sessionKey,
138 &kvno, &expirationTime, reasonP);
140 if (code && *reasonP == NULL)
141 *reasonP = ka_MapKerberosError(code);
146 strcpy(server.name, "afs");
147 strcpy(server.instance, "");
148 strcpy(server.cell, fullRealm);
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);
155 strcpy(client.smbname, smbname);
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);
165 ktc_SetToken(&server, &token, &client,
166 (flags & KA_USERAUTH_AUTHENT_LOGON) ? AFS_SETTOK_LOGON :
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";
176 *reasonP = "unknown error";
185 * This code is descended from kerberos files krb_get_in_tkt.c and
186 * send_to_kdc.c, and one.c.
190 * definition of variable set to 1.
191 * used in krb_conf.h to determine host byte order.
193 static int krbONE = 1;
195 #define HOST_BYTE_ORDER (* (char *) &krbONE)
200 * Copyright 1986, 1987, 1988 by the Massachusetts Institute
203 * For copying and distribution information, please see the file
212 #include <sys/types.h>
213 #include <winsock2.h>
215 static int swap_bytes;
218 * The kaserver defines these error codes *privately*. So we redefine them
219 * here, with a slight name change to show that they really are kaserver
222 #define KERB_KA_ERR_BAD_MSG_TYPE 99
223 #define KERB_KA_ERR_BAD_LIFETIME 98
224 #define KERB_KA_ERR_NONNULL_REALM 97
225 #define KERB_KA_ERR_PKT_LENGTH 96
226 #define KERB_KA_ERR_TEXT_LENGTH 95
229 swap_u_int32(afs_uint32 * u)
231 *u = *u >> 24 | (*u & 0x00ff0000) >> 8 | (*u & 0x0000ff00) << 8 | *u <<
236 swap_u_int16(afs_uint16 * u)
238 *u = *u >> 8 | *u << 8;
241 int pkt_clen(KTEXT pkt);
242 KTEXT pkt_cipher(KTEXT packet);
245 * The following routine has been hacked to make it work for two different
246 * possible string-to-key algorithms. This is a minimal displacement
251 * krb_get_in_tkt() gets a ticket for a given principal to use a given
252 * service and stores the returned ticket and session key for future
255 * The "user", "instance", and "realm" arguments give the identity of
256 * the client who will use the ticket. The "service" and "sinstance"
257 * arguments give the identity of the server that the client wishes
258 * to use. (The realm of the server is the same as the Kerberos server
259 * to whom the request is sent.) The "life" argument indicates the
260 * desired lifetime of the ticket; the "key_proc" argument is a pointer
261 * to the routine used for getting the client's private key to decrypt
262 * the reply from Kerberos. The "decrypt_proc" argument is a pointer
263 * to the routine used to decrypt the reply from Kerberos; and "arg"
264 * is an argument to be passed on to the "key_proc" routine.
266 * If all goes well, krb_get_in_tkt() returns INTK_OK, otherwise it
267 * returns an error code: If an AUTH_MSG_ERR_REPLY packet is returned
268 * by Kerberos, then the error code it contains is returned. Other
269 * error codes returned by this routine include INTK_PROT to indicate
270 * wrong protocol version, INTK_BADPW to indicate bad password (if
271 * decrypted ticket didn't make sense), INTK_ERR if the ticket was for
272 * the wrong server or the ticket store couldn't be initialized.
274 * The format of the message sent to Kerberos is as follows:
276 * Size Variable Field
277 * ---- -------- -----
279 * 1 byte KRB_PROT_VERSION protocol version number
280 * 1 byte AUTH_MSG_KDC_REQUEST | message type
281 * HOST_BYTE_ORDER local byte order in lsb
282 * string user client's name
283 * string instance client's instance
284 * string realm client's realm
285 * 4 bytes tlocal.tv_sec timestamp in seconds
286 * 1 byte life desired lifetime
287 * string service service's name
288 * string sinstance service's instance
292 * Check_response is a support routine for krb_get_in_tkt.
294 * Check the response with the supplied key. If the key is apparently
295 * wrong, return INTK_BADPW, otherwise zero.
298 check_response(KTEXT rpkt, KTEXT cip, char *service, char *instance,
299 char *realm, struct ktc_encryptionKey *key)
301 DES_key_schedule key_s;
303 char s_service[SNAME_SZ];
304 char s_instance[INST_SZ];
305 char s_realm[REALM_SZ];
311 /* copy information from return packet into "cip" */
312 cip->length = pkt_clen(rpkt);
313 memcpy((char *)(cip->dat), (char *)pkt_cipher(rpkt), cip->length);
316 DES_key_sched((DES_cblock *)key, &key_s);
317 DES_pcbc_encrypt((DES_cblock *) cip->dat, (DES_cblock *) cip->dat,
318 (long)cip->length, &key_s, (DES_cblock *) key, 0);
320 /* Skip session key */
321 ptr = (char *)cip->dat + 8;
323 /* Check and extract server's name */
324 if ((strlen(ptr) + (ptr - (char *)cip->dat)) > cip->length) {
328 (void)strncpy(s_service, ptr, sizeof(s_service) - 1);
329 s_service[sizeof(s_service) - 1] = '\0';
330 ptr += strlen(s_service) + 1;
332 /* Check and extract server's instance */
333 if ((strlen(ptr) + (ptr - (char *)cip->dat)) > cip->length) {
337 (void)strncpy(s_instance, ptr, sizeof(s_instance) - 1);
338 s_instance[sizeof(s_instance) - 1] = '\0';
339 ptr += strlen(s_instance) + 1;
341 /* Check and extract server's realm */
342 if ((strlen(ptr) + (ptr - (char *)cip->dat)) > cip->length) {
346 (void)strncpy(s_realm, ptr, sizeof(s_realm));
347 s_realm[sizeof(s_realm) - 1] = '\0';
348 ptr += strlen(s_realm) + 1;
350 /* Ignore ticket lifetime, server key version */
353 /* Extract and check ticket length */
354 ticket_len = (unsigned char)*ptr++;
357 || ((ticket_len + (ptr - (char *)cip->dat)) > (int)cip->length)) {
361 /* Check returned server name, instance, and realm fields */
363 * 7/23/98 - Deleting realm check. This allows cell name to differ
367 if (strcmp(s_service, service) || strcmp(s_instance, instance)
368 || strcmp(s_realm, realm)) {
370 if (strcmp(s_service, service) || strcmp(s_instance, instance)) {
372 /* not what we asked for: assume decryption failed */
380 * The old kaserver (pre 3.4) returned zero error codes sometimes, leaving
381 * the kaserver error code in a string in the text of the error message.
382 * The new one does the same, but returns KDC_GEN_ERR rather than zero.
383 * We try to extract the actual error code.
385 static char bogus_kaerror[100];
387 kaserver_map_error_code(int code, char *etext, char **reasonP)
389 if (code == 0 || code == KDC_GEN_ERR) {
391 if (sscanf(etext, "code =%u: ", &mapcode) == 1) {
393 strcpy(bogus_kaerror, etext);
394 *reasonP = bogus_kaerror;
406 krb_get_in_tkt_ext(user, instance, realm, service, sinstance, life, key1,
407 key2, ticketpp, ticketLenp, outKeyp, kvnop, expp, reasonp)
414 struct ktc_encryptionKey *key1, *key2;
417 struct ktc_encryptionKey *outKeyp;
423 KTEXT pkt = &pkt_st; /* Packet to KDC */
425 KTEXT rpkt = &rpkt_st; /* Returned packet */
427 KTEXT cip = &cip_st; /* Returned Ciphertext */
429 KTEXT tkt = &tkt_st; /* Current ticket */
430 DES_cblock ses; /* Session key for tkt */
431 int kvno; /* Kvno for session key */
432 unsigned char *v = pkt->dat; /* Prot vers no */
433 unsigned char *t = (pkt->dat + 1); /* Prot msg type */
435 char s_name[SNAME_SZ];
436 char s_instance[INST_SZ];
444 unsigned long t_local;
446 afs_uint32 rep_err_code;
450 /* BUILD REQUEST PACKET */
452 /* Set up the fixed part of the packet */
453 *v = (unsigned char)KRB_PROT_VERSION;
454 *t = (unsigned char)AUTH_MSG_KDC_REQUEST;
455 *t |= HOST_BYTE_ORDER;
457 /* Now for the variable info */
458 (void)strcpy((char *)(pkt->dat + 2), user); /* aname */
459 pkt->length = 3 + strlen(user);
460 (void)strcpy((char *)(pkt->dat + pkt->length), instance); /* instance */
461 pkt->length += 1 + strlen(instance);
462 (void)strcpy((char *)(pkt->dat + pkt->length), realm); /* realm */
463 pkt->length += 1 + strlen(realm);
466 (void)gettimeofday(&t_local, NULL);
468 t_local = time((void *)0);
471 memcpy((char *)(pkt->dat + pkt->length), (char *)&(t_local), 4);
475 kerberos_life = DEFAULT_TKT_LIFE;
477 kerberos_life = time_to_life(0, life);
478 if (kerberos_life == 0) {
479 kerberos_life = DEFAULT_TKT_LIFE;
483 *(pkt->dat + (pkt->length)++) = kerberos_life;
484 (void)strcpy((char *)(pkt->dat + pkt->length), service);
485 pkt->length += 1 + strlen(service);
486 (void)strcpy((char *)(pkt->dat + pkt->length), sinstance);
488 pkt->length += 1 + strlen(sinstance);
492 /* SEND THE REQUEST AND RECEIVE THE RETURN PACKET */
494 if (kerror = send_to_kdc(pkt, rpkt)) {
498 /* check packet version of the returned packet */
499 if (pkt_version(rpkt) != KRB_PROT_VERSION)
502 /* Check byte order */
503 msg_byte_order = pkt_msg_type(rpkt) & 1;
505 if (msg_byte_order != HOST_BYTE_ORDER) {
509 switch (pkt_msg_type(rpkt) & ~1) {
510 case AUTH_MSG_KDC_REPLY:
512 case AUTH_MSG_ERR_REPLY:
513 memcpy((char *)&rep_err_code, pkt_err_code(rpkt), 4);
515 swap_u_int32(&rep_err_code);
516 /* kaservers return bogus error codes in different ways, so map it
517 * from the error text if this is the case */
518 return kaserver_map_error_code(rep_err_code, pkt_err_text(rpkt),
525 /* get the principal's expiration date */
526 memcpy((char *)&exp_date, pkt_x_date(rpkt), sizeof(exp_date));
528 swap_u_int32(&exp_date);
530 /* Extract length. This will be re-extracted in check_response, below */
531 cip->length = pkt_clen(rpkt);
533 /* Length of zero seems to correspond to no principal (with kaserver) */
534 if (cip->length == 0) {
535 return (KERB_ERR_PRINCIPAL_UNKNOWN);
538 if ((cip->length < 0) || (cip->length > sizeof(cip->dat))) {
539 return (INTK_ERR); /* no appropriate error code
540 * currently defined for INTK_ */
544 * Check the response against both possible keys, and use the one
547 if (check_response(rpkt, cip, service, sinstance, realm, key1)
548 && check_response(rpkt, cip, service, sinstance, realm, key2)) {
553 * EXTRACT INFORMATION FROM RETURN PACKET
555 * Some of the fields, below are already checked for integrity by
558 ptr = (char *)cip->dat;
560 /* extract session key */
561 memcpy((char *)ses, ptr, 8);
564 /* extract server's name */
565 (void)strncpy(s_name, ptr, sizeof(s_name) - 1);
566 s_name[sizeof(s_name) - 1] = '\0';
567 ptr += strlen(s_name) + 1;
569 /* extract server's instance */
570 (void)strncpy(s_instance, ptr, sizeof(s_instance) - 1);
571 s_instance[sizeof(s_instance) - 1] = '\0';
572 ptr += strlen(s_instance) + 1;
574 /* extract server's realm */
575 (void)strncpy(rlm, ptr, sizeof(rlm));
576 rlm[sizeof(rlm) - 1] = '\0';
577 ptr += strlen(rlm) + 1;
579 /* extract ticket lifetime, server key version, ticket length */
580 /* be sure to avoid sign extension on lifetime! */
581 lifetime = (unsigned char)ptr[0];
582 kvno = (unsigned char)ptr[1];
583 tkt->length = (unsigned char)ptr[2];
586 /* extract ticket itself */
587 memcpy((char *)(tkt->dat), ptr, tkt->length);
590 /* check KDC time stamp */
591 memcpy((char *)&kdc_time, ptr, 4); /* Time (coarse) */
593 swap_u_int32(&kdc_time);
597 t_local = time((void *)0);
598 if (abs((int)(t_local - kdc_time)) > CLOCK_SKEW) {
599 return (RD_AP_TIME); /* XXX should probably be better
603 /* copy out results; if *ticketpp is non-null, the caller has already
604 * allocated the buffer for us.
606 memcpy(outKeyp, ses, sizeof(struct ktc_encryptionKey));
607 if (*ticketpp == NULL) {
608 *ticketpp = malloc(tkt->length);
609 } else if (tkt->length > (unsigned long)*ticketLenp)
611 *ticketLenp = tkt->length;
612 memcpy(*ticketpp, tkt->dat, tkt->length);
615 *expp = life_to_time(kdc_time, (char)lifetime);
617 return (INTK_OK); /* this is zero */
622 * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
624 * For copying and distribution information, please see the file
628 #define S_AD_SZ sizeof(struct sockaddr_in)
630 static int krb_debug;
632 /* CLIENT_KRB_TIMEOUT indicates the time to wait before
633 * retrying a server. It's defined in "krb.h".
635 static struct timeval timeout = { CLIENT_KRB_TIMEOUT, 0 };
636 static char *prog = "dm";
640 * This file contains two routines, send_to_kdc() and send_recv().
641 * send_recv() is a static routine used by send_to_kdc().
645 * send_to_kdc() sends a message to the Kerberos authentication
646 * server(s) in the given realm and returns the reply message.
647 * The "pkt" argument points to the message to be sent to Kerberos;
648 * the "rpkt" argument will be filled in with Kerberos' reply.
649 * The "realm" argument indicates the realm of the Kerberos server(s)
650 * to transact with. If the realm is null, the local realm is used.
652 * If more than one Kerberos server is known for a given realm,
653 * different servers will be queried until one of them replies.
654 * Several attempts (retries) are made for each server before
655 * giving up entirely.
657 * If an answer was received from a Kerberos host, KSUCCESS is
658 * returned. The following errors can be returned:
660 * SKDC_CANT - can't get local realm
661 * - can't find "kerberos" in /etc/services database
662 * - can't open socket
663 * - can't bind socket
665 * - couldn't find any Kerberos host
667 * SKDC_RETRY - couldn't get an answer from any Kerberos server,
668 * after several retries
671 typedef struct krb_server {
672 struct krb_server *nextp;
673 struct sockaddr_in addr;
676 static long krb_udp_port = KRB_PORT; /* In host byte order */
677 static krb_server_t *krb_hosts_p = NULL;
678 static int krb_nhosts = 0;
681 krb_set_port(long port)
687 krb_add_host(struct sockaddr_in *server_list_p)
689 krb_server_t *krb_host_p;
691 krb_host_p = malloc(sizeof(krb_server_t));
693 /* add host to list */
694 krb_host_p->nextp = krb_hosts_p;
695 krb_hosts_p = krb_host_p;
698 /* copy in the data */
699 memcpy(&krb_host_p->addr, server_list_p, sizeof(struct sockaddr_in));
705 send_to_kdc(pkt, rpkt)
713 struct sockaddr_in to;
714 int timeAvail, timePerIter, numIters;
716 memset(&to, 0, sizeof(to));
717 if ((f = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
719 fprintf(stderr, "%s: Can't open socket\n", prog);
722 /* from now on, exit through rtn label for cleanup */
724 /* compute # of retries */
725 /* The SMB client seems to time out after 60 seconds. */
727 /* Leave ourselves some margin for fooling around
729 * /* How long does one iteration take? */
730 timePerIter = krb_nhosts * CLIENT_KRB_TIMEOUT;
731 /* How many iters? */
732 numIters = timeAvail / timePerIter;
733 /* No more than max */
734 if (numIters > CLIENT_KRB_RETRY)
735 numIters = CLIENT_KRB_RETRY;
740 /* retry each host in sequence */
741 for (retry = 0; retry < numIters; ++retry) {
742 for (tsp = krb_hosts_p; tsp; tsp = tsp->nextp) {
744 to.sin_family = AF_INET;
745 to.sin_port = htons(((unsigned short)krb_udp_port));
746 if (send_recv(pkt, rpkt, f, &to)) {
756 (void)closesocket(f);
762 * try to send out and receive message.
763 * return 1 on success, 0 on failure
767 send_recv(pkt, rpkt, f, _to)
771 struct sockaddr_in *_to;
774 struct sockaddr_in from;
780 if (_to->sin_family == AF_INET)
781 printf("Sending message to %s...", inet_ntoa(_to->sin_addr));
783 printf("Sending message...");
784 (void)fflush(stdout);
787 sendto(f, (char *)(pkt->dat), pkt->length, 0, (struct sockaddr *)_to,
788 S_AD_SZ)) != (int)pkt->length) {
790 printf("sent only %d/%d\n", numsent, pkt->length);
794 printf("Sent\nWaiting for reply...");
795 (void)fflush(stdout);
800 /* select - either recv is ready, or timeout */
801 /* see if timeout or error or wrong descriptor */
802 if (select(f + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout) < 1
803 || !FD_ISSET(f, &readfds)) {
805 fprintf(stderr, "select failed: readfds=%p", readfds);
810 sin_size = sizeof(from);
812 recvfrom(f, (char *)(rpkt->dat), sizeof(rpkt->dat), 0,
813 (struct sockaddr *)&from, &sin_size))
820 printf("received packet from %s\n", inet_ntoa(from.sin_addr));
828 * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
831 * For copying and distribution information, please see the file
836 * This routine takes a reply packet from the Kerberos ticket-granting
837 * service and returns a pointer to the beginning of the ciphertext in it.
839 * See "krb_prot.h" for packet format.
843 pkt_cipher(KTEXT packet)
846 pkt_a_realm(packet) + 6 + strlen((char *)pkt_a_realm(packet));
847 /* Skip a few more fields */
848 ptr += 3 + 4; /* add 4 for exp_date */
850 /* And return the pointer */
851 return ((KTEXT) ptr);
856 * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
859 * For copying and distribution information, please see the file
864 * Given a pointer to an AUTH_MSG_KDC_REPLY packet, return the length of
865 * its ciphertext portion. The external variable "swap_bytes" is assumed
866 * to have been set to indicate whether or not the packet is in local
867 * byte order. pkt_clen() takes this into account when reading the
868 * ciphertext length out of the packet.
876 /* Start of ticket list */
878 pkt_a_realm(pkt) + 10 + strlen((char *)pkt_a_realm(pkt));
880 /* Finally the length */
881 memcpy((char *)&temp, (char *)(++ptr), 2); /* alignment */
887 printf("Clen is %d\n", temp);
893 /* This defines the Andrew string_to_key function. It accepts a password
894 string as input and converts its via a one-way encryption algorithm to a DES
895 encryption key. It is compatible with the original Andrew authentication
896 service password database. */
899 Andrew_StringToKey(str, cell, key)
901 char *cell; /* cell for password */
902 struct ktc_encryptionKey *key;
904 char password[8 + 1]; /* crypt's limit is 8 chars anyway */
908 memset(key, 0, sizeof(struct ktc_encryptionKey));
910 strncpy(password, cell, 8);
911 passlen = strlen(str);
915 for (i = 0; i < passlen; i++)
916 password[i] ^= str[i];
918 for (i = 0; i < 8; i++)
919 if (password[i] == '\0')
922 /* crypt only considers the first 8 characters of password but for some
923 * reason returns eleven characters of result (plus the two salt chars). */
924 strncpy((char *)key, (char *)crypt(password, "p1") + 2,
925 sizeof(struct ktc_encryptionKey));
927 /* parity is inserted into the LSB so leftshift each byte up one bit. This
928 * allows ascii characters with a zero MSB to retain as much significance
931 char *keybytes = (char *)key;
934 for (i = 0; i < 8; i++) {
935 temp = (unsigned int)keybytes[i];
936 keybytes[i] = (unsigned char)(temp << 1);
939 DES_fixup_key_parity((DES_cblock *)key);
944 StringToKey(str, cell, key)
946 char *cell; /* cell for password */
947 struct ktc_encryptionKey *key;
949 DES_key_schedule schedule;
952 char password[BUFSIZ];
955 strncpy(password, str, sizeof(password));
956 if ((passlen = strlen(password)) < sizeof(password) - 1)
957 strncat(password, cell, sizeof(password) - passlen);
958 if ((passlen = strlen(password)) > sizeof(password))
959 passlen = sizeof(password);
961 memcpy(ivec, "kerberos", 8);
962 memcpy(temp_key, "kerberos", 8);
963 DES_fixup_key_parity(temp_key);
964 DES_key_sched(temp_key, &schedule);
965 DES_cbc_cksum(password, ivec, passlen, &schedule, ivec);
967 memcpy(temp_key, ivec, 8);
968 DES_fixup_key_parity(temp_key);
969 DES_key_sched(temp_key, &schedule);
970 DES_cbc_cksum(password, (DES_cblock *)key, passlen, &schedule, ivec);
972 DES_fixup_key_parity((DES_cblock *)key);