2 * Copyright (c) 2005,2006,2007, 2008 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)
32 #include <afsconfig.h>
33 #include <afs/param.h>
37 #include<krb5common.h>
43 static char *afs_realm_of_cell(afs_conf_cell *, BOOL);
44 static long afs_get_cellconfig_callback(void *, struct sockaddr_in *, char *, unsigned short ipRank);
45 static int afs_get_cellconfig(char *, afs_conf_cell *, char *);
48 afs_is_running(void) {
54 if (GetServiceStatus(NULL, TRANSARCAFSDAEMON,
55 &CurrentState, NULL) != NOERROR)
57 if (CurrentState != SERVICE_RUNNING)
68 if (!afs_is_running())
71 rc = ktc_ForgetAllTokens();
77 afs_unlog_cred(khm_handle cred)
80 struct ktc_principal princ;
82 wchar_t name[KCDB_MAXCCH_NAME];
84 if (!afs_is_running())
87 cbbuf = sizeof(princ);
88 if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_server_princ,
89 NULL, &princ, &cbbuf)))
92 afs_princ_to_string(&princ, name, sizeof(name));
94 _report_cs1(KHERR_INFO, L"Destroying token %1!s!",
98 rc = ktc_ForgetToken(&princ);
103 /* convert a ktc_principal to a wchar_t string form that looks like
104 name.instance@cell return 0 if it worked. non-zero otherwise
107 afs_princ_to_string(struct ktc_principal * p,
115 l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->name);
118 rv = FAILED(StringCbCopy(buf, cbbuf, wbuf));
120 StringCbCat(buf, cbbuf, L".");
121 if((l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->instance)) > 0) {
123 rv = rv || FAILED(StringCbCat(buf, cbbuf, wbuf));
129 rv = rv || FAILED(StringCbCat(buf, cbbuf, L"@"));
130 if((l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->cell)) > 0) {
132 rv = rv || FAILED(StringCbCat(buf, cbbuf, wbuf));
142 afs_list_tokens(void)
146 kcdb_credset_flush(afs_credset);
147 r = afs_list_tokens_internal();
148 kcdb_credset_collect(NULL, afs_credset, NULL, afs_credtype_id, NULL);
151 afs_icon_set_state(AFSICON_REPORT_TOKENS, afs_credset);
152 } else if (r == -1) {
153 afs_icon_set_state(AFSICON_SERVICE_STOPPED, NULL);
155 afs_icon_set_state(AFSICON_SERVICE_ERROR, NULL);
161 /* is the credential provided an AFS token and is it from the
163 static khm_int32 KHMAPI
164 afs_filter_by_cell(khm_handle cred, khm_int32 flags, void * rock)
166 wchar_t wcell[MAXCELLCHARS];
171 tcell = (wchar_t *) rock;
173 if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
174 type != afs_credtype_id)
177 cbsize = sizeof(wcell);
178 if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell,
179 NULL, wcell, &cbsize)))
182 if(wcscmp(wcell, tcell))
188 struct token_filter_data {
193 afs_filter_for_token(khm_handle cred, khm_int32 flags, void * rock) {
194 struct token_filter_data * pdata;
195 wchar_t ccell[MAXCELLCHARS];
199 pdata = (struct token_filter_data *) rock;
201 if (KHM_FAILED(kcdb_cred_get_type(cred, &ctype)) ||
202 ctype != afs_credtype_id)
208 if (KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell,
212 _wcsicmp(ccell, pdata->cell))
220 afs_find_token(khm_handle credset, wchar_t * cell) {
221 struct token_filter_data fdata;
222 khm_handle cred = NULL;
226 if (KHM_FAILED(kcdb_credset_find_filtered(credset,
228 afs_filter_for_token,
237 static khm_int32 KHMAPI
238 afs_filter_krb5_tkt(khm_handle cred, khm_int32 flags, void * rock)
240 wchar_t cname[KCDB_CRED_MAXCCH_NAME];
243 wchar_t * t, *tkt_cell;
246 tcell = (wchar_t *) rock;
248 if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
249 type != krb5_credtype_id)
252 cbsize = sizeof(cname);
253 if (KHM_FAILED(kcdb_cred_get_name(cred, cname, &cbsize)))
256 if (!wcsncmp(cname, L"afs/", 4)) {
258 tkt_cell = cname + 4;
260 t = wcschr(tkt_cell, L'@');
265 } else if (!wcsncmp(cname, L"afs@", 4)) {
267 tkt_cell = cname + 4;
273 if (_wcsicmp(tcell, tkt_cell))
279 static khm_int32 KHMAPI
280 afs_filter_krb4_tkt(khm_handle cred, khm_int32 flags, void * rock)
282 wchar_t cname[KCDB_CRED_MAXCCH_NAME];
285 wchar_t * t, *tkt_cell;
288 tcell = (wchar_t *) rock;
290 if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
291 type != krb4_credtype_id)
294 cbsize = sizeof(cname);
295 if (KHM_FAILED(kcdb_cred_get_name(cred, cname, &cbsize)))
298 if (!wcsncmp(cname, L"afs.", 4)) {
300 tkt_cell = cname + 4;
302 t = wcschr(tkt_cell, L'@');
307 } else if (!wcsncmp(cname, L"afs@", 4)) {
309 tkt_cell = cname + 4;
315 if (_wcsicmp(tcell, tkt_cell))
321 /* collects all AFS tokens to the root credential set using the
322 generic afs_credset credential set
325 afs_list_tokens_internal(void)
327 struct ktc_principal aserver;
328 struct ktc_principal aclient;
329 struct ktc_token atoken;
334 wchar_t location[256];
339 khm_handle ident = NULL;
340 khm_handle cred = NULL;
341 afs_tk_method method;
345 if (!afs_is_running())
348 kcdb_credset_flush(afs_credset);
350 LoadString(hResModule, IDS_DEF_LOCATION, location, ARRAYLENGTH(location));
356 memset(&aserver, 0, sizeof(aserver));
357 if (rc = ktc_ListTokens(cellNum, &cellNum, &aserver))
366 memset(&atoken, '\0', sizeof(atoken));
367 if (rc = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient))
376 /* failed attempt at trying to figure out the principal name from
377 the token. The ticket that is attached to the token is not
378 in a form that is useful at this point */
380 if(atoken.kvno == RXKAD_TKT_TYPE_KERBEROS_V5) {
381 krb5_context ctx = 0;
384 krb5_error_code code;
387 code = khm_krb5_initialize(&ctx, &cc);
391 k5c = (krb5_creds *) atoken.ticket;
393 code = pkrb5_unparse_name(ctx, k5c->client, &princ);
397 MultiByteToWideChar(CP_ACP, 0, princ, strlen(princ), idname, sizeof(idname)/sizeof(idname[0]));
399 pkrb5_free_unparsed_name(ctx, princ);
405 method = AFS_TOKEN_AUTO;
407 afs_princ_to_string(&aclient, idname, sizeof(idname));
409 /* We need to figure out a good client name which we can use
410 to create an identity which looks familiar to the user. No
411 good way of doing this, so we use a heuristic.
413 Note that, we use another heuristic to find out which
414 identity to associate the token with.
418 The assumption here is that the principal for the token is
421 if realm != cell : principal looks like user@realm@cell
422 if realm == cell : principal looks like user@realm
426 We strip the part of the string that follows the second '@'
427 sign to obtain the 'user@realm' part, which we use as the
428 credential name. If there is no second '@', we use the
429 whole principal name. */
433 ats = wcschr(idname, L'@');
434 if(ats && (ats = wcschr(ats + 1, L'@')))
438 afs_princ_to_string(&aserver, crname, sizeof(crname));
440 /* Ok, now we need to figure out which identity to associate
441 this token with. This is a little bit tricky, and there is
442 currently no good way of determining the original identity
443 used to obtain the token if it was done outside of
444 NetIDMgr. So we use a heuristic here.
448 Elsewhere, (actually in afsnewcreds.c) just after obtaining
449 AFS tokens through NetIDMgr, we enumerate the AFS tokens
450 and assign the root identity (used to obtain new creds)
451 with the AFS tokens. This would still be there in the root
452 credential set when we list tokens later on.
456 If there exists an AFS token in the root credential set for
457 the same cell, we associate this token with the same
458 identity as that credential.
460 cell = wcschr(crname, L'@');
471 if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
477 kcdb_cred_get_identity(c, &ident);
479 kcdb_cred_get_attr(c, afs_attr_method, NULL,
481 kcdb_cred_release(c);
485 /* If that failed, we have try another trick. If there is a
486 Krb5 ticket of the form afs/<cell>@<realm> or afs@<CELL>
487 where <cell> matches our cell, then we pick the identity
492 If Krb5 was used to obtain the token, then there is a Krb5
493 ticket of the form afs/<cell>@<REALM> or afs@<CELL> still
494 in the cache. This is also true for Krb524 token
499 If such a Krb5 ticket is found, use the identity of that
500 credential as the identity of the AFS token.
503 if (ident == NULL && cell != NULL) {
506 if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
510 kcdb_cred_get_identity(c, &ident);
511 /* this could be Krb5 or Krb524, so we leave method at
513 method = AFS_TOKEN_AUTO;
514 kcdb_cred_release(c);
518 /* If that didn't work either, we look for a Krb4 ticket of
519 the form afs.<cell>@<REALM> or afs@<CELL> which matches the
524 If Krb4 was used to obtain an AFS token, then there should
525 be a Krb4 ticket of the form afs.<cell>@<REALM> or
526 afs@<CELL> in the cache.
530 If such a ticket is found, then use the identity of that
531 credential as the identity of the AFS token.
533 if (ident == NULL && cell != NULL) {
536 if (krb4_credtype_id < 0) {
537 kcdb_credtype_get_id(KRB4_CREDTYPE_NAME,
541 if (krb4_credtype_id >= 0 &&
542 KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
547 kcdb_cred_get_identity(c, &ident);
548 kcdb_cred_release(c);
549 method = AFS_TOKEN_KRB4;
554 /* Finally, we allow any extension plugins to give this a shot */
555 if (ident == NULL && cell != NULL) {
556 afs_ext_resolve_token(cell,
564 /* One more thing to try. If we have a cell->identity
565 mapping, then we try that. */
566 if (ident == NULL && cell != NULL) {
567 khm_handle h_cellmap;
568 wchar_t tidname[KCDB_IDENT_MAXCCH_NAME];
571 cb = sizeof(tidname);
573 if (KHM_SUCCEEDED(khc_open_space(csp_afscred,
576 if (KHM_SUCCEEDED(khc_read_string(h_cellmap,
580 kcdb_identity_create(tidname,
581 KCDB_IDENT_FLAG_CREATE,
584 khc_close_space(h_cellmap);
588 /* all else failed */
590 if(KHM_FAILED(kcdb_identity_create(idname,
591 KCDB_IDENT_FLAG_CREATE,
596 if(KHM_FAILED(kcdb_cred_create(crname, ident, afs_credtype_id, &cred)))
599 kcdb_cred_set_attr(cred, afs_attr_method, &method, sizeof(method));
601 TimetToFileTime(atoken.endTime, &ft);
602 kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &ft, sizeof(ft));
603 if (atoken.startTime != 0) {
604 TimetToFileTime(atoken.startTime, &ft);
605 kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft));
607 kcdb_cred_set_attr(cred, afs_attr_client_princ,
608 &aclient, sizeof(aclient));
609 kcdb_cred_set_attr(cred, afs_attr_server_princ,
610 &aserver, sizeof(aserver));
613 kcdb_cred_set_attr(cred, afs_attr_cell, cell, (khm_size)KCDB_CBSIZE_AUTO);
616 kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION,
617 location, (khm_size)KCDB_CBSIZE_AUTO);
619 kcdb_credset_add_cred(afs_credset, cred, -1);
621 /* both these calls are NULL pointer safe */
622 kcdb_cred_release(cred);
624 kcdb_identity_release(ident);
630 kcdb_identity_release(ident);
632 kcdb_cred_release(cred);
638 #define ALLOW_REGISTER 1
640 ViceIDToUsername(char *username,
644 struct ktc_principal *aclient,
645 struct ktc_principal *aserver,
646 struct ktc_token *atoken)
648 static char lastcell[MAXCELLCHARS+1] = { 0 };
649 static char confname[512] = { 0 };
650 char username_copy[BUFSIZ];
651 long viceId = ANONYMOUSID; /* AFS uid of user */
653 #ifdef ALLOW_REGISTER
655 #endif /* ALLOW_REGISTER */
657 if (confname[0] == '\0') {
658 StringCbCopyA(confname, sizeof(confname), AFSDIR_CLIENT_ETC_DIRPATH);
661 StringCbCopyA(lastcell, sizeof(lastcell), aserver->cell);
663 if (!pr_Initialize (0, confname, aserver->cell)) {
664 char sname[PR_MAXNAMELEN];
665 StringCbCopyA(sname, sizeof(sname), username);
666 status = pr_SNameToId (sname, &viceId);
670 #ifdef AFS_ID_TO_NAME
672 * This is a crock, but it is Transarc's crock, so
673 * we have to play along in order to get the
674 * functionality. The way the afs id is stored is
675 * as a string in the username field of the token.
676 * Contrary to what you may think by looking at
677 * the code for tokens, this hack (AFS ID %d) will
678 * not work if you change %d to something else.
680 #endif /* AFS_ID_TO_NAME */
682 * This code is taken from cklog -- it lets people
683 * automatically register with the ptserver in foreign cells
686 /* copy the username because pr_CreateUser will lowercase it */
687 StringCbCopyA(username_copy, BUFSIZ, username);
689 #ifdef ALLOW_REGISTER
691 if (viceId != ANONYMOUSID) {
692 #else /* ALLOW_REGISTER */
693 if ((status == 0) && (viceId != ANONYMOUSID))
694 #endif /* ALLOW_REGISTER */
696 #ifdef AFS_ID_TO_NAME
697 StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
698 #endif /* AFS_ID_TO_NAME */
700 #ifdef ALLOW_REGISTER
701 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
703 StringCbCopyA(aclient->name, sizeof(aclient->name), username);
704 StringCbCopyA(aclient->instance, sizeof(aclient->instance), "");
705 StringCbCopyA(aclient->cell, sizeof(aclient->cell), realm_of_user);
706 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
708 if (status = pr_Initialize(1L, confname, aserver->cell))
710 status = pr_CreateUser(username, &id);
712 StringCbCopyA(username, BUFSIZ, username_copy);
713 #ifdef AFS_ID_TO_NAME
714 StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
715 #endif /* AFS_ID_TO_NAME */
718 #endif /* ALLOW_REGISTER */
724 copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) {
725 krb5_error_code code;
729 code = pkrb5_decode_ticket(&v5cred->ticket, &ticket);
731 len = krb5_princ_realm(context, ticket->server)->length;
732 if (len > destlen - 1)
735 StringCbCopyA(dest, len, krb5_princ_realm(context, ticket->server)->data);
737 pkrb5_free_ticket(context, ticket);
742 afs_klog(khm_handle identity,
747 afs_tk_method method,
748 time_t * tok_expiration,
753 struct ktc_principal aserver;
754 struct ktc_principal aclient;
755 char realm_of_user[MAXKTCREALMLEN]; /* Kerberos realm of user */
756 char realm_of_cell[MAXKTCREALMLEN]; /* Kerberos realm of cell */
757 char local_cell[MAXCELLCHARS+1];
758 char Dmycell[MAXCELLCHARS+1];
759 struct ktc_token atoken;
760 struct ktc_token btoken;
761 afs_conf_cell ak_cellconfig; /* General information about the cell */
764 char ServiceName[128];
765 khm_handle confighandle = NULL;
766 khm_int32 supports_krb4 = (pkrb_get_tf_realm == NULL ? 0 : 1);
767 khm_int32 got524cred = 0;
770 BOOL bGotCreds = FALSE; /* got creds? */
773 *tok_expiration = (time_t) 0;
775 if (!afs_is_running()) {
776 _report_sr0(KHERR_WARNING, IDS_ERR_NOSERVICE);
780 if ( !realm ) realm = "";
781 if ( !cell ) cell = "";
782 if ( !service ) service = "";
784 memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
785 memset(RealmName, '\0', sizeof(RealmName));
786 memset(CellName, '\0', sizeof(CellName));
787 memset(ServiceName, '\0', sizeof(ServiceName));
788 memset(realm_of_user, '\0', sizeof(realm_of_user));
789 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
790 memset(Dmycell, '\0', sizeof(Dmycell));
792 // NULL or empty cell returns information on local cell
794 StringCbCopyA(Dmycell, sizeof(Dmycell), cell);
796 rc = afs_get_cellconfig(Dmycell, &ak_cellconfig, local_cell);
798 _reportf(L"afs_get_cellconfig returns %ld", rc);
800 _report_sr2(KHERR_ERROR, IDS_ERR_CELLCONFIG, _cstr(Dmycell), _int32(rc));
801 _suggest_sr(IDS_ERR_CELLCONFIG_S, KHERR_SUGGEST_NONE);
806 if (linkedCell && ak_cellconfig.linkedCell)
807 StringCbCopyA(linkedCell, MAXCELLCHARS,
808 ak_cellconfig.linkedCell);
810 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
811 afs_realm_of_cell(&ak_cellconfig, FALSE));
813 if (strlen(service) == 0)
814 StringCbCopyA(ServiceName, sizeof(ServiceName), "afs");
816 StringCbCopyA(ServiceName, sizeof(ServiceName), service);
818 if (strlen(cell) == 0)
819 StringCbCopyA(CellName, sizeof(CellName), local_cell);
821 StringCbCopyA(CellName, sizeof(CellName), cell);
823 if (strlen(realm) == 0)
824 StringCbCopyA(RealmName, sizeof(RealmName), realm_of_cell);
826 StringCbCopyA(RealmName, sizeof(RealmName), realm);
828 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 pkrb5_cc_get_principal(context, k5cc, &client_principal);
856 i = krb5_princ_realm(context, client_principal)->length;
857 if (i > MAXKTCREALMLEN-1)
858 i = MAXKTCREALMLEN-1;
859 StringCchCopyNA(realm_of_user, ARRAYLENGTH(realm_of_user),
860 krb5_princ_realm(context, client_principal)->data,
863 _reportf(L"khm_krb5_initialize returns code %d", r);
867 increds.client = client_principal;
868 increds.times.endtime = 0;
869 /* Ask for DES since that is what V4 understands */
870 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
872 #ifdef KRB5_TC_NOTICKET
873 flags = KRB5_TC_OPENCLOSE;
874 r = pkrb5_cc_set_flags(context, k5cc, flags);
876 if (strlen(realm) != 0) {
878 /* First try Service/Cell@REALM */
879 if (r = pkrb5_build_principal(context, &increds.server,
885 _reportf(L"krb5_build_principal returns %d", r);
889 r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
890 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
891 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
892 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
893 /* Next try Service@REALM */
894 pkrb5_free_principal(context, increds.server);
895 r = pkrb5_build_principal(context, &increds.server,
901 r = pkrb5_get_credentials(context, 0, k5cc,
905 /* Check to make sure we received a valid ticket; if not remove it
906 * and try again. Perhaps there are two service tickets for the
907 * same service in the ccache.
909 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
910 pkrb5_free_principal(context, increds.server);
911 pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
912 pkrb5_free_creds(context, k5creds);
914 goto retry_retcred_1;
918 /* First try Service/Cell@_CLIENT_REALM */
919 if (r = pkrb5_build_principal(context, &increds.server,
920 (int) strlen(realm_of_user),
925 _reportf(L"krb5_build_principal returns %d", r);
929 r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
931 /* the user realm is a valid cell realm */
932 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell), realm_of_user);
934 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
935 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
936 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
937 pkrb5_free_principal(context, increds.server);
938 r = pkrb5_build_principal(context, &increds.server,
939 (int) strlen(realm_of_cell),
945 r = pkrb5_get_credentials(context, 0, k5cc,
948 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
949 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
950 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
951 strlen(realm_of_cell) == 0) {
952 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
953 afs_realm_of_cell(&ak_cellconfig, TRUE));
955 pkrb5_free_principal(context, increds.server);
956 r = pkrb5_build_principal(context, &increds.server,
957 (int) strlen(realm_of_cell),
963 r = pkrb5_get_credentials(context, 0, k5cc,
966 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
967 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
968 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
969 /* Next try Service@REALM */
970 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
971 afs_realm_of_cell(&ak_cellconfig, FALSE));
973 pkrb5_free_principal(context, increds.server);
974 r = pkrb5_build_principal(context, &increds.server,
975 (int) strlen(realm_of_cell),
980 r = pkrb5_get_credentials(context, 0, k5cc,
983 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
984 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
985 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
986 strlen(realm_of_cell) == 0) {
987 /* Next try Service@REALM */
988 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
989 afs_realm_of_cell(&ak_cellconfig, TRUE));
991 pkrb5_free_principal(context, increds.server);
992 r = pkrb5_build_principal(context, &increds.server,
993 (int) strlen(realm_of_cell),
998 r = pkrb5_get_credentials(context, 0, k5cc,
1002 if (r == 0 && strlen(realm_of_cell) == 0)
1003 copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
1005 /* Check to make sure we received a valid ticket; if not remove it
1006 * and try again. Perhaps there are two service tickets for the
1007 * same service in the ccache.
1009 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
1010 pkrb5_free_principal(context, increds.server);
1011 pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
1012 pkrb5_free_creds(context, k5creds);
1014 goto retry_retcred_2;
1018 pkrb5_free_principal(context, increds.server);
1019 pkrb5_free_principal(context, client_principal);
1020 client_principal = 0;
1021 #ifdef KRB5_TC_NOTICKET
1022 flags = KRB5_TC_OPENCLOSE | KRB5_TC_NOTICKET;
1023 pkrb5_cc_set_flags(context, k5cc, flags);
1026 (void) pkrb5_cc_close(context, k5cc);
1030 _reportf(L"Code %d while getting credentials", r);
1035 if ( k5creds->ticket.length > MAXKTCTICKETLEN ||
1036 method == AFS_TOKEN_KRB524) {
1040 /* This code inserts the entire K5 ticket into the token */
1042 _reportf(L"Trying K5 SetToken");
1044 memset(&aserver, '\0', sizeof(aserver));
1045 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1046 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1048 memset(&atoken, '\0', sizeof(atoken));
1049 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
1050 atoken.startTime = k5creds->times.starttime;
1051 atoken.endTime = k5creds->times.endtime;
1052 memcpy(&atoken.sessionKey,
1053 k5creds->keyblock.contents,
1054 k5creds->keyblock.length);
1055 atoken.ticketLen = k5creds->ticket.length;
1056 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
1059 *tok_expiration = k5creds->times.endtime;
1062 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
1063 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
1064 if ( rc == KTC_NOCM && retry < 20 ) {
1067 goto retry_gettoken5;
1072 if (atoken.kvno == btoken.kvno &&
1073 atoken.ticketLen == btoken.ticketLen &&
1074 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1075 sizeof(atoken.sessionKey)) &&
1076 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1079 if (k5creds && context)
1080 pkrb5_free_creds(context, k5creds);
1083 pkrb5_free_context(context);
1085 _reportf(L"Same token already exists");
1091 // * Reset the "aclient" structure before we call ktc_SetToken.
1092 // * This structure was first set by the ktc_GetToken call when
1093 // * we were comparing whether identical tokens already existed.
1095 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
1096 StringCchCopyNA(aclient.name, MAXKTCNAMELEN,
1097 k5creds->client->data[0].data, len);
1099 if ( k5creds->client->length > 1 ) {
1100 StringCbCatA(aclient.name, sizeof(aclient.name), ".");
1101 p = aclient.name + strlen(aclient.name);
1102 len = (int) min(k5creds->client->data[1].length,
1103 MAXKTCNAMELEN - strlen(aclient.name) - 1);
1104 StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
1105 k5creds->client->data[1].data, len);
1108 aclient.instance[0] = '\0';
1110 StringCbCopyA(aclient.cell, sizeof(aclient.cell), realm_of_cell);
1112 StringCbCatA(aclient.name, sizeof(aclient.name), "@");
1113 p = aclient.name + strlen(aclient.name);
1114 len = (int) min(k5creds->client->realm.length,
1115 MAXKTCNAMELEN - strlen(aclient.name) - 1);
1116 StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
1117 k5creds->client->realm.data, len);
1119 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1120 &aclient, &aserver, &atoken);
1122 rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
1126 if (k5creds && context)
1127 pkrb5_free_creds(context, k5creds);
1130 pkrb5_free_context(context);
1135 _reportf(L"SetToken returns code %d", rc);
1139 _reportf(L"Trying Krb524");
1141 if (pkrb524_convert_creds_kdc &&
1142 (method == AFS_TOKEN_AUTO || method == AFS_TOKEN_KRB524)) {
1143 /* This requires krb524d to be running with the KDC */
1144 r = pkrb524_convert_creds_kdc(context, k5creds, &creds);
1146 _reportf(L"Code %d while converting credentials", r);
1155 if (client_principal)
1156 pkrb5_free_principal(context, client_principal);
1158 if (k5creds && context)
1159 pkrb5_free_creds(context, k5creds);
1162 pkrb5_free_context(context);
1168 if (supports_krb4) {
1169 kcdb_identity_get_config(identity, 0, &confighandle);
1170 khc_read_int32(confighandle, L"Krb4Cred\\Krb4NewCreds", &supports_krb4);
1171 khc_close_space(confighandle);
1175 _reportf(L"Kerberos 4 not configured");
1177 if (!bGotCreds && supports_krb4 &&
1178 strlen(RealmName) < REALM_SZ &&
1179 (method == AFS_TOKEN_AUTO ||
1180 method == AFS_TOKEN_KRB4)) {
1184 _reportf(L"Trying Kerberos 4");
1186 if (!realm_of_user[0] ) {
1187 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user))
1189 /* can't determine realm of user */
1190 _reportf(L"krb_get_tf_realm returns %d", rc);
1195 _reportf(L"Trying to find %S.%S@%S", ServiceName, CellName, RealmName);
1196 rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
1197 if (rc == NO_TKT_FIL) {
1198 // if the problem is that we have no krb4 tickets
1199 // do not attempt to continue
1200 _reportf(L"krb_get_cred returns %d (no ticket file)", rc);
1204 if (rc != KSUCCESS) {
1205 _reportf(L"Trying to find %S@%S", ServiceName, RealmName);
1206 rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
1209 if (rc != KSUCCESS) {
1210 _reportf(L"Trying to obtain new ticket");
1211 if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1212 CellName, RealmName, 0))
1214 if ((rc = (*pkrb_get_cred)(ServiceName, CellName,
1215 RealmName, &creds)) != KSUCCESS) {
1218 _reportf(L"Got %S.%S@%S", ServiceName, CellName, RealmName);
1220 } else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1223 if ((rc = (*pkrb_get_cred)(ServiceName, "",
1224 RealmName, &creds)) != KSUCCESS) {
1227 _reportf(L"Got %S@%S", ServiceName, RealmName);
1242 memset(&aserver, '\0', sizeof(aserver));
1243 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1244 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1246 memset(&atoken, '\0', sizeof(atoken));
1247 atoken.kvno = (short)creds.kvno;
1248 atoken.startTime = creds.issue_date;
1249 atoken.endTime = (*pkrb_life_to_time)(creds.issue_date,creds.lifetime);
1250 memcpy(&atoken.sessionKey, creds.session, 8);
1251 atoken.ticketLen = creds.ticket_st.length;
1252 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
1255 *tok_expiration = atoken.endTime;
1257 if (!(rc = ktc_GetToken(&aserver, &btoken,
1258 sizeof(btoken), &aclient)) &&
1259 atoken.kvno == btoken.kvno &&
1260 atoken.ticketLen == btoken.ticketLen &&
1261 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1262 sizeof(atoken.sessionKey)) &&
1263 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1270 // Reset the "aclient" structure before we call ktc_SetToken.
1271 // This structure was first set by the ktc_GetToken call when
1272 // we were comparing whether identical tokens already existed.
1274 StringCchCopyA(aclient.name, MAXKTCNAMELEN, creds.pname);
1275 if (creds.pinst[0]) {
1276 StringCchCatA(aclient.name, MAXKTCNAMELEN, ".");
1277 StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.pinst);
1280 StringCbCopyA(aclient.instance, sizeof(aclient.instance), "");
1282 StringCchCatA(aclient.name, MAXKTCNAMELEN, "@");
1283 StringCchCatA(aclient.name, MAXKTCNAMELEN, got524cred ? realm_of_user : creds.realm);
1285 StringCbCopyA(aclient.cell, sizeof(aclient.cell), CellName);
1287 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1288 &aclient, &aserver, &atoken);
1290 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
1291 afs_report_error(rc, "ktc_SetToken()");
1294 } else if (method == AFS_TOKEN_AUTO ||
1295 method >= AFS_TOKEN_USER) {
1296 /* we couldn't get a token using Krb5, Krb524 or Krb4, either
1297 because we couldn't get the necessary credentials or
1298 because the method was set to not use those. Now we
1299 dispatch to any extensions to see if they have better
1302 rc = !afs_ext_klog(method,
1310 /* if the return code was not set, we should set it now.
1311 Otherwise we let the code go through. */
1313 /* No tokens were obtained. We should report something */
1314 _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
1318 rc = KHM_ERROR_GENERAL;
1323 if (ak_cellconfig.linkedCell)
1324 free(ak_cellconfig.linkedCell);
1329 /**************************************/
1330 /* afs_realm_of_cell(): */
1331 /**************************************/
1333 afs_realm_of_cell(afs_conf_cell *cellconfig, BOOL referral_fallback)
1335 char krbhst[MAX_HSTNM]="";
1336 static char krbrlm[MAXKTCREALMLEN+1]="";
1337 krb5_context ctx = 0;
1338 char ** realmlist=NULL;
1339 krb5_error_code r = 0;
1344 if (referral_fallback) {
1346 p = strchr(cellconfig->hostName[0], '.');
1348 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1350 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1351 #if _MSC_VER >= 1400
1352 _strupr_s(krbrlm, sizeof(krbrlm));
1357 if ( pkrb5_init_context ) {
1358 r = pkrb5_init_context(&ctx);
1360 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
1361 if ( !r && realmlist && realmlist[0] ) {
1362 StringCbCopyA(krbrlm, sizeof(krbrlm), realmlist[0]);
1363 pkrb5_free_host_realm(ctx, realmlist);
1366 pkrb5_free_context(ctx);
1370 if (pkrb_get_krbhst && pkrb_realmofhost) {
1371 StringCbCopyA(krbrlm, sizeof(krbrlm),
1372 (char *)(*pkrb_realmofhost)(cellconfig->hostName[0]));
1373 if ((*pkrb_get_krbhst)(krbhst, krbrlm, 1) != KSUCCESS)
1379 p = strchr(cellconfig->hostName[0], '.');
1381 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1383 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1384 #if _MSC_VER >= 1400
1385 _strupr_s(krbrlm, sizeof(krbrlm));
1395 /**************************************/
1396 /* afs_get_cellconfig(): */
1397 /**************************************/
1399 afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
1403 char linkedCell[MAXCELLCHARS]="";
1405 local_cell[0] = (char)0;
1406 memset(cellconfig, 0, sizeof(*cellconfig));
1408 cellconfig->cbsize = sizeof(*cellconfig);
1410 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
1411 if (rc = cm_GetRootCellName(local_cell)) {
1415 if (strlen(cell) == 0)
1416 StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
1418 StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
1420 rc = cm_SearchCellRegistry(1, cell, NULL, linkedCell,
1421 afs_get_cellconfig_callback, (void*) cellconfig);
1422 if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
1423 rc = cm_SearchCellFileEx(cell, NULL, linkedCell, afs_get_cellconfig_callback,
1426 rc = cm_SearchCellByDNS(cell, NULL, &ttl,
1427 afs_get_cellconfig_callback,
1428 (void*) cellconfig);
1431 cellconfig->linkedCell = _strdup(linkedCell);
1436 /**************************************/
1437 /* afs_get_cellconfig_callback(): */
1438 /**************************************/
1440 afs_get_cellconfig_callback(void *cellconfig,
1441 struct sockaddr_in *addrp,
1443 unsigned short ipRank)
1445 afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
1447 cc->hostAddr[cc->numServers] = *addrp;
1448 StringCbCopyA(cc->hostName[cc->numServers],
1449 sizeof(cc->hostName[0]), namep);
1455 /**************************************/
1456 /* afs_report_error(): */
1457 /**************************************/
1459 afs_report_error(LONG rc, LPCSTR FailedFunctionName)
1462 const char *errText;
1464 // Using AFS defines as error messages for now, until Transarc
1465 // gets back to me with "string" translations of each of these
1467 if (rc == KTC_ERROR)
1468 errText = "KTC_ERROR";
1469 else if (rc == KTC_TOOBIG)
1470 errText = "KTC_TOOBIG";
1471 else if (rc == KTC_INVAL)
1472 errText = "KTC_INVAL";
1473 else if (rc == KTC_NOENT)
1474 errText = "KTC_NOENT";
1475 else if (rc == KTC_PIOCTLFAIL)
1476 errText = "KTC_PIOCTLFAIL";
1477 else if (rc == KTC_NOPIOCTL)
1478 errText = "KTC_NOPIOCTL";
1479 else if (rc == KTC_NOCELL)
1480 errText = "KTC_NOCELL";
1481 else if (rc == KTC_NOCM)
1482 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
1484 errText = "Unknown error!";
1486 StringCbPrintfA(message, sizeof(message),
1487 "%s\n(%s failed)", errText, FailedFunctionName);
1488 _report_cs1(KHERR_ERROR, L"%1!S!", _cptr(message));
1494 GetServiceStatus(LPSTR lpszMachineName,
1495 LPSTR lpszServiceName,
1496 DWORD *lpdwCurrentState,
1497 DWORD *lpdwWaitHint)
1500 SC_HANDLE schSCManager = NULL;
1501 SC_HANDLE schService = NULL;
1502 DWORD fdwDesiredAccess = 0;
1503 SERVICE_STATUS ssServiceStatus = {0};
1506 *lpdwCurrentState = 0;
1508 fdwDesiredAccess = GENERIC_READ;
1510 schSCManager = OpenSCManagerA(lpszMachineName,
1514 if(schSCManager == NULL) {
1515 hr = GetLastError();
1519 schService = OpenServiceA(schSCManager,
1523 if(schService == NULL) {
1524 hr = GetLastError();
1528 fRet = QueryServiceStatus(schService,
1532 hr = GetLastError();
1536 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
1538 *lpdwWaitHint = ssServiceStatus.dwWaitHint;
1541 CloseServiceHandle(schService);
1542 CloseServiceHandle(schSCManager);
1547 DWORD ServiceControl(LPSTR lpszMachineName,
1548 LPSTR lpszServiceName,
1552 SC_HANDLE schSCManager = NULL;
1553 SC_HANDLE schService = NULL;
1554 DWORD fdwDesiredAccess = 0;
1555 SERVICE_STATUS ssServiceStatus = {0};
1557 DWORD dwCurrentState = 0;
1561 fdwDesiredAccess = GENERIC_READ;
1563 schSCManager = OpenSCManagerA(lpszMachineName, NULL,
1566 if(schSCManager == NULL) {
1567 hr = GetLastError();
1571 fdwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
1573 schService = OpenServiceA(schSCManager, lpszServiceName,
1576 if(schService == NULL) {
1577 hr = GetLastError();
1581 fRet = QueryServiceStatus(schService, &ssServiceStatus);
1584 hr = GetLastError();
1588 dwCurrentState = ssServiceStatus.dwCurrentState;
1590 if (dwCurrentState == SERVICE_STOPPED &&
1591 dwNewState == SERVICE_RUNNING) {
1593 fRet = StartService(schService, 0, NULL);
1595 if (fRet == FALSE) {
1596 hr = GetLastError();
1601 if (dwCurrentState == SERVICE_RUNNING &&
1602 dwNewState == SERVICE_STOPPED) {
1603 fRet = ControlService(schService, SERVICE_CONTROL_STOP,
1606 if (fRet == FALSE) {
1607 hr = GetLastError();
1614 CloseServiceHandle(schService);
1615 CloseServiceHandle(schSCManager);
1621 afs_check_for_cell_realm_match(khm_handle identity, char * cell) {
1622 char local_cell[MAXCELLCHARS];
1623 wchar_t wrealm[MAXCELLCHARS];
1624 wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
1628 afs_conf_cell cellconfig;
1631 ZeroMemory(local_cell, sizeof(local_cell));
1632 ZeroMemory(&cellconfig, sizeof(cellconfig));
1634 rc = afs_get_cellconfig(cell, &cellconfig, local_cell);
1638 realm = afs_realm_of_cell(&cellconfig, FALSE);
1639 if (cellconfig.linkedCell)
1640 free(cellconfig.linkedCell);
1641 if (!realm[0]) /* referral; assume it matches */
1644 AnsiStrToUnicode(wrealm, sizeof(wrealm), realm);
1646 cb = sizeof(idname);
1648 kcdb_identity_get_name(identity, idname, &cb);
1650 atsign = wcschr(idname, L'@');
1651 if (atsign && atsign[1] && !_wcsicmp(atsign + 1, wrealm)) {