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>
19 #include <afs/kautils.h>
21 #include <afs/cm_config.h>
23 #include <afs/krb_prot.h>
26 #include <hcrypto/des.h>
28 int krb_add_host(struct sockaddr_in
*server_list_p
);
29 static void krb_set_port(long port
);
32 ka_AddHostProc(void *rockp
, struct sockaddr_in
*addrp
, char *namep
)
34 return krb_add_host(addrp
);
37 static char bogusReason
[100];
40 ka_MapKerberosError(int code
)
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";
50 return "Authentication Server was unavailable";
52 return "server and client clocks are badly skewed";
54 sprintf(bogusReason
, "unknown authentication error %d", code
);
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
,
64 struct ktc_encryptionKey
*outKeyp
, long *kvnop
,
65 long *expp
, char **reasonp
);
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
,
74 return ka_UserAuthenticateGeneral2(flags
, name
, instance
, realm
, password
,
75 NULL
, lifetime
, password_expiresP
,
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
)
86 struct ktc_encryptionKey key1
, key2
;
89 struct ktc_encryptionKey sessionKey
;
97 struct ktc_principal server
;
98 struct ktc_principal client
;
99 struct ktc_token token
;
101 if (instance
== NULL
)
104 lifetime
= MAXKTCTICKETLIFETIME
;
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
);
111 cm_SearchCellByDNS(realm
, fullRealm
, &ttl
, ka_AddHostProc
, NULL
);
114 *reasonP
= "specified realm is unknown";
118 strcpy(upperRealm
, fullRealm
);
121 /* encrypt password, both ways */
122 ka_StringToKey(password
, upperRealm
, &key1
);
123 DES_string_to_key(password
, &key2
);
125 /* set port number */
126 sp
= getservbyname("kerberos4", "udp");
128 sp
= getservbyname("kerberos-iv", "udp");
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
209 static int swap_bytes
;
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
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
223 swap_u_int32(afs_uint32
* u
)
225 *u
= *u
>> 24 | (*u
& 0x00ff0000) >> 8 | (*u
& 0x0000ff00) << 8 | *u
<<
230 swap_u_int16(afs_uint16
* u
)
232 *u
= *u
>> 8 | *u
<< 8;
235 int pkt_clen(KTEXT pkt
);
236 KTEXT
pkt_cipher(KTEXT packet
);
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
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
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.
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.
268 * The format of the message sent to Kerberos is as follows:
270 * Size Variable Field
271 * ---- -------- -----
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
286 * Check_response is a support routine for krb_get_in_tkt.
288 * Check the response with the supplied key. If the key is apparently
289 * wrong, return INTK_BADPW, otherwise zero.
292 check_response(KTEXT rpkt
, KTEXT cip
, char *service
, char *instance
,
293 char *realm
, struct ktc_encryptionKey
*key
)
295 DES_key_schedule key_s
;
297 char s_service
[SNAME_SZ
];
298 char s_instance
[INST_SZ
];
299 char s_realm
[REALM_SZ
];
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
);
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);
314 /* Skip session key */
315 ptr
= (char *)cip
->dat
+ 8;
317 /* Check and extract server's name */
318 if ((strlen(ptr
) + (ptr
- (char *)cip
->dat
)) > cip
->length
) {
322 (void)strncpy(s_service
, ptr
, sizeof(s_service
) - 1);
323 s_service
[sizeof(s_service
) - 1] = '\0';
324 ptr
+= strlen(s_service
) + 1;
326 /* Check and extract server's instance */
327 if ((strlen(ptr
) + (ptr
- (char *)cip
->dat
)) > cip
->length
) {
331 (void)strncpy(s_instance
, ptr
, sizeof(s_instance
) - 1);
332 s_instance
[sizeof(s_instance
) - 1] = '\0';
333 ptr
+= strlen(s_instance
) + 1;
335 /* Check and extract server's realm */
336 if ((strlen(ptr
) + (ptr
- (char *)cip
->dat
)) > cip
->length
) {
340 (void)strncpy(s_realm
, ptr
, sizeof(s_realm
));
341 s_realm
[sizeof(s_realm
) - 1] = '\0';
342 ptr
+= strlen(s_realm
) + 1;
344 /* Ignore ticket lifetime, server key version */
347 /* Extract and check ticket length */
348 ticket_len
= (unsigned char)*ptr
++;
351 || ((ticket_len
+ (ptr
- (char *)cip
->dat
)) > (int)cip
->length
)) {
355 /* Check returned server name, instance, and realm fields */
357 * 7/23/98 - Deleting realm check. This allows cell name to differ
361 if (strcmp(s_service
, service
) || strcmp(s_instance
, instance
)
362 || strcmp(s_realm
, realm
)) {
364 if (strcmp(s_service
, service
) || strcmp(s_instance
, instance
)) {
366 /* not what we asked for: assume decryption failed */
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.
379 static char bogus_kaerror
[100];
381 kaserver_map_error_code(int code
, char *etext
, char **reasonP
)
383 if (code
== 0 || code
== KDC_GEN_ERR
) {
385 if (sscanf(etext
, "code =%u: ", &mapcode
) == 1) {
387 strcpy(bogus_kaerror
, etext
);
388 *reasonP
= bogus_kaerror
;
400 krb_get_in_tkt_ext(user
, instance
, realm
, service
, sinstance
, life
, key1
,
401 key2
, ticketpp
, ticketLenp
, outKeyp
, kvnop
, expp
, reasonp
)
408 struct ktc_encryptionKey
*key1
, *key2
;
411 struct ktc_encryptionKey
*outKeyp
;
417 KTEXT pkt
= &pkt_st
; /* Packet to KDC */
419 KTEXT rpkt
= &rpkt_st
; /* Returned packet */
421 KTEXT cip
= &cip_st
; /* Returned Ciphertext */
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 */
429 char s_name
[SNAME_SZ
];
430 char s_instance
[INST_SZ
];
438 unsigned long t_local
;
440 afs_uint32 rep_err_code
;
444 /* BUILD REQUEST PACKET */
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
;
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
);
460 (void)gettimeofday(&t_local
, NULL
);
462 t_local
= time((void *)0);
465 memcpy((char *)(pkt
->dat
+ pkt
->length
), (char *)&(t_local
), 4);
469 kerberos_life
= DEFAULT_TKT_LIFE
;
471 kerberos_life
= time_to_life(0, life
);
472 if (kerberos_life
== 0) {
473 kerberos_life
= DEFAULT_TKT_LIFE
;
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
);
482 pkt
->length
+= 1 + strlen(sinstance
);
486 /* SEND THE REQUEST AND RECEIVE THE RETURN PACKET */
488 if (kerror
= send_to_kdc(pkt
, rpkt
)) {
492 /* check packet version of the returned packet */
493 if (pkt_version(rpkt
) != KRB_PROT_VERSION
)
496 /* Check byte order */
497 msg_byte_order
= pkt_msg_type(rpkt
) & 1;
499 if (msg_byte_order
!= HOST_BYTE_ORDER
) {
503 switch (pkt_msg_type(rpkt
) & ~1) {
504 case AUTH_MSG_KDC_REPLY
:
506 case AUTH_MSG_ERR_REPLY
:
507 memcpy((char *)&rep_err_code
, pkt_err_code(rpkt
), 4);
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
),
519 /* get the principal's expiration date */
520 memcpy((char *)&exp_date
, pkt_x_date(rpkt
), sizeof(exp_date
));
522 swap_u_int32(&exp_date
);
524 /* Extract length. This will be re-extracted in check_response, below */
525 cip
->length
= pkt_clen(rpkt
);
527 /* Length of zero seems to correspond to no principal (with kaserver) */
528 if (cip
->length
== 0) {
529 return (KERB_ERR_PRINCIPAL_UNKNOWN
);
532 if ((cip
->length
< 0) || (cip
->length
> sizeof(cip
->dat
))) {
533 return (INTK_ERR
); /* no appropriate error code
534 * currently defined for INTK_ */
538 * Check the response against both possible keys, and use the one
541 if (check_response(rpkt
, cip
, service
, sinstance
, realm
, key1
)
542 && check_response(rpkt
, cip
, service
, sinstance
, realm
, key2
)) {
547 * EXTRACT INFORMATION FROM RETURN PACKET
549 * Some of the fields, below are already checked for integrity by
552 ptr
= (char *)cip
->dat
;
554 /* extract session key */
555 memcpy((char *)ses
, ptr
, 8);
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;
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;
568 /* extract server's realm */
569 (void)strncpy(rlm
, ptr
, sizeof(rlm
));
570 rlm
[sizeof(rlm
) - 1] = '\0';
571 ptr
+= strlen(rlm
) + 1;
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];
580 /* extract ticket itself */
581 memcpy((char *)(tkt
->dat
), ptr
, tkt
->length
);
584 /* check KDC time stamp */
585 memcpy((char *)&kdc_time
, ptr
, 4); /* Time (coarse) */
587 swap_u_int32(&kdc_time
);
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
597 /* copy out results; if *ticketpp is non-null, the caller has already
598 * allocated the buffer for us.
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
)
605 *ticketLenp
= tkt
->length
;
606 memcpy(*ticketpp
, tkt
->dat
, tkt
->length
);
609 *expp
= life_to_time(kdc_time
, (char)lifetime
);
611 return (INTK_OK
); /* this is zero */
616 * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
618 * For copying and distribution information, please see the file
622 #define S_AD_SZ sizeof(struct sockaddr_in)
624 static int krb_debug
;
626 /* CLIENT_KRB_TIMEOUT indicates the time to wait before
627 * retrying a server. It's defined in "krb.h".
629 static struct timeval timeout
= { CLIENT_KRB_TIMEOUT
, 0 };
630 static char *prog
= "dm";
634 * This file contains two routines, send_to_kdc() and send_recv().
635 * send_recv() is a static routine used by send_to_kdc().
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.
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.
651 * If an answer was received from a Kerberos host, KSUCCESS is
652 * returned. The following errors can be returned:
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
659 * - couldn't find any Kerberos host
661 * SKDC_RETRY - couldn't get an answer from any Kerberos server,
662 * after several retries
665 typedef struct krb_server
{
666 struct krb_server
*nextp
;
667 struct sockaddr_in addr
;
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;
675 krb_set_port(long port
)
681 krb_add_host(struct sockaddr_in
*server_list_p
)
683 krb_server_t
*krb_host_p
;
685 krb_host_p
= malloc(sizeof(krb_server_t
));
687 /* add host to list */
688 krb_host_p
->nextp
= krb_hosts_p
;
689 krb_hosts_p
= krb_host_p
;
692 /* copy in the data */
693 memcpy(&krb_host_p
->addr
, server_list_p
, sizeof(struct sockaddr_in
));
699 send_to_kdc(pkt
, rpkt
)
707 struct sockaddr_in to
;
708 int timeAvail
, timePerIter
, numIters
;
710 memset(&to
, 0, sizeof(to
));
711 if ((f
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
713 fprintf(stderr
, "%s: Can't open socket\n", prog
);
716 /* from now on, exit through rtn label for cleanup */
718 /* compute # of retries */
719 /* The SMB client seems to time out after 60 seconds. */
721 /* Leave ourselves some margin for fooling around
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
;
734 /* retry each host in sequence */
735 for (retry
= 0; retry
< numIters
; ++retry
) {
736 for (tsp
= krb_hosts_p
; tsp
; tsp
= tsp
->nextp
) {
738 to
.sin_family
= AF_INET
;
739 to
.sin_port
= htons(((unsigned short)krb_udp_port
));
740 if (send_recv(pkt
, rpkt
, f
, &to
)) {
750 (void)closesocket(f
);
756 * try to send out and receive message.
757 * return 1 on success, 0 on failure
761 send_recv(pkt
, rpkt
, f
, _to
)
765 struct sockaddr_in
*_to
;
768 struct sockaddr_in from
;
774 if (_to
->sin_family
== AF_INET
)
775 printf("Sending message to %s...", inet_ntoa(_to
->sin_addr
));
777 printf("Sending message...");
778 (void)fflush(stdout
);
781 sendto(f
, (char *)(pkt
->dat
), pkt
->length
, 0, (struct sockaddr
*)_to
,
782 S_AD_SZ
)) != (int)pkt
->length
) {
784 printf("sent only %d/%d\n", numsent
, pkt
->length
);
788 printf("Sent\nWaiting for reply...");
789 (void)fflush(stdout
);
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
)) {
799 fprintf(stderr
, "select failed: readfds=%p", readfds
);
804 sin_size
= sizeof(from
);
806 recvfrom(f
, (char *)(rpkt
->dat
), sizeof(rpkt
->dat
), 0,
807 (struct sockaddr
*)&from
, &sin_size
))
814 printf("received packet from %s\n", inet_ntoa(from
.sin_addr
));
822 * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
825 * For copying and distribution information, please see the file
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.
833 * See "krb_prot.h" for packet format.
837 pkt_cipher(KTEXT packet
)
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 */
844 /* And return the pointer */
845 return ((KTEXT
) ptr
);
850 * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
853 * For copying and distribution information, please see the file
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.
870 /* Start of ticket list */
872 pkt_a_realm(pkt
) + 10 + strlen((char *)pkt_a_realm(pkt
));
874 /* Finally the length */
875 memcpy((char *)&temp
, (char *)(++ptr
), 2); /* alignment */
881 printf("Clen is %d\n", temp
);
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. */
893 Andrew_StringToKey(str
, cell
, key
)
895 char *cell
; /* cell for password */
896 struct ktc_encryptionKey
*key
;
898 char password
[8 + 1]; /* crypt's limit is 8 chars anyway */
902 memset(key
, 0, sizeof(struct ktc_encryptionKey
));
904 strncpy(password
, cell
, 8);
905 passlen
= strlen(str
);
909 for (i
= 0; i
< passlen
; i
++)
910 password
[i
] ^= str
[i
];
912 for (i
= 0; i
< 8; i
++)
913 if (password
[i
] == '\0')
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
));
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
925 char *keybytes
= (char *)key
;
928 for (i
= 0; i
< 8; i
++) {
929 temp
= (unsigned int)keybytes
[i
];
930 keybytes
[i
] = (unsigned char)(temp
<< 1);
933 DES_fixup_key_parity((DES_cblock
*)key
);
938 StringToKey(str
, cell
, key
)
940 char *cell
; /* cell for password */
941 struct ktc_encryptionKey
*key
;
943 DES_key_schedule schedule
;
946 char password
[BUFSIZ
];
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
);
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
);
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
);
966 DES_fixup_key_parity((DES_cblock
*)key
);