4 * Copyright 1990,1991 by the Massachusetts Institute of Technology
5 * For distribution and copying rights, see the file "mit-copyright.h"
8 * Copyright (c) 2005, 2006
9 * The Linux Box Corporation
12 * Permission is granted to use, copy, create derivative works
13 * and redistribute this software and such derivative works
14 * for any purpose, so long as the name of the Linux Box
15 * Corporation is not used in any advertising or publicity
16 * pertaining to the use or distribution of this software
17 * without specific, written prior authorization. If the
18 * above copyright notice or any other identification of the
19 * Linux Box Corporation is included in any copy of any
20 * portion of this software, then the disclaimer below must
23 * This software is provided as is, without representation
24 * from the Linux Box Corporation as to its fitness for any
25 * purpose, and without warranty by the Linux Box Corporation
26 * of any kind, either express or implied, including
27 * without limitation the implied warranties of
28 * merchantability and fitness for a particular purpose. The
29 * regents of the Linux Box Corporation shall not be liable
30 * for any damages, including special, indirect, incidental, or
31 * consequential damages, with respect to any claim arising
32 * out of or in connection with the use of the software, even
33 * if it has been or is hereafter advised of the possibility of
37 #include <afsconfig.h>
38 #include <afs/param.h>
46 #include <afs/token.h>
48 #define KERBEROS_APPLE_DEPRECATED(x)
52 #elif HAVE_ET_COM_ERR_H
53 # include <et/com_err.h>
54 #elif HAVE_KRB5_COM_ERR_H
55 # include <krb5/com_err.h>
57 # error No com_err.h? We need some kind of com_err.h
60 #ifndef HAVE_KERBEROSV_HEIM_ERR_H
61 #include <afs/com_err.h>
65 #include <sys/ioccom.h>
69 #include <afs/cellconfig.h>
71 #include <afs/venus.h>
72 #include <afs/ptserver.h>
73 #include <afs/ptuser.h>
74 #include <afs/pterror.h>
75 #include <afs/dirpath.h>
76 #include <afs/afsutil.h>
79 #include "linked_list.h"
81 #ifdef HAVE_KRB5_CREDS_KEYBLOCK
84 #ifdef HAVE_KRB5_CREDS_SESSION
85 #define USING_HEIMDAL 1
91 #ifndef AFS_TRY_FULL_PRINC
92 #define AFS_TRY_FULL_PRINC 1
93 #endif /* AFS_TRY_FULL_PRINC */
95 #define AKLOG_TRYAGAIN -1
96 #define AKLOG_SUCCESS 0
98 #define AKLOG_SOMETHINGSWRONG 2
100 #define AKLOG_KERBEROS 4
101 #define AKLOG_TOKEN 5
102 #define AKLOG_BADPATH 6
114 /* RedHat 4.x doesn't seem to define this */
115 #define MAXSYMLINKS 5
118 #define DIR '/' /* Character that divides directories */
119 #define DIRSTRING "/" /* String form of above */
120 #define VOLMARKER ':' /* Character separating cellname from mntpt */
121 #define VOLMARKERSTRING ":" /* String form of above */
125 char realm
[REALM_SZ
];
128 static krb5_ccache _krb425_ccache
= NULL
;
131 * Why doesn't AFS provide these prototypes?
134 extern int pioctl(char *, afs_int32
, struct ViceIoctl
*, afs_int32
);
140 extern char *afs_realm_of_cell(krb5_context
, struct afsconf_cell
*, int);
141 static int isdir(char *, unsigned char *);
142 static krb5_error_code
get_credv5(krb5_context context
, char *, char *,
143 char *, krb5_creds
**);
144 static int get_user_realm(krb5_context
, char **);
146 #define TRYAGAIN(x) (x == AKLOG_TRYAGAIN || \
147 x == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || \
148 x == KRB5KRB_ERR_GENERIC)
150 #if defined(HAVE_KRB5_PRINC_SIZE) || defined(krb5_princ_size)
152 #define get_princ_str(c, p, n) krb5_princ_component(c, p, n)->data
153 #define get_princ_len(c, p, n) krb5_princ_component(c, p, n)->length
154 #define second_comp(c, p) (krb5_princ_size(c, p) > 1)
155 #define realm_data(c, p) krb5_princ_realm(c, p)->data
156 #define realm_len(c, p) krb5_princ_realm(c, p)->length
158 #elif defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING)
160 #define get_princ_str(c, p, n) krb5_principal_get_comp_string(c, p, n)
161 #define get_princ_len(c, p, n) strlen(krb5_principal_get_comp_string(c, p, n))
162 #define second_comp(c, p) (krb5_principal_get_comp_string(c, p, 1) != NULL)
163 #define realm_data(c, p) krb5_realm_data(krb5_principal_get_realm(c, p))
164 #define realm_len(c, p) krb5_realm_length(krb5_principal_get_realm(c, p))
167 #error "Must have either krb5_princ_size or krb5_principal_get_comp_string"
170 #if !defined(HAVE_KRB5_ENCRYPT_TKT_PART) && defined(HAVE_ENCODE_KRB5_ENC_TKT_PART) && defined(HAVE_KRB5_C_ENCRYPT)
171 extern krb5_error_code
encode_krb5_enc_tkt_part (const krb5_enc_tkt_part
*rep
,
175 krb5_encrypt_tkt_part(krb5_context context
,
176 const krb5_keyblock
*key
,
183 if ((code
= encode_krb5_enc_tkt_part(ticket
->enc_part2
, &data
)))
185 if ((code
= krb5_c_encrypt_length(context
, key
->enctype
,
186 data
->length
, &enclen
)))
188 ticket
->enc_part
.ciphertext
.length
= enclen
;
189 if (!(ticket
->enc_part
.ciphertext
.data
= malloc(enclen
))) {
193 if ((code
= krb5_c_encrypt(context
, key
, KRB5_KEYUSAGE_KDC_REP_TICKET
,
194 0, data
, &ticket
->enc_part
))) {
195 free(ticket
->enc_part
.ciphertext
.data
);
196 ticket
->enc_part
.ciphertext
.data
= 0;
208 #if defined(HAVE_KRB5_CREDS_KEYBLOCK)
210 #define get_cred_keydata(c) c->keyblock.contents
211 #define get_cred_keylen(c) c->keyblock.length
212 #define get_creds_enctype(c) c->keyblock.enctype
214 #elif defined(HAVE_KRB5_CREDS_SESSION)
216 #define get_cred_keydata(c) c->session.keyvalue.data
217 #define get_cred_keylen(c) c->session.keyvalue.length
218 #define get_creds_enctype(c) c->session.keytype
221 #error "Must have either keyblock or session member of krb5_creds"
224 /* MITKerberosShim logs but returns success */
225 #if !defined(HAVE_KRB5_524_CONV_PRINCIPAL) || defined(AFS_DARWIN110_ENV) || (!defined(HAVE_KRB5_524_CONVERT_CREDS) && !defined(HAVE_KRB524_CONVERT_CREDS_KDC))
226 #define HAVE_NO_KRB5_524
227 #elif !defined(HAVE_KRB5_524_CONVERT_CREDS) && defined(HAVE_KRB524_CONVERT_CREDS_KDC)
228 #define krb5_524_convert_creds krb524_convert_creds_kdc
232 #define deref_keyblock_enctype(kb) \
235 #define deref_entry_keyblock(entry) \
238 #define deref_session_key(creds) \
241 #define deref_enc_tkt_addrs(tkt) \
244 #define deref_enc_length(enc) \
245 ((enc)->cipher.length)
247 #define deref_enc_data(enc) \
250 #define krb5_free_keytab_entry_contents krb5_kt_free_entry
253 #define deref_keyblock_enctype(kb) \
256 #define deref_entry_keyblock(entry) \
259 #define deref_session_key(creds) \
262 #define deref_enc_tkt_addrs(tkt) \
265 #define deref_enc_length(enc) \
266 ((enc)->ciphertext.length)
268 #define deref_enc_data(enc) \
269 ((enc)->ciphertext.data)
273 #define deref_entry_enctype(entry) \
274 deref_keyblock_enctype(&deref_entry_keyblock(entry))
277 * Provide a replacement for strerror if we don't have it
280 #ifndef HAVE_STRERROR
281 extern char *sys_errlist
[];
282 #define strerror(x) sys_errlist[x]
283 #endif /* HAVE_STRERROR */
285 static char *progname
= NULL
; /* Name of this program */
286 static int dflag
= FALSE
; /* Give debugging information */
287 static int noauth
= FALSE
; /* If true, don't try to get tokens */
288 static int zsubs
= FALSE
; /* Are we keeping track of zephyr subs? */
289 static int hosts
= FALSE
; /* Are we keeping track of hosts? */
290 static int noprdb
= FALSE
; /* Skip resolving name to id? */
291 static int linked
= FALSE
; /* try for both AFS nodes */
292 static int afssetpag
= FALSE
; /* setpag for AFS */
293 static int force
= FALSE
; /* Bash identical tokens? */
294 static int do524
= FALSE
; /* Should we do 524 instead of rxkad2b? */
295 static char *keytab
= NULL
; /* keytab for akimpersonate */
296 static char *client
= NULL
; /* client principal for akimpersonate */
297 static linked_list zsublist
; /* List of zephyr subscriptions */
298 static linked_list hostlist
; /* List of host addresses */
299 static linked_list authedcells
; /* List of cells already logged to */
301 /* A com_error bodge. The idea here is that this routine lets us lookup
302 * things in the system com_err, if the AFS one just tells us the error
307 redirect_errors(const char *who
, afs_int32 code
, const char *fmt
, va_list ap
)
314 const char *str
= afs_error_message(code
);
315 if (strncmp(str
, "unknown", strlen("unknown")) == 0) {
316 #ifdef HAVE_KRB5_SVC_GET_MSG
317 krb5_svc_get_msg(code
,&str
);
318 #elif defined(HAVE_KRB5_GET_ERROR_MESSAGE)
319 krb5_context context
;
320 krb5_init_context(&context
);
321 str
= krb5_get_error_message(context
, code
);
322 krb5_free_context(context
);
324 ; /* IRIX apparently has neither: use the string we have */
329 #ifdef HAVE_KRB5_SVC_GET_MSG
330 krb5_free_string(str
);
334 vfprintf(stderr
, fmt
, ap
);
341 afs_dprintf(char *fmt
, ...) {
351 copy_cellinfo(cellinfo_t
*cellinfo
)
353 cellinfo_t
*new_cellinfo
;
355 if ((new_cellinfo
= malloc(sizeof(cellinfo_t
))))
356 memcpy(new_cellinfo
, cellinfo
, sizeof(cellinfo_t
));
358 return ((char *)new_cellinfo
);
363 get_cellconfig(const char *config
, char *cell
,
364 struct afsconf_cell
*cellconfig
, char **local_cell
)
366 int status
= AKLOG_SUCCESS
;
367 struct afsconf_dir
*configdir
;
369 memset(cellconfig
, 0, sizeof(*cellconfig
));
371 *local_cell
= malloc(MAXCELLCHARS
);
372 if (*local_cell
== NULL
) {
373 fprintf(stderr
, "%s: can't allocate memory for local cell name\n",
378 if (!(configdir
= afsconf_Open(config
))) {
380 "%s: can't get afs configuration (afsconf_Open(%s))\n",
385 if (cell
!= NULL
&& cell
[0] == '\0') {
386 /* Use the local cell */
390 /* XXX - This function modifies 'cell' by passing it through lcstring */
391 if (afsconf_GetCellInfo(configdir
, cell
, NULL
, cellconfig
)) {
393 fprintf(stderr
, "%s: Can't get information about cell %s.\n",
396 fprintf(stderr
, "%s: Can't get information about the local cell.\n",
400 } else if (afsconf_GetLocalCell(configdir
, *local_cell
, MAXCELLCHARS
)) {
401 fprintf(stderr
, "%s: can't determine local cell.\n", progname
);
405 afsconf_Close(configdir
);
411 extract_realm(krb5_context context
, krb5_principal princ
) {
415 len
= realm_len(context
, princ
);
416 if (len
> REALM_SZ
-1)
419 realm
= malloc(sizeof(char) * (len
+1));
423 strncpy(realm
, realm_data(context
, princ
), len
);
430 get_realm_from_cred(krb5_context context
, krb5_creds
*v5cred
, char **realm
) {
431 #if !defined(HEIMDAL) && defined(HAVE_KRB5_DECODE_TICKET)
432 krb5_error_code code
;
437 code
= krb5_decode_ticket(&v5cred
->ticket
, &ticket
);
441 *realm
= extract_realm(context
, ticket
->server
);
445 krb5_free_ticket(context
, ticket
);
455 * Get a Kerberos service ticket to use as the base of an rxkad token for
459 * An initialized Kerberos v5 context
461 * The realm to look in for the service principal. If NULL, then the
462 * realm is determined from the cell name or the user's credentials
463 * (see below for the heuristics used)
465 * The cell information for the cell to obtain a ticket for
467 * A Kerberos credentials structure containing the ticket acquired
468 * for the cell. This is a dynamically allocated structure, which
469 * should be freed by using the appropriate Kerberos API function.
470 * @param[out] realmUsed
471 * The realm in which the cell's service principal was located. If
472 * unset, then the principal was located in the same realm as the
473 * current user. This is a malloc'd string which should be freed
477 * 0 on success, an error value upon failure
480 * This code tries principals in the following, much debated,
483 * If the realm is specified on the command line we do
484 * - afs/cell@COMMAND-LINE-REALM
485 * - afs@COMMAND-LINE-REALM
488 * - afs/cell@REALM-FROM-USERS-PRINCIPAL
489 * - afs/cell@krb5_get_host_realm(db-server)
490 * Then, if krb5_get_host_realm(db-server) is non-empty
491 * - afs@ krb5_get_host_realm(db-server)
493 * - afs/cell@ upper-case-domain-of-db-server
494 * - afs@ upper-case-domain-of-db-server
496 * In all cases, the 'afs@' variant is only tried where the
497 * cell and the realm match case-insensitively.
501 rxkad_get_ticket(krb5_context context
, char *realm
,
502 struct afsconf_cell
*cell
,
503 krb5_creds
**v5cred
, char **realmUsed
) {
504 char *realm_of_cell
= NULL
;
505 char *realm_of_user
= NULL
;
506 char *realm_from_princ
= NULL
;
512 if ((status
= get_user_realm(context
, &realm_of_user
))) {
513 fprintf(stderr
, "%s: Couldn't determine realm of user:", progname
);
514 afs_com_err(progname
, status
, " while getting realm");
515 status
= AKLOG_KERBEROS
;
522 /* Cell on command line - use that one */
523 if (realm
&& realm
[0]) {
524 realm_of_cell
= realm
;
525 status
= AKLOG_TRYAGAIN
;
526 afs_dprintf("We were told to authenticate to realm %s.\n", realm
);
528 /* Initially, try using afs/cell@USERREALM */
529 afs_dprintf("Trying to authenticate to user's realm %s.\n",
531 realm_of_cell
= realm_of_user
;
532 status
= get_credv5(context
, AFSKEY
, cell
->name
, realm_of_cell
,
535 /* If that failed, try to determine the realm from the name of
536 * one of the DB servers */
537 if (TRYAGAIN(status
)) {
538 realm_of_cell
= afs_realm_of_cell(context
, cell
, FALSE
);
539 if (!realm_of_cell
) {
540 fprintf(stderr
, "%s: Couldn't figure out realm for cell "
541 "%s.\n", progname
, cell
->name
);
545 if (realm_of_cell
[0])
546 afs_dprintf("We've deduced that we need to authenticate"
547 " to realm %s.\n", realm_of_cell
);
549 afs_dprintf("We've deduced that we need to authenticate "
550 "using referrals.\n");
554 if (TRYAGAIN(status
)) {
555 /* If we've got the full-princ-first option, or we're in a
556 * different realm from the cell - use the cell name as the
558 if (AFS_TRY_FULL_PRINC
||
559 strcasecmp(cell
->name
, realm_of_cell
)!=0) {
560 status
= get_credv5(context
, AFSKEY
, cell
->name
,
561 realm_of_cell
, v5cred
);
563 /* If we failed & we've got an empty realm, then try
564 * calling afs_realm_for_cell again. */
565 if (TRYAGAIN(status
) && !realm_of_cell
[0]) {
566 /* This time, get the realm by taking the domain
567 * component of the db server and make it upper case */
568 realm_of_cell
= afs_realm_of_cell(context
, cell
, TRUE
);
569 if (!realm_of_cell
) {
571 "%s: Couldn't figure out realm for cell %s.\n",
572 progname
, cell
->name
);
575 afs_dprintf("We've deduced that we need to authenticate"
576 " to realm %s.\n", realm_of_cell
);
577 status
= get_credv5(context
, AFSKEY
, cell
->name
,
578 realm_of_cell
, v5cred
);
582 /* If the realm and cell name match, then try without an
583 * instance, but only if realm is non-empty */
585 if (TRYAGAIN(status
) &&
586 strcasecmp(cell
->name
, realm_of_cell
) == 0) {
587 status
= get_credv5(context
, AFSKEY
, NULL
, realm_of_cell
,
589 if (!AFS_TRY_FULL_PRINC
&& TRYAGAIN(status
)) {
590 status
= get_credv5(context
, AFSKEY
, cell
->name
,
591 realm_of_cell
, v5cred
);
596 /* Try to find a service principal for this cell.
597 * Some broken MIT libraries return KRB5KRB_AP_ERR_MSG_TYPE upon
598 * the first attempt, so we try twice to be sure */
600 if (status
== KRB5KRB_AP_ERR_MSG_TYPE
&& retry
== 1)
607 afs_dprintf("Kerberos error code returned by get_cred : %d\n", status
);
608 fprintf(stderr
, "%s: Couldn't get %s AFS tickets:\n",
609 progname
, cell
->name
);
610 afs_com_err(progname
, status
, "while getting AFS tickets");
611 #ifdef KRB5_CC_NOT_KTYPE
612 if (status
== KRB5_CC_NOT_KTYPE
) {
613 fprintf(stderr
, "allow_weak_crypto may be required in the Kerberos configuration\n");
616 status
= AKLOG_KERBEROS
;
620 /* If we've got a valid ticket, and we still don't know the realm name
621 * try to figure it out from the contents of the ticket
623 if (strcmp(realm_of_cell
, "") == 0) {
624 status
= get_realm_from_cred(context
, *v5cred
, &realm_from_princ
);
627 "%s: Couldn't decode ticket to determine realm for "
629 progname
, cell
->name
);
631 if (realm_from_princ
)
632 realm_of_cell
= realm_from_princ
;
636 /* If the realm of the user and cell differ, then we need to use the
637 * realm when we later construct the user's principal */
638 if (realm_of_cell
!= NULL
&& strcmp(realm_of_user
, realm_of_cell
) != 0)
639 *realmUsed
= realm_of_user
;
642 if (realm_from_princ
)
643 free(realm_from_princ
);
644 if (realm_of_user
&& *realmUsed
== NULL
)
651 * Build an rxkad token from a Kerberos ticket, using only local tools (that
652 * is, without using a 524 conversion service)
655 * An initialised Kerberos 5 context
657 * A Kerberos credentials structure containing a suitable service ticket
658 * @param[out] tokenPtr
659 * An AFS token structure containing an rxkad token. This is a malloc'd
660 * structure which should be freed by the caller.
661 * @param[out[ userPtr
662 * A string containing the principal of the user to whom the token was
663 * issued. This is a malloc'd block which should be freed by the caller,
667 * 0 on success, an error value upon failure
670 rxkad_build_native_token(krb5_context context
, krb5_creds
*v5cred
,
671 struct ktc_tokenUnion
**tokenPtr
, char **userPtr
) {
672 char username
[BUFSIZ
]="";
673 struct ktc_token token
;
675 #ifdef HAVE_NO_KRB5_524
679 char k4name
[ANAME_SZ
];
680 char k4inst
[INST_SZ
];
681 char k4realm
[REALM_SZ
];
683 void *inkey
= get_cred_keydata(v5cred
);
684 size_t inkey_sz
= get_cred_keylen(v5cred
);
686 afs_dprintf("Using Kerberos V5 ticket natively\n");
691 #ifndef HAVE_NO_KRB5_524
692 status
= krb5_524_conv_principal (context
, v5cred
->client
,
698 afs_com_err(progname
, status
,
699 "while converting principal to Kerberos V4 format");
701 strcpy (username
, k4name
);
703 strcat (username
, ".");
704 strcat (username
, k4inst
);
708 len
= min(get_princ_len(context
, v5cred
->client
, 0),
709 second_comp(context
, v5cred
->client
) ?
710 MAXKTCNAMELEN
- 2 : MAXKTCNAMELEN
- 1);
711 strncpy(username
, get_princ_str(context
, v5cred
->client
, 0), len
);
712 username
[len
] = '\0';
714 if (second_comp(context
, v5cred
->client
)) {
715 strcat(username
, ".");
716 p
= username
+ strlen(username
);
717 len
= min(get_princ_len(context
, v5cred
->client
, 1),
718 MAXKTCNAMELEN
- strlen(username
) - 1);
719 strncpy(p
, get_princ_str(context
, v5cred
->client
, 1), len
);
724 memset(&token
, 0, sizeof(struct ktc_token
));
726 token
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
727 token
.startTime
= v5cred
->times
.starttime
;;
728 token
.endTime
= v5cred
->times
.endtime
;
729 if (tkt_DeriveDesKey(get_creds_enctype(v5cred
), inkey
, inkey_sz
,
730 &token
.sessionKey
) != 0) {
733 token
.ticketLen
= v5cred
->ticket
.length
;
734 memcpy(token
.ticket
, v5cred
->ticket
.data
, token
.ticketLen
);
736 status
= token_importRxkadViceId(tokenPtr
, &token
, 0);
741 if (username
[0] != '\0')
742 *userPtr
= strdup(username
);
748 * Convert a Keberos ticket to an rxkad token, using information obtained
749 * from an external Kerberos 5->4 conversion service. If the code is built
750 * with HAVE_NO_KRB5_524 then this is a stub function which will always
751 * return success without a token.
754 * An initialised Kerberos 5 context
756 * A Kerberos credentials structure containing a suitable service ticket
757 * @param[out] tokenPtr
758 * An AFS token structure containing an rxkad token. This is a malloc'd
759 * structure which should be freed by the caller.
760 * @param[out[ userPtr
761 * A string containing the principal of the user to whom the token was
762 * issued. This is a malloc'd block which should be freed by the caller,
766 * 0 on success, an error value upon failure
769 #ifdef HAVE_NO_KRB5_524
771 rxkad_get_converted_token(krb5_context context
, krb5_creds
*v5cred
,
772 struct ktc_tokenUnion
**tokenPtr
, char **userPtr
) {
780 rxkad_get_converted_token(krb5_context context
, krb5_creds
*v5cred
,
781 struct ktc_tokenUnion
**tokenPtr
, char **userPtr
) {
783 char username
[BUFSIZ
];
784 struct ktc_token token
;
790 afs_dprintf("Using Kerberos 524 translator service\n");
792 status
= krb5_524_convert_creds(context
, v5cred
, &cred
);
795 afs_com_err(progname
, status
, "while converting tickets "
796 "to Kerberos V4 format");
797 return AKLOG_KERBEROS
;
800 strcpy (username
, cred
.pname
);
802 strcat (username
, ".");
803 strcat (username
, cred
.pinst
);
806 memset(&token
, 0, sizeof(struct ktc_token
));
808 token
.kvno
= cred
.kvno
;
809 token
.startTime
= cred
.issue_date
;
811 * It seems silly to go through a bunch of contortions to
812 * extract the expiration time, when the v5 credentials already
813 * has the exact time! Let's use that instead.
815 * Note that this isn't a security hole, as the expiration time
816 * is also contained in the encrypted token
818 token
.endTime
= v5cred
->times
.endtime
;
819 memcpy(&token
.sessionKey
, cred
.session
, 8);
820 token
.ticketLen
= cred
.ticket_st
.length
;
821 memcpy(token
.ticket
, cred
.ticket_st
.dat
, token
.ticketLen
);
823 status
= token_importRxkadViceId(tokenPtr
, &token
, 0);
828 *userPtr
= strdup(username
);
835 * This function gets an rxkad token for a given cell.
838 * An initialized Kerberos v5 context
840 * The cell information for the cell which we're obtaining a token for
842 * The realm to look in for the service principal. If NULL, then the
843 * realm is determined from the cell name or the user's credentials
844 * (see the documentation for rxkad_get_ticket)
846 * The rxkad token produced. This is a malloc'd structure which should
847 * be freed by the caller.
848 * @parma[out] authuser
849 * A string containing the principal of the user to whom the token was
850 * issued. This is a malloc'd block which should be freed by the caller,
852 * @param[out] foreign
853 * Whether the user is considered as 'foreign' to the realm of the cell.
856 * 0 on success, an error value upon failuer
859 rxkad_get_token(krb5_context context
, struct afsconf_cell
*cell
, char *realm
,
860 struct ktc_tokenUnion
**token
, char **authuser
, int *foreign
) {
862 char *realmUsed
= NULL
;
863 char *username
= NULL
;
870 status
= rxkad_get_ticket(context
, realm
, cell
, &v5cred
, &realmUsed
);
875 status
= rxkad_get_converted_token(context
, v5cred
, token
, &username
);
877 status
= rxkad_build_native_token(context
, v5cred
, token
, &username
);
882 /* We now have the username, plus the realm name, so stitch them together
883 * to give us the name that the ptserver will know the user by */
884 if (realmUsed
== NULL
|| username
== NULL
) {
885 *authuser
= username
;
889 if (asprintf(authuser
, "%s@%s", username
, realmUsed
) < 0) {
890 fprintf(stderr
, "%s: Out of memory building PTS name\n", progname
);
908 * Log to a cell. If the cell has already been logged to, return without
909 * doing anything. Otherwise, log to it and mark that it has been logged
913 auth_to_cell(krb5_context context
, const char *config
,
914 char *cell
, char *realm
, char **linkedcell
)
916 int status
= AKLOG_SUCCESS
;
918 char *username
= NULL
; /* To hold client username structure */
919 afs_int32 viceId
; /* AFS uid of user */
921 char *local_cell
= NULL
;
922 struct ktc_tokenUnion
*rxkadToken
= NULL
;
923 struct ktc_setTokenData
*token
;
924 struct ktc_setTokenData
*btoken
= NULL
;
925 struct afsconf_cell cellconf
;
927 /* NULL or empty cell returns information on local cell */
928 if ((status
= get_cellconfig(config
, cell
, &cellconf
, &local_cell
)))
931 if (linkedcell
!= NULL
) {
932 if (cellconf
.linkedCell
!= NULL
) {
933 *linkedcell
= strdup(cellconf
.linkedCell
);
934 if (*linkedcell
== NULL
) {
943 if (ll_string(&authedcells
, ll_s_check
, cellconf
.name
)) {
944 afs_dprintf("Already authenticated to %s (or tried to)\n", cellconf
.name
);
945 status
= AKLOG_SUCCESS
;
950 * Record that we have attempted to log to this cell. We do this
951 * before we try rather than after so that we will not try
952 * and fail repeatedly for one cell.
954 ll_string(&authedcells
, ll_s_add
, cellconf
.name
);
957 * Record this cell in the list of zephyr subscriptions. We may
958 * want zephyr subscriptions even if authentication fails.
959 * If this is done after we attempt to get tokens, aklog -zsubs
960 * can return something different depending on whether or not we
961 * are in -noauth mode.
963 if (ll_string(&zsublist
, ll_s_add
, cellconf
.name
) == LL_FAILURE
) {
965 "%s: failure adding cell %s to zephyr subscriptions list.\n",
966 progname
, cellconf
.name
);
969 if (ll_string(&zsublist
, ll_s_add
, local_cell
) == LL_FAILURE
) {
971 "%s: failure adding cell %s to zephyr subscriptions list.\n",
972 progname
, local_cell
);
977 afs_dprintf("Authenticating to cell %s (server %s).\n", cellconf
.name
,
978 cellconf
.hostName
[0]);
980 token
= token_buildTokenJar(cellconf
.name
);
986 status
= rxkad_get_token(context
, &cellconf
, realm
, &rxkadToken
,
987 &username
, &isForeign
);
991 /* We need to keep the token structure around so that we can stick
992 * the viceId into it (once we know it) */
993 status
= token_addToken(token
, rxkadToken
);
995 afs_dprintf("Add Token failed with %d", status
);
1000 ktc_GetTokenEx(cellconf
.name
, &btoken
) == 0 &&
1001 token_SetsEquivalent(token
, btoken
)) {
1003 token_FreeSet(&btoken
);
1004 afs_dprintf("Identical tokens already exist; skipping.\n");
1005 status
= AKLOG_SUCCESS
;
1010 token_FreeSet(&btoken
);
1016 if (username
== NULL
) {
1017 afs_dprintf("Not resolving name to id\n");
1020 afs_dprintf("Not resolving name %s to id (-noprdb set)\n", username
);
1023 afs_dprintf("About to resolve name %s to id in cell %s.\n", username
,
1026 if (!pr_Initialize (0, AFSDIR_CLIENT_ETC_DIRPATH
, cellconf
.name
))
1027 status
= pr_SNameToId (username
, &viceId
);
1030 afs_dprintf("Error %d\n", status
);
1032 afs_dprintf("Id %d\n", (int) viceId
);
1036 * This code is taken from cklog -- it lets people
1037 * automatically register with the ptserver in foreign cells
1040 #ifdef ALLOW_REGISTER
1041 if ((status
== 0) && (viceId
== ANONYMOUSID
) && isForeign
) {
1042 afs_dprintf("doing first-time registration of %s at %s\n",
1043 username
, cellconf
.name
);
1046 status
= ktc_SetTokenEx(token
);
1048 afs_com_err(progname
, status
,
1049 "while obtaining tokens for cell %s",
1051 status
= AKLOG_TOKEN
;
1055 * In case you're wondering, we don't need to change the
1056 * filename here because we're still connecting to the
1057 * same cell -- we're just using a different authenticat ion
1061 if ((status
= pr_Initialize(1L, AFSDIR_CLIENT_ETC_DIRPATH
,
1063 printf("Error %d\n", status
);
1066 if ((status
= pr_CreateUser(username
, &viceId
))) {
1067 fprintf(stderr
, "%s: %s so unable to create remote PTS "
1068 "user %s in cell %s (status: %d).\n", progname
,
1069 afs_error_message(status
), username
, cellconf
.name
,
1071 viceId
= ANONYMOUSID
;
1073 printf("created cross-cell entry for %s (Id %d) at %s\n",
1074 username
, viceId
, cellconf
.name
);
1077 #endif /* ALLOW_REGISTER */
1079 if ((status
== 0) && (viceId
!= ANONYMOUSID
)) {
1080 status
= token_setRxkadViceId(rxkadToken
, viceId
);
1082 fprintf(stderr
, "Error %d setting rxkad ViceId\n", status
);
1083 status
= AKLOG_SUCCESS
;
1085 token_replaceToken(token
, rxkadToken
);
1091 afs_dprintf("Setting tokens. %s @ %s\n",
1092 username
, cellconf
.name
);
1094 afs_dprintf("Setting tokens for cell %s\n", cellconf
.name
);
1097 #ifndef AFS_AIX51_ENV
1098 /* on AIX 4.1.4 with AFS 3.4a+ if a write is not done before
1099 * this routine, it will not add the token. It is not clear what
1100 * is going on here! So we will do the following operation.
1101 * On AIX 5, it causes the parent program to die, so we won't.
1102 * We don't care about the return value, but need to collect it
1103 * to avoid compiler warnings.
1105 if (write(2,"",0) < 0) {
1106 /* dummy write, don't care */
1109 token_setPag(token
, afssetpag
);
1110 status
= ktc_SetTokenEx(token
);
1112 afs_com_err(progname
, status
, "while setting tokens for cell %s",
1114 status
= AKLOG_TOKEN
;
1118 afs_dprintf("Noauth mode; not authenticating.\n");
1122 token_freeToken(&rxkadToken
);
1134 get_afs_mountpoint(char *file
, char *mountpoint
, int size
)
1137 char V
='V'; /* AFS has problem on Sun with pioctl */
1139 char our_file
[MAXPATHLEN
+ 1];
1141 char *last_component
;
1142 struct ViceIoctl vio
;
1143 char cellname
[BUFSIZ
];
1145 strlcpy(our_file
, file
, sizeof(our_file
));
1147 if ((last_component
= strrchr(our_file
, DIR))) {
1148 *last_component
++ = 0;
1149 parent_dir
= our_file
;
1152 last_component
= our_file
;
1156 memset(cellname
, 0, sizeof(cellname
));
1158 vio
.in
= last_component
;
1159 vio
.in_size
= strlen(last_component
)+1;
1160 vio
.out_size
= size
;
1161 vio
.out
= mountpoint
;
1163 if (!pioctl(parent_dir
, VIOC_AFS_STAT_MT_PT
, &vio
, 0)) {
1164 if (strchr(mountpoint
, VOLMARKER
) == NULL
) {
1166 vio
.in_size
= strlen(file
) + 1;
1167 vio
.out_size
= sizeof(cellname
);
1170 if (!pioctl(file
, VIOC_FILE_CELL_NAME
, &vio
, 1)) {
1171 strlcat(cellname
, VOLMARKERSTRING
, sizeof(cellname
));
1172 strlcat(cellname
, mountpoint
+ 1, sizeof(cellname
));
1173 memset(mountpoint
+ 1, 0, size
- 1);
1174 strcpy(mountpoint
+ 1, cellname
);
1184 * This routine each time it is called returns the next directory
1185 * down a pathname. It resolves all symbolic links. The first time
1186 * it is called, it should be called with the name of the path
1187 * to be descended. After that, it should be called with the arguemnt
1191 next_path(char *origpath
)
1193 static char path
[MAXPATHLEN
+ 1];
1194 static char pathtocheck
[MAXPATHLEN
+ 1];
1196 ssize_t link
; /* Return value from readlink */
1197 char linkbuf
[MAXPATHLEN
+ 1];
1198 char tmpbuf
[MAXPATHLEN
+ 1];
1200 static char *last_comp
; /* last component of directory name */
1201 static char *elast_comp
; /* End of last component */
1205 static int symlinkcount
= 0; /* We can't exceed MAXSYMLINKS */
1207 /* If we are given something for origpath, we are initializing only. */
1209 memset(path
, 0, sizeof(path
));
1210 memset(pathtocheck
, 0, sizeof(pathtocheck
));
1211 strlcpy(path
, origpath
, sizeof(path
));
1217 /* We were not given origpath; find then next path to check */
1219 /* If we've gotten all the way through already, return NULL */
1220 if (last_comp
== NULL
)
1224 while (*last_comp
== DIR)
1225 strncat(pathtocheck
, last_comp
++, 1);
1226 len
= (elast_comp
= strchr(last_comp
, DIR))
1227 ? elast_comp
- last_comp
: strlen(last_comp
);
1228 strncat(pathtocheck
, last_comp
, len
);
1229 memset(linkbuf
, 0, sizeof(linkbuf
));
1230 link
= readlink(pathtocheck
, linkbuf
, sizeof(linkbuf
)-1);
1233 linkbuf
[link
] = '\0'; /* NUL terminate string */
1235 if (++symlinkcount
> MAXSYMLINKS
) {
1236 fprintf(stderr
, "%s: %s\n", progname
, strerror(ELOOP
));
1237 exit(AKLOG_BADPATH
);
1240 memset(tmpbuf
, 0, sizeof(tmpbuf
));
1242 strlcpy(tmpbuf
, elast_comp
, sizeof(tmpbuf
));
1243 if (linkbuf
[0] == DIR) {
1245 * If this is a symbolic link to an absolute path,
1246 * replace what we have by the absolute path.
1248 memset(path
, 0, strlen(path
));
1249 memcpy(path
, linkbuf
, sizeof(linkbuf
));
1250 strcat(path
, tmpbuf
);
1253 memset(pathtocheck
, 0, sizeof(pathtocheck
));
1257 * If this is a symbolic link to a relative path,
1258 * replace only the last component with the link name.
1260 strncpy(last_comp
, linkbuf
, strlen(linkbuf
) + 1);
1261 strcat(path
, tmpbuf
);
1263 if ((t
= strrchr(pathtocheck
, DIR))) {
1265 memset(t
, 0, strlen(t
));
1268 memset(pathtocheck
, 0, sizeof(pathtocheck
));
1272 last_comp
= elast_comp
;
1276 return(pathtocheck
);
1280 add_hosts(char *file
)
1283 char V
= 'V'; /* AFS has problem on SunOS */
1285 struct ViceIoctl vio
;
1286 char outbuf
[BUFSIZ
];
1292 memset(outbuf
, 0, sizeof(outbuf
));
1294 vio
.out_size
= sizeof(outbuf
);
1298 afs_dprintf("Getting list of hosts for %s\n", file
);
1300 /* Don't worry about errors. */
1301 if (!pioctl(file
, VIOCWHEREIS
, &vio
, 1)) {
1302 phosts
= (long *) outbuf
;
1305 * Lists hosts that we care about. If ALLHOSTS is defined,
1306 * then all hosts that you ever may possible go through are
1307 * included in this list. If not, then only hosts that are
1308 * the only ones appear. That is, if a volume you must use
1309 * is replaced on only one server, that server is included.
1310 * If it is replicated on many servers, then none are included.
1311 * This is not perfect, but the result is that people don't
1312 * get subscribed to a lot of instances of FILSRV that they
1313 * probably won't need which reduces the instances of
1314 * people getting messages that don't apply to them.
1317 if (phosts
[1] != '\0')
1320 for (i
= 0; phosts
[i
]; i
++) {
1322 in
.s_addr
= phosts
[i
];
1323 afs_dprintf("Got host %s\n", inet_ntoa(in
));
1324 ll_string(&hostlist
, ll_s_add
, (char *)inet_ntoa(in
));
1326 if (zsubs
&& (hp
=gethostbyaddr((char *) &phosts
[i
],sizeof(long),AF_INET
))) {
1327 afs_dprintf("Got host %s\n", hp
->h_name
);
1328 ll_string(&zsublist
, ll_s_add
, hp
->h_name
);
1335 * This routine descends through a path to a directory, logging to
1336 * every cell it encounters along the way.
1339 auth_to_path(krb5_context context
, const char *config
, char *path
)
1341 int status
= AKLOG_SUCCESS
;
1342 int auth_status
= AKLOG_SUCCESS
;
1345 char pathtocheck
[MAXPATHLEN
+ 1];
1346 char mountpoint
[MAXPATHLEN
+ 1];
1355 strlcpy(pathtocheck
, path
, sizeof(pathtocheck
));
1357 if (getcwd(pathtocheck
, sizeof(pathtocheck
)) == NULL
) {
1358 fprintf(stderr
, "Unable to find current working directory:\n");
1359 fprintf(stderr
, "%s\n", pathtocheck
);
1360 fprintf(stderr
, "Try an absolute pathname.\n");
1361 exit(AKLOG_BADPATH
);
1364 strlcat(pathtocheck
, DIRSTRING
, sizeof(pathtocheck
));
1365 strlcat(pathtocheck
, path
, sizeof(pathtocheck
));
1368 next_path(pathtocheck
);
1370 /* Go on to the next level down the path */
1371 while ((nextpath
= next_path(NULL
))) {
1372 strlcpy(pathtocheck
, nextpath
, sizeof(pathtocheck
));
1373 afs_dprintf("Checking directory %s\n", pathtocheck
);
1375 * If this is an afs mountpoint, determine what cell from
1376 * the mountpoint name which is of the form
1377 * #cellname:volumename or %cellname:volumename.
1379 if (get_afs_mountpoint(pathtocheck
, mountpoint
, sizeof(mountpoint
))) {
1380 /* skip over the '#' or '%' */
1381 cell
= mountpoint
+ 1;
1382 /* Add this (cell:volumename) to the list of zsubs */
1384 ll_string(&zsublist
, ll_s_add
, cell
);
1386 add_hosts(pathtocheck
);
1387 if ((endofcell
= strchr(mountpoint
, VOLMARKER
))) {
1389 auth_status
= auth_to_cell(context
, config
, cell
, NULL
, NULL
);
1391 if (status
== AKLOG_SUCCESS
)
1392 status
= auth_status
;
1393 else if (status
!= auth_status
)
1394 status
= AKLOG_SOMETHINGSWRONG
;
1399 if (isdir(pathtocheck
, &isdirectory
) < 0) {
1401 * If we've logged and still can't stat, there's
1404 fprintf(stderr
, "%s: stat(%s): %s\n", progname
,
1405 pathtocheck
, strerror(errno
));
1406 return(AKLOG_BADPATH
);
1408 else if (! isdirectory
) {
1409 /* Allow only directories */
1410 fprintf(stderr
, "%s: %s: %s\n", progname
, pathtocheck
,
1412 return(AKLOG_BADPATH
);
1422 /* Print usage message and exit */
1426 fprintf(stderr
, "\nUsage: %s %s%s%s\n", progname
,
1427 "[-d] [[-cell | -c] cell [-k krb_realm]] ",
1428 "[[-p | -path] pathname]\n",
1429 " [-zsubs] [-hosts] [-noauth] [-noprdb] [-force] [-setpag] \n"
1431 #ifndef HAVE_NO_KRB5_524
1435 fprintf(stderr
, " -d gives debugging information.\n");
1436 fprintf(stderr
, " krb_realm is the kerberos realm of a cell.\n");
1437 fprintf(stderr
, " pathname is the name of a directory to which ");
1438 fprintf(stderr
, "you wish to authenticate.\n");
1439 fprintf(stderr
, " -zsubs gives zephyr subscription information.\n");
1440 fprintf(stderr
, " -hosts gives host address information.\n");
1441 fprintf(stderr
, " -noauth does not attempt to get tokens.\n");
1442 fprintf(stderr
, " -noprdb means don't try to determine AFS ID.\n");
1443 fprintf(stderr
, " -force means replace identical tickets. \n");
1444 fprintf(stderr
, " -linked means if AFS node is linked, try both. \n");
1445 fprintf(stderr
, " -setpag set the AFS process authentication group.\n");
1446 #ifndef HAVE_NO_KRB5_524
1447 fprintf(stderr
, " -524 means use the 524 converter instead of V5 directly\n");
1449 fprintf(stderr
, " No commandline arguments means ");
1450 fprintf(stderr
, "authenticate to the local cell.\n");
1451 fprintf(stderr
, "\n");
1456 main(int argc
, char *argv
[])
1458 krb5_context context
;
1459 int status
= AKLOG_SUCCESS
;
1461 int somethingswrong
= FALSE
;
1463 cellinfo_t cellinfo
;
1465 extern char *progname
; /* Name of this program */
1467 int cmode
= FALSE
; /* Cellname mode */
1468 int pmode
= FALSE
; /* Path name mode */
1470 char realm
[REALM_SZ
]; /* Kerberos realm of afs server */
1471 char cell
[BUFSIZ
]; /* Cell to which we are authenticating */
1472 char path
[MAXPATHLEN
+ 1]; /* Path length for path mode */
1474 linked_list cells
; /* List of cells to log to */
1475 linked_list paths
; /* List of paths to log to */
1478 const char *config
= AFSDIR_CLIENT_ETC_DIRPATH
;
1480 memset(&cellinfo
, 0, sizeof(cellinfo
));
1482 memset(realm
, 0, sizeof(realm
));
1483 memset(cell
, 0, sizeof(cell
));
1484 memset(path
, 0, sizeof(path
));
1492 /* Store the program name here for error messages */
1493 if ((progname
= strrchr(argv
[0], DIR)))
1498 #if defined(KRB5_PROG_ETYPE_NOSUPP) && !(defined(HAVE_KRB5_ENCTYPE_ENABLE) || defined(HAVE_KRB5_ALLOW_WEAK_CRYPTO))
1500 char *filepath
= NULL
, *newpath
= NULL
;
1501 #ifndef AFS_DARWIN_ENV
1502 char *defaultpath
= "/etc/krb5.conf:/etc/krb5/krb5.conf";
1504 char *defaultpath
= "~/Library/Preferences/edu.mit.Kerberos:/Library/Preferences/edu.mit.Kerberos";
1506 filepath
= getenv("KRB5_CONFIG");
1508 /* only fiddle with KRB5_CONFIG if krb5-weak.conf actually exists */
1509 if (asprintf(&newpath
, "%s/krb5-weak.conf",
1510 AFSDIR_CLIENT_ETC_DIRPATH
) < 0)
1512 if (newpath
!= NULL
&& access(newpath
, R_OK
) == 0) {
1515 if (asprintf(&newpath
, "%s:%s/krb5-weak.conf",
1516 filepath
? filepath
: defaultpath
,
1517 AFSDIR_CLIENT_ETC_DIRPATH
) < 0)
1520 setenv("KRB5_CONFIG", newpath
, 1);
1523 krb5_init_context(&context
);
1525 #if defined(KRB5_PROG_ETYPE_NOSUPP) && !(defined(HAVE_KRB5_ENCTYPE_ENABLE) || defined(HAVE_KRB5_ALLOW_WEAK_CRYPTO))
1529 setenv("KRB5_CONFIG", filepath
, 1);
1531 unsetenv("KRB5_CONFIG");
1534 initialize_KTC_error_table ();
1535 initialize_U_error_table();
1536 initialize_RXK_error_table();
1537 initialize_ACFG_error_table();
1538 initialize_PT_error_table();
1539 afs_set_com_err_hook(redirect_errors
);
1542 * Enable DES enctypes, which are currently still required for AFS.
1543 * krb5_allow_weak_crypto is MIT Kerberos 1.8. krb5_enctype_enable is
1546 #if defined(HAVE_KRB5_ENCTYPE_ENABLE)
1547 i
= krb5_enctype_valid(context
, ETYPE_DES_CBC_CRC
);
1549 krb5_enctype_enable(context
, ETYPE_DES_CBC_CRC
);
1550 #elif defined(HAVE_KRB5_ALLOW_WEAK_CRYPTO)
1551 krb5_allow_weak_crypto(context
, 1);
1554 /* Initialize list of cells to which we have authenticated */
1555 ll_init(&authedcells
);
1557 /* Parse commandline arguments and make list of what to do. */
1558 for (i
= 1; i
< argc
; i
++) {
1559 if (strcmp(argv
[i
], "-d") == 0)
1561 else if (strcmp(argv
[i
], "-noauth") == 0)
1563 else if (strcmp(argv
[i
], "-zsubs") == 0)
1565 else if (strcmp(argv
[i
], "-hosts") == 0)
1567 else if (strcmp(argv
[i
], "-noprdb") == 0)
1569 else if (strcmp(argv
[i
], "-linked") == 0)
1571 else if (strcmp(argv
[i
], "-force") == 0)
1573 #ifndef HAVE_NO_KRB5_524
1574 else if (strcmp(argv
[i
], "-524") == 0)
1577 else if (strcmp(argv
[i
], "-setpag") == 0)
1579 else if (((strcmp(argv
[i
], "-cell") == 0) ||
1580 (strcmp(argv
[i
], "-c") == 0)) && !pmode
)
1583 strlcpy(cell
, argv
[i
], sizeof(cell
));
1587 else if ((strcmp(argv
[i
], "-keytab") == 0))
1593 else if ((strcmp(argv
[i
], "-principal") == 0))
1599 else if (((strcmp(argv
[i
], "-path") == 0) ||
1600 (strcmp(argv
[i
], "-p") == 0)) && !cmode
)
1603 strlcpy(path
, argv
[i
], sizeof(path
));
1607 else if (strcmp(argv
[i
], "-config") == 0)
1613 else if (argv
[i
][0] == '-')
1615 else if (!pmode
&& !cmode
) {
1616 if (strchr(argv
[i
], DIR) || (strcmp(argv
[i
], ".") == 0) ||
1617 (strcmp(argv
[i
], "..") == 0)) {
1619 strlcpy(path
, argv
[i
], sizeof(path
));
1623 strlcpy(cell
, argv
[i
], sizeof(cell
));
1630 if (((i
+ 1) < argc
) && (strcmp(argv
[i
+ 1], "-k") == 0)) {
1633 strlcpy(realm
, argv
[i
], sizeof(realm
));
1637 /* Add this cell to list of cells */
1638 strcpy(cellinfo
.cell
, cell
);
1639 strcpy(cellinfo
.realm
, realm
);
1640 if ((cur_node
= ll_add_node(&cells
, ll_tail
))) {
1642 if ((new_cellinfo
= copy_cellinfo(&cellinfo
)))
1643 ll_add_data(cur_node
, new_cellinfo
);
1646 "%s: failure copying cellinfo.\n", progname
);
1651 fprintf(stderr
, "%s: failure adding cell to cells list.\n",
1655 memset(&cellinfo
, 0, sizeof(cellinfo
));
1657 memset(cell
, 0, sizeof(cell
));
1658 memset(realm
, 0, sizeof(realm
));
1661 /* Add this path to list of paths */
1662 if ((cur_node
= ll_add_node(&paths
, ll_tail
))) {
1664 if ((new_path
= strdup(path
)))
1665 ll_add_data(cur_node
, new_path
);
1667 fprintf(stderr
, "%s: failure copying path name.\n",
1673 fprintf(stderr
, "%s: failure adding path to paths list.\n",
1678 memset(path
, 0, sizeof(path
));
1682 /* If nothing was given, log to the local cell. */
1683 if ((cells
.nelements
+ paths
.nelements
) == 0) {
1686 status
= auth_to_cell(context
, config
, NULL
, NULL
, &linkedcell
);
1688 /* If this cell is linked to a DCE cell, and user requested -linked,
1689 * get tokens for both. This is very useful when the AFS cell is
1690 * linked to a DFS cell and this system does not also have DFS.
1693 if (!status
&& linked
&& linkedcell
!= NULL
) {
1694 afs_dprintf("Linked cell: %s\n", linkedcell
);
1695 status
= auth_to_cell(context
, config
, linkedcell
, NULL
, NULL
);
1703 * Local hack - if the person has a file in their home
1704 * directory called ".xlog", read that for a list of
1705 * extra cells to authenticate to
1708 if ((pwd
= getpwuid(getuid())) != NULL
) {
1711 char fcell
[100], xlog_path
[512];
1713 strlcpy(xlog_path
, pwd
->pw_dir
, sizeof(xlog_path
));
1714 strlcat(xlog_path
, "/.xlog", sizeof(xlog_path
));
1716 if ((stat(xlog_path
, &sbuf
) == 0) &&
1717 ((f
= fopen(xlog_path
, "r")) != NULL
)) {
1719 afs_dprintf("Reading %s for cells to authenticate to.\n",
1722 while (fgets(fcell
, 100, f
) != NULL
) {
1725 fcell
[strlen(fcell
) - 1] = '\0';
1727 afs_dprintf("Found cell %s in %s.\n", fcell
, xlog_path
);
1729 auth_status
= auth_to_cell(context
, config
, fcell
, NULL
, NULL
);
1730 if (status
== AKLOG_SUCCESS
)
1731 status
= auth_status
;
1733 status
= AKLOG_SOMETHINGSWRONG
;
1739 /* Log to all cells in the cells list first */
1740 for (cur_node
= cells
.first
; cur_node
; cur_node
= cur_node
->next
) {
1741 memcpy((char *)&cellinfo
, cur_node
->data
, sizeof(cellinfo
));
1742 status
= auth_to_cell(context
, config
, cellinfo
.cell
,
1743 cellinfo
.realm
, &linkedcell
);
1747 if (linked
&& linkedcell
!= NULL
) {
1748 afs_dprintf("Linked cell: %s\n", linkedcell
);
1749 status
= auth_to_cell(context
, config
, linkedcell
,
1750 cellinfo
.realm
, NULL
);
1754 if (linkedcell
!= NULL
) {
1761 /* Then, log to all paths in the paths list */
1762 for (cur_node
= paths
.first
; cur_node
; cur_node
= cur_node
->next
) {
1763 status
= auth_to_path(context
, config
, cur_node
->data
);
1769 * If only one thing was logged to, we'll return the status
1770 * of the single call. Otherwise, we'll return a generic
1771 * something failed status.
1773 if (somethingswrong
&& ((cells
.nelements
+ paths
.nelements
) > 1))
1774 status
= AKLOG_SOMETHINGSWRONG
;
1777 /* If we are keeping track of zephyr subscriptions, print them. */
1779 for (cur_node
= zsublist
.first
; cur_node
; cur_node
= cur_node
->next
) {
1780 printf("zsub: %s\n", cur_node
->data
);
1783 /* If we are keeping track of host information, print it. */
1785 for (cur_node
= hostlist
.first
; cur_node
; cur_node
= cur_node
->next
) {
1786 printf("host: %s\n", cur_node
->data
);
1793 isdir(char *path
, unsigned char *val
)
1795 struct stat statbuf
;
1797 if (lstat(path
, &statbuf
) < 0)
1800 if ((statbuf
.st_mode
& S_IFMT
) == S_IFDIR
)
1808 static krb5_error_code
1809 get_credv5_akimpersonate(krb5_context context
,
1811 krb5_principal service_principal
,
1812 krb5_principal client_principal
,
1815 int *allowed_enctypes
,
1817 krb5_creds
** out_creds
/* out */ )
1819 #if defined(USING_HEIMDAL) || (defined(HAVE_ENCODE_KRB5_ENC_TKT) && defined(HAVE_ENCODE_KRB5_TICKET) && defined(HAVE_KRB5_C_ENCRYPT))
1820 krb5_error_code code
;
1822 krb5_kt_cursor cursor
[1];
1823 krb5_keytab_entry entry
[1];
1825 krb5_creds
*creds
= 0;
1826 krb5_enctype enctype
;
1828 krb5_keyblock session_key
[1];
1830 Ticket ticket_reply
[1];
1831 EncTicketPart enc_tkt_reply
[1];
1832 krb5_address address
[30];
1833 krb5_addresses faddr
[1];
1834 unsigned int temp_vno
[1];
1835 time_t temp_time
[2];
1837 krb5_ticket ticket_reply
[1];
1838 krb5_enc_tkt_part enc_tkt_reply
[1];
1839 krb5_address address
[30], *faddr
[30];
1843 static int any_enctype
[] = {0};
1845 if (!(creds
= malloc(sizeof *creds
))) {
1849 if (!allowed_enctypes
)
1850 allowed_enctypes
= any_enctype
;
1853 enctype
= 0; /* AKIMPERSONATE_IGNORE_ENCTYPE */
1854 kvno
= 0; /* AKIMPERSONATE_IGNORE_VNO */
1855 memset((char*)creds
, 0, sizeof *creds
);
1856 memset((char*)entry
, 0, sizeof *entry
);
1857 memset((char*)session_key
, 0, sizeof *session_key
);
1858 memset((char*)ticket_reply
, 0, sizeof *ticket_reply
);
1859 memset((char*)enc_tkt_reply
, 0, sizeof *enc_tkt_reply
);
1860 code
= krb5_kt_resolve(context
, keytab
, &kt
);
1863 afs_com_err(progname
, code
, "while resolving keytab %s", keytab
);
1865 afs_com_err(progname
, code
, "while resolving default keytab");
1869 if (service_principal
) {
1870 for (i
= 0; (enctype
= allowed_enctypes
[i
]) || !i
; ++i
) {
1871 code
= krb5_kt_get_entry(context
,
1878 if (allowed_enctypes
[i
])
1879 deref_keyblock_enctype(session_key
) = allowed_enctypes
[i
];
1884 afs_com_err(progname
, code
,"while scanning keytab entries");
1888 krb5_keytab_entry
new[1];
1890 memset(new, 0, sizeof *new);
1891 if ((code
= krb5_kt_start_seq_get(context
, kt
, cursor
))) {
1892 afs_com_err(progname
, code
, "while starting keytab scan");
1895 while (!(code
= krb5_kt_next_entry(context
, kt
, new, cursor
))) {
1897 allowed_enctypes
[i
] && allowed_enctypes
[i
]
1898 != deref_entry_enctype(new); ++i
)
1900 if ((!i
|| allowed_enctypes
[i
]) &&
1901 (best
< 0 || best
> i
)) {
1902 krb5_free_keytab_entry_contents(context
, entry
);
1904 memset(new, 0, sizeof *new);
1905 } else krb5_free_keytab_entry_contents(context
, new);
1907 if ((i
= krb5_kt_end_seq_get(context
, kt
, cursor
))) {
1908 afs_com_err(progname
, i
, "while ending keytab scan");
1913 afs_com_err(progname
, code
, "while scanning keytab");
1916 deref_keyblock_enctype(session_key
) = deref_entry_enctype(entry
);
1922 if ((code
= krb5_generate_random_keyblock(context
,
1923 deref_keyblock_enctype(session_key
), session_key
))) {
1924 afs_com_err(progname
, code
, "while making session key");
1927 enc_tkt_reply
->flags
.initial
= 1;
1928 enc_tkt_reply
->transited
.tr_type
= DOMAIN_X500_COMPRESS
;
1929 enc_tkt_reply
->cname
= client_principal
->name
;
1930 enc_tkt_reply
->crealm
= client_principal
->realm
;
1931 enc_tkt_reply
->key
= *session_key
;
1933 static krb5_data empty_string
;
1934 enc_tkt_reply
->transited
.contents
= empty_string
;
1936 enc_tkt_reply
->authtime
= starttime
;
1937 enc_tkt_reply
->starttime
= temp_time
;
1938 *enc_tkt_reply
->starttime
= starttime
;
1940 enc_tkt_reply
->renew_till
= temp_time
+ 1;
1941 *enc_tkt_reply
->renew_till
= endtime
;
1943 enc_tkt_reply
->endtime
= endtime
;
1945 if ((code
= krb5_c_make_random_key(context
,
1946 deref_keyblock_enctype(session_key
), session_key
))) {
1947 afs_com_err(progname
, code
, "while making session key");
1950 enc_tkt_reply
->magic
= KV5M_ENC_TKT_PART
;
1951 #define DATACAST (unsigned char *)
1952 enc_tkt_reply
->flags
|= TKT_FLG_INITIAL
;
1953 enc_tkt_reply
->transited
.tr_type
= KRB5_DOMAIN_X500_COMPRESS
;
1954 enc_tkt_reply
->session
= session_key
;
1955 enc_tkt_reply
->client
= client_principal
;
1957 static krb5_data empty_string
;
1958 enc_tkt_reply
->transited
.tr_contents
= empty_string
;
1960 enc_tkt_reply
->times
.authtime
= starttime
;
1961 enc_tkt_reply
->times
.starttime
= starttime
; /* krb524init needs this */
1962 enc_tkt_reply
->times
.endtime
= endtime
;
1963 #endif /* USING_HEIMDAL */
1964 /* NB: We will discard address for now--ignoring caddr field
1965 in any case. MIT branch does what it always did. */
1967 if (paddress
&& *paddress
) {
1968 deref_enc_tkt_addrs(enc_tkt_reply
) = faddr
;
1971 faddr
->val
= address
;
1973 for (i
= 0; paddress
[i
]; ++i
) {
1975 address
[i
].addr_type
= KRB5_ADDRESS_INET
;
1976 address
[i
].address
.data
= (void*)(paddress
+i
);
1977 address
[i
].address
.length
= sizeof(paddress
[i
]);
1980 address
[i
].magic
= KV5M_ADDRESS
;
1981 address
[i
].addrtype
= ADDRTYPE_INET
;
1983 address
[i
].addrtype
= AF_INET
;
1985 address
[i
].contents
= (void*)(paddress
+i
);
1986 address
[i
].length
= sizeof(int);
1987 faddr
[i
] = address
+i
;
1998 ticket_reply
->sname
= service_principal
->name
;
1999 ticket_reply
->realm
= service_principal
->realm
;
2001 { /* crypto block */
2002 krb5_crypto crypto
= 0;
2003 unsigned char *buf
= 0;
2004 size_t buf_size
, buf_len
;
2007 ASN1_MALLOC_ENCODE(EncTicketPart
, buf
, buf_size
,
2008 enc_tkt_reply
, &buf_len
, code
);
2010 afs_com_err(progname
, code
, "while encoding ticket");
2014 if(buf_len
!= buf_size
) {
2015 afs_com_err(progname
, code
,
2016 "%u != %u while encoding ticket (internal ASN.1 encoder error",
2017 (unsigned int)buf_len
, (unsigned int)buf_size
);
2020 what
= "krb5_crypto_init";
2021 code
= krb5_crypto_init(context
,
2022 &deref_entry_keyblock(entry
),
2023 deref_entry_enctype(entry
),
2026 what
= "krb5_encrypt";
2027 code
= krb5_encrypt_EncryptedData(context
, crypto
, KRB5_KU_TICKET
,
2028 buf
, buf_len
, entry
->vno
, &(ticket_reply
->enc_part
));
2031 if (crypto
) krb5_crypto_destroy(context
, crypto
);
2033 afs_com_err(progname
, code
, "while %s", what
);
2036 } /* crypto block */
2037 ticket_reply
->enc_part
.etype
= deref_entry_enctype(entry
);
2038 ticket_reply
->enc_part
.kvno
= (void *)temp_vno
;
2039 *ticket_reply
->enc_part
.kvno
= entry
->vno
;
2040 ticket_reply
->tkt_vno
= 5;
2042 ticket_reply
->server
= service_principal
;
2043 ticket_reply
->enc_part2
= enc_tkt_reply
;
2044 if ((code
= krb5_encrypt_tkt_part(context
, &deref_entry_keyblock(entry
), ticket_reply
))) {
2045 afs_com_err(progname
, code
, "while making ticket");
2048 ticket_reply
->enc_part
.kvno
= entry
->vno
;
2051 /* Construct Creds */
2053 if ((code
= krb5_copy_principal(context
, service_principal
,
2055 afs_com_err(progname
, code
, "while copying service principal");
2058 if ((code
= krb5_copy_principal(context
, client_principal
,
2060 afs_com_err(progname
, code
, "while copying client principal");
2063 if ((code
= krb5_copy_keyblock_contents(context
, session_key
,
2064 &deref_session_key(creds
)))) {
2065 afs_com_err(progname
, code
, "while copying session key");
2070 creds
->times
.authtime
= enc_tkt_reply
->authtime
;
2071 creds
->times
.starttime
= *(enc_tkt_reply
->starttime
);
2072 creds
->times
.endtime
= enc_tkt_reply
->endtime
;
2073 creds
->times
.renew_till
= 0; /* *(enc_tkt_reply->renew_till) */
2074 creds
->flags
.b
= enc_tkt_reply
->flags
;
2076 creds
->times
= enc_tkt_reply
->times
;
2077 creds
->ticket_flags
= enc_tkt_reply
->flags
;
2079 if (!deref_enc_tkt_addrs(enc_tkt_reply
))
2081 else if ((code
= krb5_copy_addresses(context
,
2082 deref_enc_tkt_addrs(enc_tkt_reply
), &creds
->addresses
))) {
2083 afs_com_err(progname
, code
, "while copying addresses");
2089 size_t creds_tkt_len
;
2090 ASN1_MALLOC_ENCODE(Ticket
, creds
->ticket
.data
, creds
->ticket
.length
,
2091 ticket_reply
, &creds_tkt_len
, code
);
2093 afs_com_err(progname
, code
, "while encoding ticket");
2098 if ((code
= encode_krb5_ticket(ticket_reply
, &temp
))) {
2099 afs_com_err(progname
, code
, "while encoding ticket");
2102 creds
->ticket
= *temp
;
2109 if (deref_enc_data(&ticket_reply
->enc_part
))
2110 free(deref_enc_data(&ticket_reply
->enc_part
));
2111 krb5_free_keytab_entry_contents(context
, entry
);
2112 if (client_principal
)
2113 krb5_free_principal(context
, client_principal
);
2114 if (service_principal
)
2115 krb5_free_principal(context
, service_principal
);
2117 krb5_cc_close(context
, cc
);
2119 krb5_kt_close(context
, kt
);
2120 if (creds
) krb5_free_creds(context
, creds
);
2121 krb5_free_keyblock_contents(context
, session_key
);
2129 static krb5_error_code
2130 get_credv5(krb5_context context
, char *name
, char *inst
, char *realm
,
2135 static krb5_principal client_principal
= 0;
2137 afs_dprintf("Getting tickets: %s%s%s@%s\n", name
,
2138 (inst
&& inst
[0]) ? "/" : "", inst
? inst
: "", realm
);
2140 memset(&increds
, 0, sizeof(increds
));
2141 /* ANL - instance may be ptr to a null string. Pass null then */
2142 if ((r
= krb5_build_principal(context
, &increds
.server
,
2143 strlen(realm
), realm
,
2145 (inst
&& strlen(inst
)) ? inst
: NULL
,
2151 if (!_krb425_ccache
) {
2152 r
= krb5_cc_default(context
, &_krb425_ccache
);
2156 if (!client_principal
) {
2158 r
= krb5_parse_name(context
, client
, &client_principal
);
2160 r
= krb5_cc_get_principal(context
, _krb425_ccache
, &client_principal
);
2166 increds
.client
= client_principal
;
2167 increds
.times
.endtime
= 0;
2169 /* Ask for DES since that is what V4 understands */
2170 get_creds_enctype((&increds
)) = ENCTYPE_DES_CBC_CRC
;
2173 int allowed_enctypes
[] = {
2174 ENCTYPE_DES_CBC_CRC
, 0
2177 r
= get_credv5_akimpersonate(context
,
2186 r
= krb5_get_credentials(context
, 0, _krb425_ccache
, &increds
, creds
);
2193 get_user_realm(krb5_context context
, char **realm
)
2195 static krb5_principal client_principal
= 0;
2196 krb5_error_code r
= 0;
2200 if (!_krb425_ccache
) {
2201 r
= krb5_cc_default(context
, &_krb425_ccache
);
2205 if (!client_principal
) {
2207 r
= krb5_parse_name(context
, client
, &client_principal
);
2209 r
= krb5_cc_get_principal(context
, _krb425_ccache
, &client_principal
);
2215 *realm
= extract_realm(context
, client_principal
);