2 * Copyright (c) 2005-2011 Secure Endpoints Inc.
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 /* Disable the 'macro redefinition' warning which is getting
28 triggerred by a redefinition of the ENCRYPT and DECRYPT macros. */
29 #pragma warning (push)
30 #pragma warning (disable: 4005)
34 #include<krb5common.h>
40 static char *afs_realm_of_cell(afs_conf_cell
*, BOOL
);
41 static long afs_get_cellconfig_callback(void *, struct sockaddr_in
*, char *, unsigned short ipRank
);
42 static int afs_get_cellconfig(char *, afs_conf_cell
*, char *);
45 afs_is_running(void) {
51 if (GetServiceStatus(NULL
, TRANSARCAFSDAEMON
,
52 &CurrentState
, NULL
) != NOERROR
)
54 if (CurrentState
!= SERVICE_RUNNING
)
65 if (!afs_is_running())
68 rc
= ktc_ForgetAllTokens();
74 afs_unlog_cred(khm_handle cred
)
77 struct ktc_principal princ
;
79 wchar_t name
[KCDB_MAXCCH_NAME
];
81 if (!afs_is_running())
84 cbbuf
= sizeof(princ
);
85 if(KHM_FAILED(kcdb_cred_get_attr(cred
, afs_attr_server_princ
,
86 NULL
, &princ
, &cbbuf
)))
89 afs_princ_to_string(&princ
, name
, sizeof(name
));
91 _report_cs1(KHERR_INFO
, L
"Destroying token %1!s!",
95 rc
= ktc_ForgetToken(&princ
);
100 /* convert a ktc_principal to a wchar_t string form that looks like
101 name.instance@cell return 0 if it worked. non-zero otherwise
104 afs_princ_to_string(struct ktc_principal
* p
,
112 l
= AnsiStrToUnicode(wbuf
, sizeof(wbuf
), p
->name
);
115 rv
= FAILED(StringCbCopy(buf
, cbbuf
, wbuf
));
117 StringCbCat(buf
, cbbuf
, L
".");
118 if((l
= AnsiStrToUnicode(wbuf
, sizeof(wbuf
), p
->instance
)) > 0) {
120 rv
= rv
|| FAILED(StringCbCat(buf
, cbbuf
, wbuf
));
126 rv
= rv
|| FAILED(StringCbCat(buf
, cbbuf
, L
"@"));
127 if((l
= AnsiStrToUnicode(wbuf
, sizeof(wbuf
), p
->cell
)) > 0) {
129 rv
= rv
|| FAILED(StringCbCat(buf
, cbbuf
, wbuf
));
139 afs_list_tokens(void)
143 kcdb_credset_flush(afs_credset
);
144 r
= afs_list_tokens_internal();
145 kcdb_credset_collect(NULL
, afs_credset
, NULL
, afs_credtype_id
, NULL
);
148 afs_icon_set_state(AFSICON_REPORT_TOKENS
, afs_credset
);
149 } else if (r
== -1) {
150 afs_icon_set_state(AFSICON_SERVICE_STOPPED
, NULL
);
152 afs_icon_set_state(AFSICON_SERVICE_ERROR
, NULL
);
158 /* is the credential provided an AFS token and is it from the
160 static khm_int32 KHMAPI
161 afs_filter_by_cell(khm_handle cred
, khm_int32 flags
, void * rock
)
163 wchar_t wcell
[MAXCELLCHARS
];
168 tcell
= (wchar_t *) rock
;
170 if(KHM_FAILED(kcdb_cred_get_type(cred
, &type
)) ||
171 type
!= afs_credtype_id
)
174 cbsize
= sizeof(wcell
);
175 if(KHM_FAILED(kcdb_cred_get_attr(cred
, afs_attr_cell
,
176 NULL
, wcell
, &cbsize
)))
179 if(wcscmp(wcell
, tcell
))
185 struct token_filter_data
{
190 afs_filter_for_token(khm_handle cred
, khm_int32 flags
, void * rock
) {
191 struct token_filter_data
* pdata
;
192 wchar_t ccell
[MAXCELLCHARS
];
196 pdata
= (struct token_filter_data
*) rock
;
198 if (KHM_FAILED(kcdb_cred_get_type(cred
, &ctype
)) ||
199 ctype
!= afs_credtype_id
)
205 if (KHM_FAILED(kcdb_cred_get_attr(cred
, afs_attr_cell
,
209 _wcsicmp(ccell
, pdata
->cell
))
217 afs_find_token(khm_handle credset
, wchar_t * cell
) {
218 struct token_filter_data fdata
;
219 khm_handle cred
= NULL
;
223 if (KHM_FAILED(kcdb_credset_find_filtered(credset
,
225 afs_filter_for_token
,
234 static khm_int32 KHMAPI
235 afs_filter_krb5_tkt(khm_handle cred
, khm_int32 flags
, void * rock
)
237 wchar_t cname
[KCDB_CRED_MAXCCH_NAME
];
240 wchar_t * t
, *tkt_cell
;
243 tcell
= (wchar_t *) rock
;
245 if(KHM_FAILED(kcdb_cred_get_type(cred
, &type
)) ||
246 type
!= krb5_credtype_id
)
249 cbsize
= sizeof(cname
);
250 if (KHM_FAILED(kcdb_cred_get_name(cred
, cname
, &cbsize
)))
253 if (!wcsncmp(cname
, L
"afs/", 4)) {
255 tkt_cell
= cname
+ 4;
257 t
= wcschr(tkt_cell
, L
'@');
262 } else if (!wcsncmp(cname
, L
"afs@", 4)) {
264 tkt_cell
= cname
+ 4;
270 if (_wcsicmp(tcell
, tkt_cell
))
276 static khm_int32 KHMAPI
277 afs_filter_krb4_tkt(khm_handle cred
, khm_int32 flags
, void * rock
)
279 wchar_t cname
[KCDB_CRED_MAXCCH_NAME
];
282 wchar_t * t
, *tkt_cell
;
285 tcell
= (wchar_t *) rock
;
287 if(KHM_FAILED(kcdb_cred_get_type(cred
, &type
)) ||
288 type
!= krb4_credtype_id
)
291 cbsize
= sizeof(cname
);
292 if (KHM_FAILED(kcdb_cred_get_name(cred
, cname
, &cbsize
)))
295 if (!wcsncmp(cname
, L
"afs.", 4)) {
297 tkt_cell
= cname
+ 4;
299 t
= wcschr(tkt_cell
, L
'@');
304 } else if (!wcsncmp(cname
, L
"afs@", 4)) {
306 tkt_cell
= cname
+ 4;
312 if (_wcsicmp(tcell
, tkt_cell
))
318 /* collects all AFS tokens to the root credential set using the
319 generic afs_credset credential set
322 afs_list_tokens_internal(void)
324 struct ktc_principal aserver
;
325 struct ktc_principal aclient
;
326 struct ktc_token atoken
;
331 wchar_t location
[256];
336 khm_handle ident
= NULL
;
337 khm_handle cred
= NULL
;
338 afs_tk_method method
;
342 if (!afs_is_running())
345 kcdb_credset_flush(afs_credset
);
347 LoadString(hResModule
, IDS_DEF_LOCATION
, location
, ARRAYLENGTH(location
));
353 memset(&aserver
, 0, sizeof(aserver
));
354 if (rc
= ktc_ListTokens(cellNum
, &cellNum
, &aserver
))
363 memset(&atoken
, '\0', sizeof(atoken
));
364 if (rc
= ktc_GetToken(&aserver
, &atoken
, sizeof(atoken
), &aclient
))
373 /* failed attempt at trying to figure out the principal name from
374 the token. The ticket that is attached to the token is not
375 in a form that is useful at this point */
377 if(atoken
.kvno
== RXKAD_TKT_TYPE_KERBEROS_V5
) {
378 krb5_context ctx
= 0;
381 krb5_error_code code
;
384 code
= khm_krb5_initialize(&ctx
, &cc
);
388 k5c
= (krb5_creds
*) atoken
.ticket
;
390 code
= krb5_unparse_name(ctx
, k5c
->client
, &princ
);
394 MultiByteToWideChar(CP_ACP
, 0, princ
, strlen(princ
), idname
, sizeof(idname
)/sizeof(idname
[0]));
396 krb5_free_unparsed_name(ctx
, princ
);
402 method
= AFS_TOKEN_AUTO
;
404 afs_princ_to_string(&aclient
, idname
, sizeof(idname
));
406 /* We need to figure out a good client name which we can use
407 to create an identity which looks familiar to the user. No
408 good way of doing this, so we use a heuristic.
410 Note that, we use another heuristic to find out which
411 identity to associate the token with.
415 The assumption here is that the principal for the token is
418 if realm != cell : principal looks like user@realm@cell
419 if realm == cell : principal looks like user@realm
423 We strip the part of the string that follows the second '@'
424 sign to obtain the 'user@realm' part, which we use as the
425 credential name. If there is no second '@', we use the
426 whole principal name. */
430 ats
= wcschr(idname
, L
'@');
431 if(ats
&& (ats
= wcschr(ats
+ 1, L
'@')))
435 afs_princ_to_string(&aserver
, crname
, sizeof(crname
));
437 /* Ok, now we need to figure out which identity to associate
438 this token with. This is a little bit tricky, and there is
439 currently no good way of determining the original identity
440 used to obtain the token if it was done outside of
441 NetIDMgr. So we use a heuristic here.
445 Elsewhere, (actually in afsnewcreds.c) just after obtaining
446 AFS tokens through NetIDMgr, we enumerate the AFS tokens
447 and assign the root identity (used to obtain new creds)
448 with the AFS tokens. This would still be there in the root
449 credential set when we list tokens later on.
453 If there exists an AFS token in the root credential set for
454 the same cell, we associate this token with the same
455 identity as that credential.
457 cell
= wcschr(crname
, L
'@');
468 if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL
, -1,
474 kcdb_cred_get_identity(c
, &ident
);
476 kcdb_cred_get_attr(c
, afs_attr_method
, NULL
,
478 kcdb_cred_release(c
);
482 /* If that failed, we have try another trick. If there is a
483 Krb5 ticket of the form afs/<cell>@<realm> or afs@<CELL>
484 where <cell> matches our cell, then we pick the identity
489 If Krb5 was used to obtain the token, then there is a Krb5
490 ticket of the form afs/<cell>@<REALM> or afs@<CELL> still
491 in the cache. This is also true for Krb524 token
496 If such a Krb5 ticket is found, use the identity of that
497 credential as the identity of the AFS token.
500 if (ident
== NULL
&& cell
!= NULL
) {
503 if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL
, -1,
507 kcdb_cred_get_identity(c
, &ident
);
508 /* this could be Krb5 or Krb524, so we leave method at
510 method
= AFS_TOKEN_AUTO
;
511 kcdb_cred_release(c
);
515 /* If that didn't work either, we look for a Krb4 ticket of
516 the form afs.<cell>@<REALM> or afs@<CELL> which matches the
521 If Krb4 was used to obtain an AFS token, then there should
522 be a Krb4 ticket of the form afs.<cell>@<REALM> or
523 afs@<CELL> in the cache.
527 If such a ticket is found, then use the identity of that
528 credential as the identity of the AFS token.
530 if (ident
== NULL
&& cell
!= NULL
) {
533 if (krb4_credtype_id
< 0) {
534 kcdb_credtype_get_id(KRB4_CREDTYPE_NAME
,
538 if (krb4_credtype_id
>= 0 &&
539 KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL
, -1,
544 kcdb_cred_get_identity(c
, &ident
);
545 kcdb_cred_release(c
);
546 method
= AFS_TOKEN_KRB4
;
551 /* Finally, we allow any extension plugins to give this a shot */
552 if (ident
== NULL
&& cell
!= NULL
) {
553 afs_ext_resolve_token(cell
,
561 /* One more thing to try. If we have a cell->identity
562 mapping, then we try that. */
563 if (ident
== NULL
&& cell
!= NULL
) {
564 khm_handle h_cellmap
;
565 wchar_t tidname
[KCDB_IDENT_MAXCCH_NAME
];
568 cb
= sizeof(tidname
);
570 if (KHM_SUCCEEDED(khc_open_space(csp_afscred
,
573 if (KHM_SUCCEEDED(khc_read_string(h_cellmap
,
577 kcdb_identity_create(tidname
,
578 KCDB_IDENT_FLAG_CREATE
,
581 khc_close_space(h_cellmap
);
585 /* all else failed */
587 if(KHM_FAILED(kcdb_identity_create(idname
,
588 KCDB_IDENT_FLAG_CREATE
,
593 if(KHM_FAILED(kcdb_cred_create(crname
, ident
, afs_credtype_id
, &cred
)))
596 kcdb_cred_set_attr(cred
, afs_attr_method
, &method
, sizeof(method
));
598 TimetToFileTime(atoken
.endTime
, &ft
);
599 kcdb_cred_set_attr(cred
, KCDB_ATTR_EXPIRE
, &ft
, sizeof(ft
));
600 if (atoken
.startTime
!= 0) {
601 TimetToFileTime(atoken
.startTime
, &ft
);
602 kcdb_cred_set_attr(cred
, KCDB_ATTR_ISSUE
, &ft
, sizeof(ft
));
604 kcdb_cred_set_attr(cred
, afs_attr_client_princ
,
605 &aclient
, sizeof(aclient
));
606 kcdb_cred_set_attr(cred
, afs_attr_server_princ
,
607 &aserver
, sizeof(aserver
));
610 kcdb_cred_set_attr(cred
, afs_attr_cell
, cell
, (khm_size
)KCDB_CBSIZE_AUTO
);
613 kcdb_cred_set_attr(cred
, KCDB_ATTR_LOCATION
,
614 location
, (khm_size
)KCDB_CBSIZE_AUTO
);
616 kcdb_credset_add_cred(afs_credset
, cred
, -1);
618 /* both these calls are NULL pointer safe */
619 kcdb_cred_release(cred
);
621 kcdb_identity_release(ident
);
627 kcdb_identity_release(ident
);
629 kcdb_cred_release(cred
);
635 #define ALLOW_REGISTER 1
637 ViceIDToUsername(char *username
,
641 struct ktc_principal
*aclient
,
642 struct ktc_principal
*aserver
,
643 struct ktc_token
*atoken
)
645 static char lastcell
[MAXCELLCHARS
+1] = { 0 };
646 static char confname
[512] = { 0 };
647 char username_copy
[BUFSIZ
];
648 long viceId
= ANONYMOUSID
; /* AFS uid of user */
650 #ifdef ALLOW_REGISTER
652 #endif /* ALLOW_REGISTER */
654 if (confname
[0] == '\0') {
655 StringCbCopyA(confname
, sizeof(confname
), AFSDIR_CLIENT_ETC_DIRPATH
);
658 StringCbCopyA(lastcell
, sizeof(lastcell
), aserver
->cell
);
660 if (!pr_Initialize (0, confname
, aserver
->cell
)) {
661 char sname
[PR_MAXNAMELEN
];
662 StringCbCopyA(sname
, sizeof(sname
), username
);
663 status
= pr_SNameToId (sname
, &viceId
);
667 #ifdef AFS_ID_TO_NAME
669 * This is a crock, but it is Transarc's crock, so
670 * we have to play along in order to get the
671 * functionality. The way the afs id is stored is
672 * as a string in the username field of the token.
673 * Contrary to what you may think by looking at
674 * the code for tokens, this hack (AFS ID %d) will
675 * not work if you change %d to something else.
677 #endif /* AFS_ID_TO_NAME */
679 * This code is taken from cklog -- it lets people
680 * automatically register with the ptserver in foreign cells
683 /* copy the username because pr_CreateUser will lowercase it */
684 StringCbCopyA(username_copy
, BUFSIZ
, username
);
686 #ifdef ALLOW_REGISTER
688 if (viceId
!= ANONYMOUSID
) {
689 #else /* ALLOW_REGISTER */
690 if ((status
== 0) && (viceId
!= ANONYMOUSID
))
691 #endif /* ALLOW_REGISTER */
693 #ifdef AFS_ID_TO_NAME
694 StringCchPrintfA(username
, BUFSIZ
, "%s (AFS ID %d)", username_copy
, (int) viceId
);
695 #endif /* AFS_ID_TO_NAME */
697 #ifdef ALLOW_REGISTER
698 } else if (strcmp(realm_of_user
, realm_of_cell
) != 0) {
700 StringCbCopyA(aclient
->name
, sizeof(aclient
->name
), username
);
701 StringCbCopyA(aclient
->instance
, sizeof(aclient
->instance
), "");
702 StringCbCopyA(aclient
->cell
, sizeof(aclient
->cell
), realm_of_user
);
703 if (status
= ktc_SetToken(aserver
, atoken
, aclient
, 0))
705 if (status
= pr_Initialize(1L, confname
, aserver
->cell
))
707 status
= pr_CreateUser(username
, &id
);
709 StringCbCopyA(username
, BUFSIZ
, username_copy
);
710 #ifdef AFS_ID_TO_NAME
711 StringCchPrintfA(username
, BUFSIZ
, "%s (AFS ID %d)", username_copy
, (int) viceId
);
712 #endif /* AFS_ID_TO_NAME */
715 #endif /* ALLOW_REGISTER */
721 copy_realm_of_ticket(krb5_context context
, char * dest
, size_t destlen
, krb5_creds
*v5cred
) {
726 ret
= decode_Ticket(v5cred
->ticket
.data
, v5cred
->ticket
.length
,
729 StringCbCopyA(dest
, destlen
, ticket
.realm
);
731 free_Ticket(&ticket
);
736 afs_klog(khm_handle identity
,
741 afs_tk_method method
,
742 time_t * tok_expiration
,
749 struct ktc_principal aserver
;
750 struct ktc_principal aclient
;
751 char realm_of_user
[MAXKTCREALMLEN
]; /* Kerberos realm of user */
752 char realm_of_cell
[MAXKTCREALMLEN
]; /* Kerberos realm of cell */
753 char local_cell
[MAXCELLCHARS
+1];
754 char Dmycell
[MAXCELLCHARS
+1];
755 struct ktc_token atoken
;
756 struct ktc_token btoken
;
757 afs_conf_cell ak_cellconfig
; /* General information about the cell */
760 char ServiceName
[128];
761 khm_handle confighandle
= NULL
;
763 khm_int32 supports_krb4
= (pkrb_get_tf_realm
== NULL
? 0 : 1);
764 khm_int32 got524cred
= 0;
768 BOOL bGotCreds
= FALSE
; /* got creds? */
771 *tok_expiration
= (time_t) 0;
773 if (!afs_is_running()) {
774 _report_sr0(KHERR_WARNING
, IDS_ERR_NOSERVICE
);
778 if ( !realm
) realm
= "";
779 if ( !cell
) cell
= "";
780 if ( !service
) service
= "";
782 memset(&ak_cellconfig
, 0, sizeof(ak_cellconfig
));
783 memset(RealmName
, '\0', sizeof(RealmName
));
784 memset(CellName
, '\0', sizeof(CellName
));
785 memset(ServiceName
, '\0', sizeof(ServiceName
));
786 memset(realm_of_user
, '\0', sizeof(realm_of_user
));
787 memset(realm_of_cell
, '\0', sizeof(realm_of_cell
));
788 memset(Dmycell
, '\0', sizeof(Dmycell
));
790 // NULL or empty cell returns information on local cell
792 StringCbCopyA(Dmycell
, sizeof(Dmycell
), cell
);
794 rc
= afs_get_cellconfig(Dmycell
, &ak_cellconfig
, local_cell
);
796 _reportf(L
"afs_get_cellconfig returns %ld", rc
);
798 _report_sr2(KHERR_ERROR
, IDS_ERR_CELLCONFIG
, _cstr(Dmycell
), _int32(rc
));
799 _suggest_sr(IDS_ERR_CELLCONFIG_S
, KHERR_SUGGEST_NONE
);
804 if (linkedCell
&& ak_cellconfig
.linkedCell
)
805 StringCbCopyA(linkedCell
, MAXCELLCHARS
,
806 ak_cellconfig
.linkedCell
);
808 StringCbCopyA(realm_of_cell
, sizeof(realm_of_cell
),
809 afs_realm_of_cell(&ak_cellconfig
, FALSE
));
811 if (strlen(service
) == 0)
812 StringCbCopyA(ServiceName
, sizeof(ServiceName
), "afs");
814 StringCbCopyA(ServiceName
, sizeof(ServiceName
), service
);
816 if (strlen(cell
) == 0)
817 StringCbCopyA(CellName
, sizeof(CellName
), local_cell
);
819 StringCbCopyA(CellName
, sizeof(CellName
), cell
);
821 if (strlen(realm
) == 0)
822 StringCbCopyA(RealmName
, sizeof(RealmName
), realm_of_cell
);
824 StringCbCopyA(RealmName
, sizeof(RealmName
), realm
);
827 memset(&creds
, '\0', sizeof(creds
));
830 /*** Kerberos 5 and 524 ***/
832 if (method
== AFS_TOKEN_AUTO
||
833 method
== AFS_TOKEN_KRB5
||
834 method
== AFS_TOKEN_KRB524
) {
836 krb5_context context
= 0;
837 krb5_ccache k5cc
= 0;
839 krb5_creds
* k5creds
= 0;
841 krb5_principal client_principal
= 0;
842 krb5_flags flags
= 0;
848 _reportf(L
"Trying Kerberos 5");
850 if (!(r
= khm_krb5_initialize(identity
, &context
, &k5cc
))) {
853 memset(&increds
, 0, sizeof(increds
));
855 r
= krb5_cc_get_principal(context
, k5cc
, &client_principal
);
857 StringCchCopyA(realm_of_user
, ARRAYLENGTH(realm_of_user
),
858 krb5_principal_get_realm(context
, client_principal
));
860 _reportf(L
"krb5_cc_get_principal returns code %d", r
);
868 _reportf(L
"khm_krb5_initialize returns code %d", r
);
876 increds
.client
= client_principal
;
877 increds
.times
.endtime
= 0;
878 /* Ask for DES since that is what V4 understands */
879 if (method
== AFS_TOKEN_KRB524
)
880 increds
.session
.keytype
= ENCTYPE_DES_CBC_CRC
;
882 #ifdef KRB5_TC_NOTICKET
883 flags
= KRB5_TC_OPENCLOSE
;
884 r
= krb5_cc_set_flags(context
, k5cc
, flags
);
886 if (strlen(realm
) != 0) {
888 /* First try Service/Cell@REALM */
889 if (r
= krb5_build_principal(context
, &increds
.server
,
895 _reportf(L
"krb5_build_principal returns %d", r
);
899 r
= krb5_get_credentials(context
, 0, k5cc
, &increds
, &k5creds
);
900 if (r
== KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
||
901 r
== KRB5_ERR_HOST_REALM_UNKNOWN
||
902 r
== KRB5KRB_ERR_GENERIC
/* Heimdal */) {
903 /* Next try Service@REALM */
904 krb5_free_principal(context
, increds
.server
);
905 r
= krb5_build_principal(context
, &increds
.server
,
911 r
= krb5_get_credentials(context
, 0, k5cc
,
915 /* Check to make sure we received a valid ticket; if not remove it
916 * and try again. Perhaps there are two service tickets for the
917 * same service in the ccache.
919 if (r
== 0 && k5creds
&& k5creds
->times
.endtime
< time(NULL
)) {
920 krb5_free_principal(context
, increds
.server
);
921 krb5_cc_remove_cred(context
, k5cc
, 0, k5creds
);
922 krb5_free_creds(context
, k5creds
);
924 goto retry_retcred_1
;
928 /* First try Service/Cell@_CLIENT_REALM */
929 if (r
= krb5_build_principal(context
, &increds
.server
,
930 (int) strlen(realm_of_user
),
935 _reportf(L
"krb5_build_principal returns %d", r
);
939 r
= krb5_get_credentials(context
, 0, k5cc
, &increds
, &k5creds
);
941 /* the user realm is a valid cell realm */
942 StringCbCopyA(realm_of_cell
, sizeof(realm_of_cell
), realm_of_user
);
944 if (r
== KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
||
945 r
== KRB5_ERR_HOST_REALM_UNKNOWN
||
946 r
== KRB5KRB_ERR_GENERIC
/* Heimdal */) {
947 krb5_free_principal(context
, increds
.server
);
948 r
= krb5_build_principal(context
, &increds
.server
,
949 (int) strlen(realm_of_cell
),
955 r
= krb5_get_credentials(context
, 0, k5cc
,
958 if ((r
== KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
||
959 r
== KRB5_ERR_HOST_REALM_UNKNOWN
||
960 r
== KRB5KRB_ERR_GENERIC
/* Heimdal */) &&
961 strlen(realm_of_cell
) == 0) {
962 StringCbCopyA(realm_of_cell
, sizeof(realm_of_cell
),
963 afs_realm_of_cell(&ak_cellconfig
, TRUE
));
965 krb5_free_principal(context
, increds
.server
);
966 r
= krb5_build_principal(context
, &increds
.server
,
967 (int) strlen(realm_of_cell
),
973 r
= krb5_get_credentials(context
, 0, k5cc
,
976 if (r
== KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
||
977 r
== KRB5_ERR_HOST_REALM_UNKNOWN
||
978 r
== KRB5KRB_ERR_GENERIC
/* Heimdal */) {
979 /* Next try Service@REALM */
980 StringCbCopyA(realm_of_cell
, sizeof(realm_of_cell
),
981 afs_realm_of_cell(&ak_cellconfig
, FALSE
));
983 krb5_free_principal(context
, increds
.server
);
984 r
= krb5_build_principal(context
, &increds
.server
,
985 (int) strlen(realm_of_cell
),
990 r
= krb5_get_credentials(context
, 0, k5cc
,
993 if ((r
== KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
||
994 r
== KRB5_ERR_HOST_REALM_UNKNOWN
||
995 r
== KRB5KRB_ERR_GENERIC
/* Heimdal */) &&
996 strlen(realm_of_cell
) == 0) {
997 /* Next try Service@REALM */
998 StringCbCopyA(realm_of_cell
, sizeof(realm_of_cell
),
999 afs_realm_of_cell(&ak_cellconfig
, TRUE
));
1001 krb5_free_principal(context
, increds
.server
);
1002 r
= krb5_build_principal(context
, &increds
.server
,
1003 (int) strlen(realm_of_cell
),
1008 r
= krb5_get_credentials(context
, 0, k5cc
,
1009 &increds
, &k5creds
);
1012 if (r
== 0 && strlen(realm_of_cell
) == 0)
1013 copy_realm_of_ticket(context
, realm_of_cell
, sizeof(realm_of_cell
), k5creds
);
1015 /* Check to make sure we received a valid ticket; if not
1016 * remove it and try again. Perhaps there are two service
1017 * tickets for the same service in the ccache.
1019 if (r
== 0 && k5creds
&& k5creds
->times
.endtime
< time(NULL
)) {
1020 krb5_free_principal(context
, increds
.server
);
1021 krb5_cc_remove_cred(context
, k5cc
, 0, k5creds
);
1022 krb5_free_creds(context
, k5creds
);
1024 goto retry_retcred_2
;
1028 krb5_free_principal(context
, increds
.server
);
1029 krb5_free_principal(context
, client_principal
);
1030 client_principal
= 0;
1031 #ifdef KRB5_TC_NOTICKET
1032 flags
= KRB5_TC_OPENCLOSE
| KRB5_TC_NOTICKET
;
1033 krb5_cc_set_flags(context
, k5cc
, flags
);
1036 (void) krb5_cc_close(context
, k5cc
);
1040 _reportf(L
"Code %d while getting credentials", r
);
1046 if ( k5creds
->ticket
.length
> MAXKTCTICKETLEN
||
1047 method
== AFS_TOKEN_KRB524
) {
1052 /* This code inserts the entire K5 ticket into the token */
1054 _reportf(L
"Trying K5 SetToken");
1056 memset(&aserver
, '\0', sizeof(aserver
));
1057 StringCchCopyA(aserver
.name
, MAXKTCNAMELEN
, ServiceName
);
1058 StringCchCopyA(aserver
.cell
, MAXKTCREALMLEN
, CellName
);
1060 memset(&atoken
, '\0', sizeof(atoken
));
1061 atoken
.kvno
= RXKAD_TKT_TYPE_KERBEROS_V5
;
1062 atoken
.startTime
= k5creds
->times
.starttime
;
1063 atoken
.endTime
= k5creds
->times
.endtime
;
1064 if (tkt_DeriveDesKey(k5creds
->session
.keytype
,
1065 k5creds
->session
.keyvalue
.data
,
1066 k5creds
->session
.keyvalue
.length
,
1067 &atoken
.sessionKey
))
1069 atoken
.ticketLen
= k5creds
->ticket
.length
;
1070 memcpy(atoken
.ticket
, k5creds
->ticket
.data
, atoken
.ticketLen
);
1073 *tok_expiration
= k5creds
->times
.endtime
;
1076 rc
= ktc_GetToken(&aserver
, &btoken
, sizeof(btoken
), &aclient
);
1077 if (rc
!= 0 && rc
!= KTC_NOENT
&& rc
!= KTC_NOCELL
) {
1078 if ( rc
== KTC_NOCM
&& retry
< 20 ) {
1081 goto retry_gettoken5
;
1090 if (atoken
.kvno
== btoken
.kvno
&&
1091 atoken
.ticketLen
== btoken
.ticketLen
&&
1092 !memcmp(&atoken
.sessionKey
, &btoken
.sessionKey
,
1093 sizeof(atoken
.sessionKey
)) &&
1094 !memcmp(atoken
.ticket
, btoken
.ticket
, atoken
.ticketLen
)) {
1097 if (k5creds
&& context
)
1098 krb5_free_creds(context
, k5creds
);
1101 krb5_free_context(context
);
1103 _reportf(L
"Same token already exists");
1109 // * Reset the "aclient" structure before we call ktc_SetToken.
1110 // * This structure was first set by the ktc_GetToken call when
1111 // * we were comparing whether identical tokens already existed.
1113 StringCchCopyA(aclient
.name
, MAXKTCNAMELEN
,
1114 krb5_principal_get_comp_string(context
, k5creds
->client
, 0));
1116 if ( krb5_principal_get_num_comp(context
, k5creds
->client
) > 1 ) {
1117 StringCbCatA(aclient
.name
, sizeof(aclient
.name
), ".");
1118 StringCbCatA(aclient
.name
, sizeof(aclient
.name
),
1119 krb5_principal_get_comp_string(context
, k5creds
->client
, 1));
1122 aclient
.instance
[0] = '\0';
1124 StringCbCopyA(aclient
.cell
, sizeof(aclient
.cell
), realm_of_cell
);
1126 StringCbCatA(aclient
.name
, sizeof(aclient
.name
), "@");
1127 StringCbCatA(aclient
.name
, sizeof(aclient
.name
),
1128 krb5_principal_get_realm(context
, k5creds
->client
));
1130 ViceIDToUsername(aclient
.name
, realm_of_user
, realm_of_cell
, CellName
,
1131 &aclient
, &aserver
, &atoken
);
1133 rc
= ktc_SetToken(&aserver
, &atoken
, &aclient
, 0);
1137 if (k5creds
&& context
)
1138 krb5_free_creds(context
, k5creds
);
1141 krb5_free_context(context
);
1146 _reportf(L
"SetToken returns code %d", rc
);
1151 _reportf(L
"Trying Krb524");
1153 if (krb524_convert_creds_kdc
&&
1154 (method
== AFS_TOKEN_AUTO
|| method
== AFS_TOKEN_KRB524
)) {
1155 /* This requires krb524d to be running with the KDC */
1156 r
= krb524_convert_creds_kdc(context
, k5creds
, &creds
);
1158 _reportf(L
"Code %d while converting credentials", r
);
1168 if (client_principal
)
1169 krb5_free_principal(context
, client_principal
);
1171 if (k5creds
&& context
)
1172 krb5_free_creds(context
, k5creds
);
1175 krb5_free_context(context
);
1182 if (supports_krb4
) {
1183 kcdb_identity_get_config(identity
, 0, &confighandle
);
1184 khc_read_int32(confighandle
, L
"Krb4Cred\\Krb4NewCreds", &supports_krb4
);
1185 khc_close_space(confighandle
);
1189 _reportf(L
"Kerberos 4 not configured");
1191 if (!bGotCreds
&& supports_krb4
&&
1192 strlen(RealmName
) < REALM_SZ
&&
1193 (method
== AFS_TOKEN_AUTO
||
1194 method
== AFS_TOKEN_KRB4
)) {
1198 _reportf(L
"Trying Kerberos 4");
1200 if (!realm_of_user
[0] ) {
1201 if ((rc
= (*pkrb_get_tf_realm
)((*ptkt_string
)(), realm_of_user
))
1203 /* can't determine realm of user */
1204 _reportf(L
"krb_get_tf_realm returns %d", rc
);
1209 _reportf(L
"Trying to find %S.%S@%S", ServiceName
, CellName
, RealmName
);
1210 rc
= (*pkrb_get_cred
)(ServiceName
, CellName
, RealmName
, &creds
);
1211 if (rc
== NO_TKT_FIL
) {
1212 // if the problem is that we have no krb4 tickets
1213 // do not attempt to continue
1214 _reportf(L
"krb_get_cred returns %d (no ticket file)", rc
);
1218 if (rc
!= KSUCCESS
) {
1219 _reportf(L
"Trying to find %S@%S", ServiceName
, RealmName
);
1220 rc
= (*pkrb_get_cred
)(ServiceName
, "", RealmName
, &creds
);
1223 if (rc
!= KSUCCESS
) {
1224 _reportf(L
"Trying to obtain new ticket");
1225 if ((rc
= (*pkrb_mk_req
)(&ticket
, ServiceName
,
1226 CellName
, RealmName
, 0))
1228 if ((rc
= (*pkrb_get_cred
)(ServiceName
, CellName
,
1229 RealmName
, &creds
)) != KSUCCESS
) {
1232 _reportf(L
"Got %S.%S@%S", ServiceName
, CellName
, RealmName
);
1234 } else if ((rc
= (*pkrb_mk_req
)(&ticket
, ServiceName
,
1237 if ((rc
= (*pkrb_get_cred
)(ServiceName
, "",
1238 RealmName
, &creds
)) != KSUCCESS
) {
1241 _reportf(L
"Got %S@%S", ServiceName
, RealmName
);
1256 memset(&aserver
, '\0', sizeof(aserver
));
1257 StringCchCopyA(aserver
.name
, MAXKTCNAMELEN
, ServiceName
);
1258 StringCchCopyA(aserver
.cell
, MAXKTCREALMLEN
, CellName
);
1260 memset(&atoken
, '\0', sizeof(atoken
));
1261 atoken
.kvno
= (short)creds
.kvno
;
1262 atoken
.startTime
= creds
.issue_date
;
1263 atoken
.endTime
= (*pkrb_life_to_time
)(creds
.issue_date
,creds
.lifetime
);
1264 memcpy(&atoken
.sessionKey
, creds
.session
, 8);
1265 atoken
.ticketLen
= creds
.ticket_st
.length
;
1266 memcpy(atoken
.ticket
, creds
.ticket_st
.dat
, atoken
.ticketLen
);
1269 *tok_expiration
= atoken
.endTime
;
1271 if (!(rc
= ktc_GetToken(&aserver
, &btoken
,
1272 sizeof(btoken
), &aclient
)) &&
1273 atoken
.kvno
== btoken
.kvno
&&
1274 atoken
.ticketLen
== btoken
.ticketLen
&&
1275 !memcmp(&atoken
.sessionKey
, &btoken
.sessionKey
,
1276 sizeof(atoken
.sessionKey
)) &&
1277 !memcmp(atoken
.ticket
, btoken
.ticket
, atoken
.ticketLen
)) {
1284 // Reset the "aclient" structure before we call ktc_SetToken.
1285 // This structure was first set by the ktc_GetToken call when
1286 // we were comparing whether identical tokens already existed.
1288 StringCchCopyA(aclient
.name
, MAXKTCNAMELEN
, creds
.pname
);
1289 if (creds
.pinst
[0]) {
1290 StringCchCatA(aclient
.name
, MAXKTCNAMELEN
, ".");
1291 StringCchCatA(aclient
.name
, MAXKTCNAMELEN
, creds
.pinst
);
1294 StringCbCopyA(aclient
.instance
, sizeof(aclient
.instance
), "");
1296 StringCchCatA(aclient
.name
, MAXKTCNAMELEN
, "@");
1297 StringCchCatA(aclient
.name
, MAXKTCNAMELEN
, got524cred
? realm_of_user
: creds
.realm
);
1299 StringCbCopyA(aclient
.cell
, sizeof(aclient
.cell
), CellName
);
1301 ViceIDToUsername(aclient
.name
, realm_of_user
, realm_of_cell
, CellName
,
1302 &aclient
, &aserver
, &atoken
);
1304 if (rc
= ktc_SetToken(&aserver
, &atoken
, &aclient
, 0)) {
1305 afs_report_error(rc
, "ktc_SetToken()");
1312 (method
== AFS_TOKEN_AUTO
||
1313 method
>= AFS_TOKEN_USER
)) {
1314 /* we couldn't get a token using Krb5, Krb524 or Krb4,
1315 either because we couldn't get the necessary
1316 credentials or because the method was set to not use
1317 those. Now we dispatch to any extensions to see if
1318 they have better luck. */
1320 rc
= !afs_ext_klog(method
,
1327 } else if (!bGotCreds
) {
1328 /* if the return code was not set, we should set it now.
1329 Otherwise we let the code go through. */
1331 /* No tokens were obtained. We should report something */
1332 _report_sr1(KHERR_ERROR
, IDS_ERR_GENERAL
,
1336 rc
= KHM_ERROR_GENERAL
;
1341 if (ak_cellconfig
.linkedCell
)
1342 free(ak_cellconfig
.linkedCell
);
1347 /**************************************/
1348 /* afs_realm_of_cell(): */
1349 /**************************************/
1351 afs_realm_of_cell(afs_conf_cell
*cellconfig
, BOOL referral_fallback
)
1353 char krbhst
[MAX_HSTNM
]="";
1354 static char krbrlm
[MAXKTCREALMLEN
+1]="";
1355 krb5_context ctx
= 0;
1356 char ** realmlist
=NULL
;
1357 krb5_error_code r
= 0;
1362 if (referral_fallback
) {
1364 p
= strchr(cellconfig
->hostName
[0], '.');
1366 StringCbCopyA(krbrlm
, sizeof(krbrlm
), p
);
1368 StringCbCopyA(krbrlm
, sizeof(krbrlm
), cellconfig
->name
);
1369 #if _MSC_VER >= 1400
1370 _strupr_s(krbrlm
, sizeof(krbrlm
));
1375 r
= krb5_init_context(&ctx
);
1377 r
= krb5_get_host_realm(ctx
, cellconfig
->hostName
[0], &realmlist
);
1378 if ( !r
&& realmlist
&& realmlist
[0] ) {
1379 StringCbCopyA(krbrlm
, sizeof(krbrlm
), realmlist
[0]);
1380 krb5_free_host_realm(ctx
, realmlist
);
1383 krb5_free_context(ctx
);
1387 if (pkrb_get_krbhst
&& pkrb_realmofhost
) {
1388 StringCbCopyA(krbrlm
, sizeof(krbrlm
),
1389 (char *)(*pkrb_realmofhost
)(cellconfig
->hostName
[0]));
1390 if ((*pkrb_get_krbhst
)(krbhst
, krbrlm
, 1) != KSUCCESS
)
1396 p
= strchr(cellconfig
->hostName
[0], '.');
1398 StringCbCopyA(krbrlm
, sizeof(krbrlm
), p
);
1400 StringCbCopyA(krbrlm
, sizeof(krbrlm
), cellconfig
->name
);
1401 #if _MSC_VER >= 1400
1402 _strupr_s(krbrlm
, sizeof(krbrlm
));
1413 /**************************************/
1414 /* afs_get_cellconfig(): */
1415 /**************************************/
1417 afs_get_cellconfig(char *cell
, afs_conf_cell
*cellconfig
, char *local_cell
)
1421 char linkedCell
[MAXCELLCHARS
]="";
1423 local_cell
[0] = (char)0;
1424 memset(cellconfig
, 0, sizeof(*cellconfig
));
1426 cellconfig
->cbsize
= sizeof(*cellconfig
);
1428 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
1429 if (rc
= cm_GetRootCellName(local_cell
)) {
1433 if (strlen(cell
) == 0)
1434 StringCbCopyA(cell
, (MAXCELLCHARS
+1) * sizeof(char), local_cell
);
1436 StringCbCopyA(cellconfig
->name
, (MAXCELLCHARS
+1) * sizeof(char), cell
);
1438 rc
= cm_SearchCellRegistry(1, cell
, NULL
, linkedCell
,
1439 afs_get_cellconfig_callback
, (void*) cellconfig
);
1440 if (rc
&& rc
!= CM_ERROR_FORCE_DNS_LOOKUP
)
1441 rc
= cm_SearchCellFileEx(cell
, NULL
, linkedCell
, afs_get_cellconfig_callback
,
1444 rc
= cm_SearchCellByDNS(cell
, NULL
, &ttl
,
1445 afs_get_cellconfig_callback
,
1446 (void*) cellconfig
);
1449 cellconfig
->linkedCell
= strdup(linkedCell
);
1454 /**************************************/
1455 /* afs_get_cellconfig_callback(): */
1456 /**************************************/
1458 afs_get_cellconfig_callback(void *cellconfig
,
1459 struct sockaddr_in
*addrp
,
1461 unsigned short ipRank
)
1463 afs_conf_cell
*cc
= (afs_conf_cell
*)cellconfig
;
1465 cc
->hostAddr
[cc
->numServers
] = *addrp
;
1466 StringCbCopyA(cc
->hostName
[cc
->numServers
],
1467 sizeof(cc
->hostName
[0]), namep
);
1473 /**************************************/
1474 /* afs_report_error(): */
1475 /**************************************/
1477 afs_report_error(LONG rc
, LPCSTR FailedFunctionName
)
1480 const char *errText
;
1482 // Using AFS defines as error messages for now, until Transarc
1483 // gets back to me with "string" translations of each of these
1485 if (rc
== KTC_ERROR
)
1486 errText
= "KTC_ERROR";
1487 else if (rc
== KTC_TOOBIG
)
1488 errText
= "KTC_TOOBIG";
1489 else if (rc
== KTC_INVAL
)
1490 errText
= "KTC_INVAL";
1491 else if (rc
== KTC_NOENT
)
1492 errText
= "KTC_NOENT";
1493 else if (rc
== KTC_PIOCTLFAIL
)
1494 errText
= "KTC_PIOCTLFAIL";
1495 else if (rc
== KTC_NOPIOCTL
)
1496 errText
= "KTC_NOPIOCTL";
1497 else if (rc
== KTC_NOCELL
)
1498 errText
= "KTC_NOCELL";
1499 else if (rc
== KTC_NOCM
)
1500 errText
= "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
1502 errText
= "Unknown error!";
1504 StringCbPrintfA(message
, sizeof(message
),
1505 "%s\n(%s failed)", errText
, FailedFunctionName
);
1506 _report_cs1(KHERR_ERROR
, L
"%1!S!", _cptr(message
));
1512 GetServiceStatus(LPSTR lpszMachineName
,
1513 LPSTR lpszServiceName
,
1514 DWORD
*lpdwCurrentState
,
1515 DWORD
*lpdwWaitHint
)
1518 SC_HANDLE schSCManager
= NULL
;
1519 SC_HANDLE schService
= NULL
;
1520 DWORD fdwDesiredAccess
= 0;
1521 SERVICE_STATUS ssServiceStatus
= {0};
1524 *lpdwCurrentState
= 0;
1526 fdwDesiredAccess
= GENERIC_READ
;
1528 schSCManager
= OpenSCManagerA(lpszMachineName
,
1532 if(schSCManager
== NULL
) {
1533 hr
= GetLastError();
1537 schService
= OpenServiceA(schSCManager
,
1541 if(schService
== NULL
) {
1542 hr
= GetLastError();
1546 fRet
= QueryServiceStatus(schService
,
1550 hr
= GetLastError();
1554 *lpdwCurrentState
= ssServiceStatus
.dwCurrentState
;
1556 *lpdwWaitHint
= ssServiceStatus
.dwWaitHint
;
1559 CloseServiceHandle(schService
);
1560 CloseServiceHandle(schSCManager
);
1565 DWORD
ServiceControl(LPSTR lpszMachineName
,
1566 LPSTR lpszServiceName
,
1570 SC_HANDLE schSCManager
= NULL
;
1571 SC_HANDLE schService
= NULL
;
1572 DWORD fdwDesiredAccess
= 0;
1573 SERVICE_STATUS ssServiceStatus
= {0};
1575 DWORD dwCurrentState
= 0;
1579 fdwDesiredAccess
= GENERIC_READ
;
1581 schSCManager
= OpenSCManagerA(lpszMachineName
, NULL
,
1584 if(schSCManager
== NULL
) {
1585 hr
= GetLastError();
1589 fdwDesiredAccess
= GENERIC_READ
| GENERIC_EXECUTE
;
1591 schService
= OpenServiceA(schSCManager
, lpszServiceName
,
1594 if(schService
== NULL
) {
1595 hr
= GetLastError();
1599 fRet
= QueryServiceStatus(schService
, &ssServiceStatus
);
1602 hr
= GetLastError();
1606 dwCurrentState
= ssServiceStatus
.dwCurrentState
;
1608 if (dwCurrentState
== SERVICE_STOPPED
&&
1609 dwNewState
== SERVICE_RUNNING
) {
1611 fRet
= StartService(schService
, 0, NULL
);
1613 if (fRet
== FALSE
) {
1614 hr
= GetLastError();
1619 if (dwCurrentState
== SERVICE_RUNNING
&&
1620 dwNewState
== SERVICE_STOPPED
) {
1621 fRet
= ControlService(schService
, SERVICE_CONTROL_STOP
,
1624 if (fRet
== FALSE
) {
1625 hr
= GetLastError();
1632 CloseServiceHandle(schService
);
1633 CloseServiceHandle(schSCManager
);
1639 afs_check_for_cell_realm_match(khm_handle identity
, char * cell
) {
1640 char local_cell
[MAXCELLCHARS
];
1641 wchar_t wrealm
[MAXCELLCHARS
];
1642 wchar_t idname
[KCDB_IDENT_MAXCCH_NAME
];
1646 afs_conf_cell cellconfig
;
1649 ZeroMemory(local_cell
, sizeof(local_cell
));
1650 ZeroMemory(&cellconfig
, sizeof(cellconfig
));
1652 rc
= afs_get_cellconfig(cell
, &cellconfig
, local_cell
);
1656 realm
= afs_realm_of_cell(&cellconfig
, FALSE
);
1657 if (cellconfig
.linkedCell
)
1658 free(cellconfig
.linkedCell
);
1659 if (!realm
[0]) /* referral; assume it matches */
1662 AnsiStrToUnicode(wrealm
, sizeof(wrealm
), realm
);
1664 cb
= sizeof(idname
);
1666 kcdb_identity_get_name(identity
, idname
, &cb
);
1668 atsign
= wcschr(idname
, L
'@');
1669 if (atsign
&& atsign
[1] && !_wcsicmp(atsign
+ 1, wrealm
)) {