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 krb5_cc_get_principal(context, k5cc, &client_principal);
856 StringCchCopyA(realm_of_user, ARRAYLENGTH(realm_of_user),
857 krb5_principal_get_realm(context, client_principal));
859 _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.session.keytype = ENCTYPE_DES_CBC_CRC;
872 #ifdef KRB5_TC_NOTICKET
873 flags = KRB5_TC_OPENCLOSE;
874 r = krb5_cc_set_flags(context, k5cc, flags);
876 if (strlen(realm) != 0) {
878 /* First try Service/Cell@REALM */
879 if (r = krb5_build_principal(context, &increds.server,
885 _reportf(L"krb5_build_principal returns %d", r);
889 r = krb5_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 krb5_free_principal(context, increds.server);
895 r = krb5_build_principal(context, &increds.server,
901 r = krb5_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 krb5_free_principal(context, increds.server);
911 krb5_cc_remove_cred(context, k5cc, 0, k5creds);
912 krb5_free_creds(context, k5creds);
914 goto retry_retcred_1;
918 /* First try Service/Cell@_CLIENT_REALM */
919 if (r = krb5_build_principal(context, &increds.server,
920 (int) strlen(realm_of_user),
925 _reportf(L"krb5_build_principal returns %d", r);
929 r = krb5_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 krb5_free_principal(context, increds.server);
938 r = krb5_build_principal(context, &increds.server,
939 (int) strlen(realm_of_cell),
945 r = krb5_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 krb5_free_principal(context, increds.server);
956 r = krb5_build_principal(context, &increds.server,
957 (int) strlen(realm_of_cell),
963 r = krb5_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 krb5_free_principal(context, increds.server);
974 r = krb5_build_principal(context, &increds.server,
975 (int) strlen(realm_of_cell),
980 r = krb5_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 krb5_free_principal(context, increds.server);
992 r = krb5_build_principal(context, &increds.server,
993 (int) strlen(realm_of_cell),
998 r = krb5_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
1006 * remove it and try again. Perhaps there are two service
1007 * tickets for the same service in the ccache.
1009 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
1010 krb5_free_principal(context, increds.server);
1011 krb5_cc_remove_cred(context, k5cc, 0, k5creds);
1012 krb5_free_creds(context, k5creds);
1014 goto retry_retcred_2;
1018 krb5_free_principal(context, increds.server);
1019 krb5_free_principal(context, client_principal);
1020 client_principal = 0;
1021 #ifdef KRB5_TC_NOTICKET
1022 flags = KRB5_TC_OPENCLOSE | KRB5_TC_NOTICKET;
1023 krb5_cc_set_flags(context, k5cc, flags);
1026 (void) krb5_cc_close(context, k5cc);
1030 _reportf(L"Code %d while getting credentials", r);
1036 if ( k5creds->ticket.length > MAXKTCTICKETLEN ||
1037 method == AFS_TOKEN_KRB524) {
1042 /* This code inserts the entire K5 ticket into the token */
1044 _reportf(L"Trying K5 SetToken");
1046 memset(&aserver, '\0', sizeof(aserver));
1047 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1048 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1050 memset(&atoken, '\0', sizeof(atoken));
1051 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
1052 atoken.startTime = k5creds->times.starttime;
1053 atoken.endTime = k5creds->times.endtime;
1054 memcpy(&atoken.sessionKey,
1055 k5creds->session.keyvalue.data,
1056 k5creds->session.keyvalue.length);
1057 atoken.ticketLen = k5creds->ticket.length;
1058 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
1061 *tok_expiration = k5creds->times.endtime;
1064 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
1065 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
1066 if ( rc == KTC_NOCM && retry < 20 ) {
1069 goto retry_gettoken5;
1078 if (atoken.kvno == btoken.kvno &&
1079 atoken.ticketLen == btoken.ticketLen &&
1080 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1081 sizeof(atoken.sessionKey)) &&
1082 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1085 if (k5creds && context)
1086 krb5_free_creds(context, k5creds);
1089 krb5_free_context(context);
1091 _reportf(L"Same token already exists");
1097 // * Reset the "aclient" structure before we call ktc_SetToken.
1098 // * This structure was first set by the ktc_GetToken call when
1099 // * we were comparing whether identical tokens already existed.
1101 StringCchCopyA(aclient.name, MAXKTCNAMELEN,
1102 krb5_principal_get_comp_string(context, k5creds->client, 0));
1104 if ( krb5_principal_get_num_comp(context, k5creds->client) > 1 ) {
1105 StringCbCatA(aclient.name, sizeof(aclient.name), ".");
1106 StringCbCatA(aclient.name, sizeof(aclient.name),
1107 krb5_principal_get_comp_string(context, k5creds->client, 1));
1110 aclient.instance[0] = '\0';
1112 StringCbCopyA(aclient.cell, sizeof(aclient.cell), realm_of_cell);
1114 StringCbCatA(aclient.name, sizeof(aclient.name), "@");
1115 StringCbCatA(aclient.name, sizeof(aclient.name),
1116 krb5_principal_get_realm(context, k5creds->client));
1118 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1119 &aclient, &aserver, &atoken);
1121 rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
1125 if (k5creds && context)
1126 krb5_free_creds(context, k5creds);
1129 krb5_free_context(context);
1134 _reportf(L"SetToken returns code %d", rc);
1139 _reportf(L"Trying Krb524");
1141 if (krb524_convert_creds_kdc &&
1142 (method == AFS_TOKEN_AUTO || method == AFS_TOKEN_KRB524)) {
1143 /* This requires krb524d to be running with the KDC */
1144 r = krb524_convert_creds_kdc(context, k5creds, &creds);
1146 _reportf(L"Code %d while converting credentials", r);
1156 if (client_principal)
1157 krb5_free_principal(context, client_principal);
1159 if (k5creds && context)
1160 krb5_free_creds(context, k5creds);
1163 krb5_free_context(context);
1170 if (supports_krb4) {
1171 kcdb_identity_get_config(identity, 0, &confighandle);
1172 khc_read_int32(confighandle, L"Krb4Cred\\Krb4NewCreds", &supports_krb4);
1173 khc_close_space(confighandle);
1177 _reportf(L"Kerberos 4 not configured");
1179 if (!bGotCreds && supports_krb4 &&
1180 strlen(RealmName) < REALM_SZ &&
1181 (method == AFS_TOKEN_AUTO ||
1182 method == AFS_TOKEN_KRB4)) {
1186 _reportf(L"Trying Kerberos 4");
1188 if (!realm_of_user[0] ) {
1189 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user))
1191 /* can't determine realm of user */
1192 _reportf(L"krb_get_tf_realm returns %d", rc);
1197 _reportf(L"Trying to find %S.%S@%S", ServiceName, CellName, RealmName);
1198 rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
1199 if (rc == NO_TKT_FIL) {
1200 // if the problem is that we have no krb4 tickets
1201 // do not attempt to continue
1202 _reportf(L"krb_get_cred returns %d (no ticket file)", rc);
1206 if (rc != KSUCCESS) {
1207 _reportf(L"Trying to find %S@%S", ServiceName, RealmName);
1208 rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
1211 if (rc != KSUCCESS) {
1212 _reportf(L"Trying to obtain new ticket");
1213 if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1214 CellName, RealmName, 0))
1216 if ((rc = (*pkrb_get_cred)(ServiceName, CellName,
1217 RealmName, &creds)) != KSUCCESS) {
1220 _reportf(L"Got %S.%S@%S", ServiceName, CellName, RealmName);
1222 } else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1225 if ((rc = (*pkrb_get_cred)(ServiceName, "",
1226 RealmName, &creds)) != KSUCCESS) {
1229 _reportf(L"Got %S@%S", ServiceName, RealmName);
1244 memset(&aserver, '\0', sizeof(aserver));
1245 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1246 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1248 memset(&atoken, '\0', sizeof(atoken));
1249 atoken.kvno = (short)creds.kvno;
1250 atoken.startTime = creds.issue_date;
1251 atoken.endTime = (*pkrb_life_to_time)(creds.issue_date,creds.lifetime);
1252 memcpy(&atoken.sessionKey, creds.session, 8);
1253 atoken.ticketLen = creds.ticket_st.length;
1254 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
1257 *tok_expiration = atoken.endTime;
1259 if (!(rc = ktc_GetToken(&aserver, &btoken,
1260 sizeof(btoken), &aclient)) &&
1261 atoken.kvno == btoken.kvno &&
1262 atoken.ticketLen == btoken.ticketLen &&
1263 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1264 sizeof(atoken.sessionKey)) &&
1265 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1272 // Reset the "aclient" structure before we call ktc_SetToken.
1273 // This structure was first set by the ktc_GetToken call when
1274 // we were comparing whether identical tokens already existed.
1276 StringCchCopyA(aclient.name, MAXKTCNAMELEN, creds.pname);
1277 if (creds.pinst[0]) {
1278 StringCchCatA(aclient.name, MAXKTCNAMELEN, ".");
1279 StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.pinst);
1282 StringCbCopyA(aclient.instance, sizeof(aclient.instance), "");
1284 StringCchCatA(aclient.name, MAXKTCNAMELEN, "@");
1285 StringCchCatA(aclient.name, MAXKTCNAMELEN, got524cred ? realm_of_user : creds.realm);
1287 StringCbCopyA(aclient.cell, sizeof(aclient.cell), CellName);
1289 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1290 &aclient, &aserver, &atoken);
1292 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
1293 afs_report_error(rc, "ktc_SetToken()");
1300 (method == AFS_TOKEN_AUTO ||
1301 method >= AFS_TOKEN_USER)) {
1302 /* we couldn't get a token using Krb5, Krb524 or Krb4,
1303 either because we couldn't get the necessary
1304 credentials or because the method was set to not use
1305 those. Now we dispatch to any extensions to see if
1306 they have better luck. */
1308 rc = !afs_ext_klog(method,
1315 } else if (!bGotCreds) {
1316 /* if the return code was not set, we should set it now.
1317 Otherwise we let the code go through. */
1319 /* No tokens were obtained. We should report something */
1320 _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
1324 rc = KHM_ERROR_GENERAL;
1329 if (ak_cellconfig.linkedCell)
1330 free(ak_cellconfig.linkedCell);
1335 /**************************************/
1336 /* afs_realm_of_cell(): */
1337 /**************************************/
1339 afs_realm_of_cell(afs_conf_cell *cellconfig, BOOL referral_fallback)
1341 char krbhst[MAX_HSTNM]="";
1342 static char krbrlm[MAXKTCREALMLEN+1]="";
1343 krb5_context ctx = 0;
1344 char ** realmlist=NULL;
1345 krb5_error_code r = 0;
1350 if (referral_fallback) {
1352 p = strchr(cellconfig->hostName[0], '.');
1354 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1356 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1357 #if _MSC_VER >= 1400
1358 _strupr_s(krbrlm, sizeof(krbrlm));
1363 r = krb5_init_context(&ctx);
1365 r = krb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
1366 if ( !r && realmlist && realmlist[0] ) {
1367 StringCbCopyA(krbrlm, sizeof(krbrlm), realmlist[0]);
1368 krb5_free_host_realm(ctx, realmlist);
1371 krb5_free_context(ctx);
1375 if (pkrb_get_krbhst && pkrb_realmofhost) {
1376 StringCbCopyA(krbrlm, sizeof(krbrlm),
1377 (char *)(*pkrb_realmofhost)(cellconfig->hostName[0]));
1378 if ((*pkrb_get_krbhst)(krbhst, krbrlm, 1) != KSUCCESS)
1384 p = strchr(cellconfig->hostName[0], '.');
1386 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1388 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1389 #if _MSC_VER >= 1400
1390 _strupr_s(krbrlm, sizeof(krbrlm));
1401 /**************************************/
1402 /* afs_get_cellconfig(): */
1403 /**************************************/
1405 afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
1409 char linkedCell[MAXCELLCHARS]="";
1411 local_cell[0] = (char)0;
1412 memset(cellconfig, 0, sizeof(*cellconfig));
1414 cellconfig->cbsize = sizeof(*cellconfig);
1416 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
1417 if (rc = cm_GetRootCellName(local_cell)) {
1421 if (strlen(cell) == 0)
1422 StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
1424 StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
1426 rc = cm_SearchCellRegistry(1, cell, NULL, linkedCell,
1427 afs_get_cellconfig_callback, (void*) cellconfig);
1428 if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
1429 rc = cm_SearchCellFileEx(cell, NULL, linkedCell, afs_get_cellconfig_callback,
1432 rc = cm_SearchCellByDNS(cell, NULL, &ttl,
1433 afs_get_cellconfig_callback,
1434 (void*) cellconfig);
1437 cellconfig->linkedCell = _strdup(linkedCell);
1442 /**************************************/
1443 /* afs_get_cellconfig_callback(): */
1444 /**************************************/
1446 afs_get_cellconfig_callback(void *cellconfig,
1447 struct sockaddr_in *addrp,
1449 unsigned short ipRank)
1451 afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
1453 cc->hostAddr[cc->numServers] = *addrp;
1454 StringCbCopyA(cc->hostName[cc->numServers],
1455 sizeof(cc->hostName[0]), namep);
1461 /**************************************/
1462 /* afs_report_error(): */
1463 /**************************************/
1465 afs_report_error(LONG rc, LPCSTR FailedFunctionName)
1468 const char *errText;
1470 // Using AFS defines as error messages for now, until Transarc
1471 // gets back to me with "string" translations of each of these
1473 if (rc == KTC_ERROR)
1474 errText = "KTC_ERROR";
1475 else if (rc == KTC_TOOBIG)
1476 errText = "KTC_TOOBIG";
1477 else if (rc == KTC_INVAL)
1478 errText = "KTC_INVAL";
1479 else if (rc == KTC_NOENT)
1480 errText = "KTC_NOENT";
1481 else if (rc == KTC_PIOCTLFAIL)
1482 errText = "KTC_PIOCTLFAIL";
1483 else if (rc == KTC_NOPIOCTL)
1484 errText = "KTC_NOPIOCTL";
1485 else if (rc == KTC_NOCELL)
1486 errText = "KTC_NOCELL";
1487 else if (rc == KTC_NOCM)
1488 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
1490 errText = "Unknown error!";
1492 StringCbPrintfA(message, sizeof(message),
1493 "%s\n(%s failed)", errText, FailedFunctionName);
1494 _report_cs1(KHERR_ERROR, L"%1!S!", _cptr(message));
1500 GetServiceStatus(LPSTR lpszMachineName,
1501 LPSTR lpszServiceName,
1502 DWORD *lpdwCurrentState,
1503 DWORD *lpdwWaitHint)
1506 SC_HANDLE schSCManager = NULL;
1507 SC_HANDLE schService = NULL;
1508 DWORD fdwDesiredAccess = 0;
1509 SERVICE_STATUS ssServiceStatus = {0};
1512 *lpdwCurrentState = 0;
1514 fdwDesiredAccess = GENERIC_READ;
1516 schSCManager = OpenSCManagerA(lpszMachineName,
1520 if(schSCManager == NULL) {
1521 hr = GetLastError();
1525 schService = OpenServiceA(schSCManager,
1529 if(schService == NULL) {
1530 hr = GetLastError();
1534 fRet = QueryServiceStatus(schService,
1538 hr = GetLastError();
1542 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
1544 *lpdwWaitHint = ssServiceStatus.dwWaitHint;
1547 CloseServiceHandle(schService);
1548 CloseServiceHandle(schSCManager);
1553 DWORD ServiceControl(LPSTR lpszMachineName,
1554 LPSTR lpszServiceName,
1558 SC_HANDLE schSCManager = NULL;
1559 SC_HANDLE schService = NULL;
1560 DWORD fdwDesiredAccess = 0;
1561 SERVICE_STATUS ssServiceStatus = {0};
1563 DWORD dwCurrentState = 0;
1567 fdwDesiredAccess = GENERIC_READ;
1569 schSCManager = OpenSCManagerA(lpszMachineName, NULL,
1572 if(schSCManager == NULL) {
1573 hr = GetLastError();
1577 fdwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
1579 schService = OpenServiceA(schSCManager, lpszServiceName,
1582 if(schService == NULL) {
1583 hr = GetLastError();
1587 fRet = QueryServiceStatus(schService, &ssServiceStatus);
1590 hr = GetLastError();
1594 dwCurrentState = ssServiceStatus.dwCurrentState;
1596 if (dwCurrentState == SERVICE_STOPPED &&
1597 dwNewState == SERVICE_RUNNING) {
1599 fRet = StartService(schService, 0, NULL);
1601 if (fRet == FALSE) {
1602 hr = GetLastError();
1607 if (dwCurrentState == SERVICE_RUNNING &&
1608 dwNewState == SERVICE_STOPPED) {
1609 fRet = ControlService(schService, SERVICE_CONTROL_STOP,
1612 if (fRet == FALSE) {
1613 hr = GetLastError();
1620 CloseServiceHandle(schService);
1621 CloseServiceHandle(schSCManager);
1627 afs_check_for_cell_realm_match(khm_handle identity, char * cell) {
1628 char local_cell[MAXCELLCHARS];
1629 wchar_t wrealm[MAXCELLCHARS];
1630 wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
1634 afs_conf_cell cellconfig;
1637 ZeroMemory(local_cell, sizeof(local_cell));
1638 ZeroMemory(&cellconfig, sizeof(cellconfig));
1640 rc = afs_get_cellconfig(cell, &cellconfig, local_cell);
1644 realm = afs_realm_of_cell(&cellconfig, FALSE);
1645 if (cellconfig.linkedCell)
1646 free(cellconfig.linkedCell);
1647 if (!realm[0]) /* referral; assume it matches */
1650 AnsiStrToUnicode(wrealm, sizeof(wrealm), realm);
1652 cb = sizeof(idname);
1654 kcdb_identity_get_name(identity, idname, &cb);
1656 atsign = wcschr(idname, L'@');
1657 if (atsign && atsign[1] && !_wcsicmp(atsign + 1, wrealm)) {