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))
372 method = AFS_TOKEN_AUTO;
374 afs_princ_to_string(&aclient, idname, sizeof(idname));
376 /* We need to figure out a good client name which we can use
377 to create an identity which looks familiar to the user. No
378 good way of doing this, so we use a heuristic.
380 Note that, we use another heuristic to find out which
381 identity to associate the token with.
385 The assumption here is that the principal for the token is
388 if realm != cell : principal looks like user@realm@cell
389 if realm == cell : principal looks like user@realm
393 We strip the part of the string that follows the second '@'
394 sign to obtain the 'user@realm' part, which we use as the
395 credential name. If there is no second '@', we use the
396 whole principal name. */
400 ats = wcschr(idname, L'@');
401 if(ats && (ats = wcschr(ats + 1, L'@')))
405 afs_princ_to_string(&aserver, crname, sizeof(crname));
407 /* Ok, now we need to figure out which identity to associate
408 this token with. This is a little bit tricky, and there is
409 currently no good way of determining the original identity
410 used to obtain the token if it was done outside of
411 NetIDMgr. So we use a heuristic here.
415 Elsewhere, (actually in afsnewcreds.c) just after obtaining
416 AFS tokens through NetIDMgr, we enumerate the AFS tokens
417 and assign the root identity (used to obtain new creds)
418 with the AFS tokens. This would still be there in the root
419 credential set when we list tokens later on.
423 If there exists an AFS token in the root credential set for
424 the same cell, we associate this token with the same
425 identity as that credential.
427 cell = wcschr(crname, L'@');
438 if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
444 kcdb_cred_get_identity(c, &ident);
446 kcdb_cred_get_attr(c, afs_attr_method, NULL,
448 kcdb_cred_release(c);
452 /* If that failed, we have try another trick. If there is a
453 Krb5 ticket of the form afs/<cell>@<realm> or afs@<CELL>
454 where <cell> matches our cell, then we pick the identity
459 If Krb5 was used to obtain the token, then there is a Krb5
460 ticket of the form afs/<cell>@<REALM> or afs@<CELL> still
461 in the cache. This is also true for Krb524 token
466 If such a Krb5 ticket is found, use the identity of that
467 credential as the identity of the AFS token.
470 if (ident == NULL && cell != NULL) {
473 if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
477 kcdb_cred_get_identity(c, &ident);
478 /* this could be Krb5 or Krb524, so we leave method at
480 method = AFS_TOKEN_AUTO;
481 kcdb_cred_release(c);
485 /* If that didn't work either, we look for a Krb4 ticket of
486 the form afs.<cell>@<REALM> or afs@<CELL> which matches the
491 If Krb4 was used to obtain an AFS token, then there should
492 be a Krb4 ticket of the form afs.<cell>@<REALM> or
493 afs@<CELL> in the cache.
497 If such a ticket is found, then use the identity of that
498 credential as the identity of the AFS token.
500 if (ident == NULL && cell != NULL) {
503 if (krb4_credtype_id < 0) {
504 kcdb_credtype_get_id(KRB4_CREDTYPE_NAME,
508 if (krb4_credtype_id >= 0 &&
509 KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
514 kcdb_cred_get_identity(c, &ident);
515 kcdb_cred_release(c);
516 method = AFS_TOKEN_KRB4;
521 /* Finally, we allow any extension plugins to give this a shot */
522 if (ident == NULL && cell != NULL) {
523 afs_ext_resolve_token(cell,
531 /* One more thing to try. If we have a cell->identity
532 mapping, then we try that. */
533 if (ident == NULL && cell != NULL) {
534 khm_handle h_cellmap;
535 wchar_t tidname[KCDB_IDENT_MAXCCH_NAME];
538 cb = sizeof(tidname);
540 if (KHM_SUCCEEDED(khc_open_space(csp_afscred,
543 if (KHM_SUCCEEDED(khc_read_string(h_cellmap,
547 kcdb_identity_create(tidname,
548 KCDB_IDENT_FLAG_CREATE,
551 khc_close_space(h_cellmap);
555 /* all else failed */
557 if(KHM_FAILED(kcdb_identity_create(idname,
558 KCDB_IDENT_FLAG_CREATE,
563 if(KHM_FAILED(kcdb_cred_create(crname, ident, afs_credtype_id, &cred)))
566 kcdb_cred_set_attr(cred, afs_attr_method, &method, sizeof(method));
568 TimetToFileTime(atoken.endTime, &ft);
569 kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &ft, sizeof(ft));
570 if (atoken.startTime != 0) {
571 TimetToFileTime(atoken.startTime, &ft);
572 kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft));
574 kcdb_cred_set_attr(cred, afs_attr_client_princ,
575 &aclient, sizeof(aclient));
576 kcdb_cred_set_attr(cred, afs_attr_server_princ,
577 &aserver, sizeof(aserver));
580 kcdb_cred_set_attr(cred, afs_attr_cell, cell, (khm_size)KCDB_CBSIZE_AUTO);
583 kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION,
584 location, (khm_size)KCDB_CBSIZE_AUTO);
586 kcdb_credset_add_cred(afs_credset, cred, -1);
588 /* both these calls are NULL pointer safe */
589 kcdb_cred_release(cred);
591 kcdb_identity_release(ident);
597 kcdb_identity_release(ident);
599 kcdb_cred_release(cred);
605 #define ALLOW_REGISTER 1
607 ViceIDToUsername(char *username,
611 struct ktc_principal *aclient,
612 struct ktc_principal *aserver,
613 struct ktc_token *atoken)
615 static char lastcell[MAXCELLCHARS+1] = { 0 };
616 static char confname[512] = { 0 };
617 char username_copy[BUFSIZ];
618 long viceId = ANONYMOUSID; /* AFS uid of user */
620 #ifdef ALLOW_REGISTER
622 #endif /* ALLOW_REGISTER */
624 if (confname[0] == '\0') {
625 StringCbCopyA(confname, sizeof(confname), AFSDIR_CLIENT_ETC_DIRPATH);
628 StringCbCopyA(lastcell, sizeof(lastcell), aserver->cell);
630 if (!pr_Initialize (0, confname, aserver->cell)) {
631 char sname[PR_MAXNAMELEN];
632 StringCbCopyA(sname, sizeof(sname), username);
633 status = pr_SNameToId (sname, &viceId);
637 #ifdef AFS_ID_TO_NAME
639 * This is a crock, but it is Transarc's crock, so
640 * we have to play along in order to get the
641 * functionality. The way the afs id is stored is
642 * as a string in the username field of the token.
643 * Contrary to what you may think by looking at
644 * the code for tokens, this hack (AFS ID %d) will
645 * not work if you change %d to something else.
647 #endif /* AFS_ID_TO_NAME */
649 * This code is taken from cklog -- it lets people
650 * automatically register with the ptserver in foreign cells
653 /* copy the username because pr_CreateUser will lowercase it */
654 StringCbCopyA(username_copy, BUFSIZ, username);
656 #ifdef ALLOW_REGISTER
658 if (viceId != ANONYMOUSID) {
659 #else /* ALLOW_REGISTER */
660 if ((status == 0) && (viceId != ANONYMOUSID))
661 #endif /* ALLOW_REGISTER */
663 #ifdef AFS_ID_TO_NAME
664 StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
665 #endif /* AFS_ID_TO_NAME */
667 #ifdef ALLOW_REGISTER
668 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
670 StringCbCopyA(aclient->name, sizeof(aclient->name), username);
671 StringCbCopyA(aclient->instance, sizeof(aclient->instance), "");
672 StringCbCopyA(aclient->cell, sizeof(aclient->cell), realm_of_user);
673 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
675 if (status = pr_Initialize(1L, confname, aserver->cell))
677 status = pr_CreateUser(username, &id);
679 StringCbCopyA(username, BUFSIZ, username_copy);
680 #ifdef AFS_ID_TO_NAME
681 StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
682 #endif /* AFS_ID_TO_NAME */
685 #endif /* ALLOW_REGISTER */
691 copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) {
696 ret = decode_Ticket(v5cred->ticket.data, v5cred->ticket.length,
699 StringCbCopyA(dest, destlen, ticket.realm);
701 free_Ticket(&ticket);
706 afs_klog(khm_handle identity,
711 afs_tk_method method,
712 time_t * tok_expiration,
719 struct ktc_principal aserver;
720 struct ktc_principal aclient;
721 char realm_of_user[MAXKTCREALMLEN]; /* Kerberos realm of user */
722 char realm_of_cell[MAXKTCREALMLEN]; /* Kerberos realm of cell */
723 char local_cell[MAXCELLCHARS+1];
724 char Dmycell[MAXCELLCHARS+1];
725 struct ktc_token atoken;
726 struct ktc_token btoken;
727 afs_conf_cell ak_cellconfig; /* General information about the cell */
730 char ServiceName[128];
731 khm_handle confighandle = NULL;
733 khm_int32 supports_krb4 = (pkrb_get_tf_realm == NULL ? 0 : 1);
734 khm_int32 got524cred = 0;
738 BOOL bGotCreds = FALSE; /* got creds? */
741 *tok_expiration = (time_t) 0;
743 if (!afs_is_running()) {
744 _report_sr0(KHERR_WARNING, IDS_ERR_NOSERVICE);
748 if ( !realm ) realm = "";
749 if ( !cell ) cell = "";
750 if ( !service ) service = "";
752 memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
753 memset(RealmName, '\0', sizeof(RealmName));
754 memset(CellName, '\0', sizeof(CellName));
755 memset(ServiceName, '\0', sizeof(ServiceName));
756 memset(realm_of_user, '\0', sizeof(realm_of_user));
757 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
758 memset(Dmycell, '\0', sizeof(Dmycell));
760 // NULL or empty cell returns information on local cell
762 StringCbCopyA(Dmycell, sizeof(Dmycell), cell);
764 rc = afs_get_cellconfig(Dmycell, &ak_cellconfig, local_cell);
766 _reportf(L"afs_get_cellconfig returns %ld", rc);
768 _report_sr2(KHERR_ERROR, IDS_ERR_CELLCONFIG, _cstr(Dmycell), _int32(rc));
769 _suggest_sr(IDS_ERR_CELLCONFIG_S, KHERR_SUGGEST_NONE);
774 if (linkedCell && ak_cellconfig.linkedCell)
775 StringCbCopyA(linkedCell, MAXCELLCHARS,
776 ak_cellconfig.linkedCell);
778 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
779 afs_realm_of_cell(&ak_cellconfig, FALSE));
781 if (strlen(service) == 0)
782 StringCbCopyA(ServiceName, sizeof(ServiceName), "afs");
784 StringCbCopyA(ServiceName, sizeof(ServiceName), service);
786 if (strlen(cell) == 0)
787 StringCbCopyA(CellName, sizeof(CellName), local_cell);
789 StringCbCopyA(CellName, sizeof(CellName), cell);
791 if (strlen(realm) == 0)
792 StringCbCopyA(RealmName, sizeof(RealmName), realm_of_cell);
794 StringCbCopyA(RealmName, sizeof(RealmName), realm);
797 memset(&creds, '\0', sizeof(creds));
800 /*** Kerberos 5 and 524 ***/
802 if (method == AFS_TOKEN_AUTO ||
803 method == AFS_TOKEN_KRB5 ||
804 method == AFS_TOKEN_KRB524) {
806 krb5_context context = 0;
807 krb5_ccache k5cc = 0;
809 krb5_creds * k5creds = 0;
811 krb5_principal client_principal = 0;
812 krb5_flags flags = 0;
818 _reportf(L"Trying Kerberos 5");
820 if (!(r = khm_krb5_initialize(identity, &context, &k5cc))) {
823 memset(&increds, 0, sizeof(increds));
825 r = krb5_cc_get_principal(context, k5cc, &client_principal);
827 StringCchCopyA(realm_of_user, ARRAYLENGTH(realm_of_user),
828 krb5_principal_get_realm(context, client_principal));
830 _reportf(L"krb5_cc_get_principal returns code %d", r);
838 _reportf(L"khm_krb5_initialize returns code %d", r);
846 increds.client = client_principal;
847 increds.times.endtime = 0;
848 /* Ask for DES since that is what V4 understands */
849 if (method == AFS_TOKEN_KRB524)
850 increds.session.keytype = ENCTYPE_DES_CBC_CRC;
852 #ifdef KRB5_TC_NOTICKET
853 flags = KRB5_TC_OPENCLOSE;
854 r = krb5_cc_set_flags(context, k5cc, flags);
856 if (strlen(realm) != 0) {
858 /* First try Service/Cell@REALM */
859 if (r = krb5_build_principal(context, &increds.server,
865 _reportf(L"krb5_build_principal returns %d", r);
869 r = krb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
870 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
871 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
872 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
873 /* Next try Service@REALM */
874 krb5_free_principal(context, increds.server);
875 r = krb5_build_principal(context, &increds.server,
881 r = krb5_get_credentials(context, 0, k5cc,
885 /* Check to make sure we received a valid ticket; if not remove it
886 * and try again. Perhaps there are two service tickets for the
887 * same service in the ccache.
889 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
890 krb5_free_principal(context, increds.server);
891 krb5_cc_remove_cred(context, k5cc, 0, k5creds);
892 krb5_free_creds(context, k5creds);
894 goto retry_retcred_1;
898 /* First try Service/Cell@_CLIENT_REALM */
899 if (r = krb5_build_principal(context, &increds.server,
900 (int) strlen(realm_of_user),
905 _reportf(L"krb5_build_principal returns %d", r);
909 r = krb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
911 /* the user realm is a valid cell realm */
912 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell), realm_of_user);
914 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
915 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
916 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
917 krb5_free_principal(context, increds.server);
918 r = krb5_build_principal(context, &increds.server,
919 (int) strlen(realm_of_cell),
925 r = krb5_get_credentials(context, 0, k5cc,
928 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
929 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
930 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
931 strlen(realm_of_cell) == 0) {
932 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
933 afs_realm_of_cell(&ak_cellconfig, TRUE));
935 krb5_free_principal(context, increds.server);
936 r = krb5_build_principal(context, &increds.server,
937 (int) strlen(realm_of_cell),
943 r = krb5_get_credentials(context, 0, k5cc,
946 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
947 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
948 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
949 /* Next try Service@REALM */
950 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
951 afs_realm_of_cell(&ak_cellconfig, FALSE));
953 krb5_free_principal(context, increds.server);
954 r = krb5_build_principal(context, &increds.server,
955 (int) strlen(realm_of_cell),
960 r = krb5_get_credentials(context, 0, k5cc,
963 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
964 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
965 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
966 strlen(realm_of_cell) == 0) {
967 /* Next try Service@REALM */
968 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
969 afs_realm_of_cell(&ak_cellconfig, TRUE));
971 krb5_free_principal(context, increds.server);
972 r = krb5_build_principal(context, &increds.server,
973 (int) strlen(realm_of_cell),
978 r = krb5_get_credentials(context, 0, k5cc,
982 if (r == 0 && strlen(realm_of_cell) == 0)
983 copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
985 /* Check to make sure we received a valid ticket; if not
986 * remove it and try again. Perhaps there are two service
987 * tickets for the same service in the ccache.
989 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
990 krb5_free_principal(context, increds.server);
991 krb5_cc_remove_cred(context, k5cc, 0, k5creds);
992 krb5_free_creds(context, k5creds);
994 goto retry_retcred_2;
998 krb5_free_principal(context, increds.server);
999 krb5_free_principal(context, client_principal);
1000 client_principal = 0;
1001 #ifdef KRB5_TC_NOTICKET
1002 flags = KRB5_TC_OPENCLOSE | KRB5_TC_NOTICKET;
1003 krb5_cc_set_flags(context, k5cc, flags);
1006 (void) krb5_cc_close(context, k5cc);
1010 _reportf(L"Code %d while getting credentials", r);
1016 if ( k5creds->ticket.length > MAXKTCTICKETLEN ||
1017 method == AFS_TOKEN_KRB524) {
1022 /* This code inserts the entire K5 ticket into the token */
1024 _reportf(L"Trying K5 SetToken");
1026 memset(&aserver, '\0', sizeof(aserver));
1027 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1028 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1030 memset(&atoken, '\0', sizeof(atoken));
1031 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
1032 atoken.startTime = k5creds->times.starttime;
1033 atoken.endTime = k5creds->times.endtime;
1034 if (tkt_DeriveDesKey(k5creds->session.keytype,
1035 k5creds->session.keyvalue.data,
1036 k5creds->session.keyvalue.length,
1037 &atoken.sessionKey))
1039 atoken.ticketLen = k5creds->ticket.length;
1040 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
1043 *tok_expiration = k5creds->times.endtime;
1046 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
1047 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
1048 if ( rc == KTC_NOCM && retry < 20 ) {
1051 goto retry_gettoken5;
1060 if (atoken.kvno == btoken.kvno &&
1061 atoken.ticketLen == btoken.ticketLen &&
1062 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1063 sizeof(atoken.sessionKey)) &&
1064 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1067 if (k5creds && context)
1068 krb5_free_creds(context, k5creds);
1071 krb5_free_context(context);
1073 _reportf(L"Same token already exists");
1079 // * Reset the "aclient" structure before we call ktc_SetToken.
1080 // * This structure was first set by the ktc_GetToken call when
1081 // * we were comparing whether identical tokens already existed.
1083 StringCchCopyA(aclient.name, MAXKTCNAMELEN,
1084 krb5_principal_get_comp_string(context, k5creds->client, 0));
1086 if ( krb5_principal_get_num_comp(context, k5creds->client) > 1 ) {
1087 StringCbCatA(aclient.name, sizeof(aclient.name), ".");
1088 StringCbCatA(aclient.name, sizeof(aclient.name),
1089 krb5_principal_get_comp_string(context, k5creds->client, 1));
1092 aclient.instance[0] = '\0';
1094 StringCbCopyA(aclient.cell, sizeof(aclient.cell), realm_of_cell);
1096 StringCbCatA(aclient.name, sizeof(aclient.name), "@");
1097 StringCbCatA(aclient.name, sizeof(aclient.name),
1098 krb5_principal_get_realm(context, k5creds->client));
1100 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1101 &aclient, &aserver, &atoken);
1103 rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
1107 if (k5creds && context)
1108 krb5_free_creds(context, k5creds);
1111 krb5_free_context(context);
1116 _reportf(L"SetToken returns code %d", rc);
1121 _reportf(L"Trying Krb524");
1123 if (krb524_convert_creds_kdc &&
1124 (method == AFS_TOKEN_AUTO || method == AFS_TOKEN_KRB524)) {
1125 /* This requires krb524d to be running with the KDC */
1126 r = krb524_convert_creds_kdc(context, k5creds, &creds);
1128 _reportf(L"Code %d while converting credentials", r);
1138 if (client_principal)
1139 krb5_free_principal(context, client_principal);
1141 if (k5creds && context)
1142 krb5_free_creds(context, k5creds);
1145 krb5_free_context(context);
1152 if (supports_krb4) {
1153 kcdb_identity_get_config(identity, 0, &confighandle);
1154 khc_read_int32(confighandle, L"Krb4Cred\\Krb4NewCreds", &supports_krb4);
1155 khc_close_space(confighandle);
1159 _reportf(L"Kerberos 4 not configured");
1161 if (!bGotCreds && supports_krb4 &&
1162 strlen(RealmName) < REALM_SZ &&
1163 (method == AFS_TOKEN_AUTO ||
1164 method == AFS_TOKEN_KRB4)) {
1168 _reportf(L"Trying Kerberos 4");
1170 if (!realm_of_user[0] ) {
1171 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user))
1173 /* can't determine realm of user */
1174 _reportf(L"krb_get_tf_realm returns %d", rc);
1179 _reportf(L"Trying to find %S.%S@%S", ServiceName, CellName, RealmName);
1180 rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
1181 if (rc == NO_TKT_FIL) {
1182 // if the problem is that we have no krb4 tickets
1183 // do not attempt to continue
1184 _reportf(L"krb_get_cred returns %d (no ticket file)", rc);
1188 if (rc != KSUCCESS) {
1189 _reportf(L"Trying to find %S@%S", ServiceName, RealmName);
1190 rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
1193 if (rc != KSUCCESS) {
1194 _reportf(L"Trying to obtain new ticket");
1195 if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1196 CellName, RealmName, 0))
1198 if ((rc = (*pkrb_get_cred)(ServiceName, CellName,
1199 RealmName, &creds)) != KSUCCESS) {
1202 _reportf(L"Got %S.%S@%S", ServiceName, CellName, RealmName);
1204 } else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1207 if ((rc = (*pkrb_get_cred)(ServiceName, "",
1208 RealmName, &creds)) != KSUCCESS) {
1211 _reportf(L"Got %S@%S", ServiceName, RealmName);
1226 memset(&aserver, '\0', sizeof(aserver));
1227 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1228 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1230 memset(&atoken, '\0', sizeof(atoken));
1231 atoken.kvno = (short)creds.kvno;
1232 atoken.startTime = creds.issue_date;
1233 atoken.endTime = (*pkrb_life_to_time)(creds.issue_date,creds.lifetime);
1234 memcpy(&atoken.sessionKey, creds.session, 8);
1235 atoken.ticketLen = creds.ticket_st.length;
1236 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
1239 *tok_expiration = atoken.endTime;
1241 if (!(rc = ktc_GetToken(&aserver, &btoken,
1242 sizeof(btoken), &aclient)) &&
1243 atoken.kvno == btoken.kvno &&
1244 atoken.ticketLen == btoken.ticketLen &&
1245 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1246 sizeof(atoken.sessionKey)) &&
1247 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1254 // Reset the "aclient" structure before we call ktc_SetToken.
1255 // This structure was first set by the ktc_GetToken call when
1256 // we were comparing whether identical tokens already existed.
1258 StringCchCopyA(aclient.name, MAXKTCNAMELEN, creds.pname);
1259 if (creds.pinst[0]) {
1260 StringCchCatA(aclient.name, MAXKTCNAMELEN, ".");
1261 StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.pinst);
1264 StringCbCopyA(aclient.instance, sizeof(aclient.instance), "");
1266 StringCchCatA(aclient.name, MAXKTCNAMELEN, "@");
1267 StringCchCatA(aclient.name, MAXKTCNAMELEN, got524cred ? realm_of_user : creds.realm);
1269 StringCbCopyA(aclient.cell, sizeof(aclient.cell), CellName);
1271 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1272 &aclient, &aserver, &atoken);
1274 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
1275 afs_report_error(rc, "ktc_SetToken()");
1282 (method == AFS_TOKEN_AUTO ||
1283 method >= AFS_TOKEN_USER)) {
1284 /* we couldn't get a token using Krb5, Krb524 or Krb4,
1285 either because we couldn't get the necessary
1286 credentials or because the method was set to not use
1287 those. Now we dispatch to any extensions to see if
1288 they have better luck. */
1290 rc = !afs_ext_klog(method,
1297 } else if (!bGotCreds) {
1298 /* if the return code was not set, we should set it now.
1299 Otherwise we let the code go through. */
1301 /* No tokens were obtained. We should report something */
1302 _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
1306 rc = KHM_ERROR_GENERAL;
1311 if (ak_cellconfig.linkedCell)
1312 free(ak_cellconfig.linkedCell);
1317 /**************************************/
1318 /* afs_realm_of_cell(): */
1319 /**************************************/
1321 afs_realm_of_cell(afs_conf_cell *cellconfig, BOOL referral_fallback)
1323 char krbhst[MAX_HSTNM]="";
1324 static char krbrlm[MAXKTCREALMLEN+1]="";
1325 krb5_context ctx = 0;
1326 char ** realmlist=NULL;
1327 krb5_error_code r = 0;
1332 if (referral_fallback) {
1334 p = strchr(cellconfig->hostName[0], '.');
1336 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1338 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1339 #if _MSC_VER >= 1400
1340 _strupr_s(krbrlm, sizeof(krbrlm));
1345 r = krb5_init_context(&ctx);
1347 r = krb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
1348 if ( !r && realmlist && realmlist[0] ) {
1349 StringCbCopyA(krbrlm, sizeof(krbrlm), realmlist[0]);
1350 krb5_free_host_realm(ctx, realmlist);
1353 krb5_free_context(ctx);
1357 if (pkrb_get_krbhst && pkrb_realmofhost) {
1358 StringCbCopyA(krbrlm, sizeof(krbrlm),
1359 (char *)(*pkrb_realmofhost)(cellconfig->hostName[0]));
1360 if ((*pkrb_get_krbhst)(krbhst, krbrlm, 1) != KSUCCESS)
1366 p = strchr(cellconfig->hostName[0], '.');
1368 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1370 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1371 #if _MSC_VER >= 1400
1372 _strupr_s(krbrlm, sizeof(krbrlm));
1383 /**************************************/
1384 /* afs_get_cellconfig(): */
1385 /**************************************/
1387 afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
1391 char linkedCell[MAXCELLCHARS]="";
1393 local_cell[0] = (char)0;
1394 memset(cellconfig, 0, sizeof(*cellconfig));
1396 cellconfig->cbsize = sizeof(*cellconfig);
1398 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
1399 if (rc = cm_GetRootCellName(local_cell)) {
1403 if (strlen(cell) == 0)
1404 StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
1406 StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
1408 rc = cm_SearchCellRegistry(1, cell, NULL, linkedCell,
1409 afs_get_cellconfig_callback, (void*) cellconfig);
1410 if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
1411 rc = cm_SearchCellFileEx(cell, NULL, linkedCell, afs_get_cellconfig_callback,
1414 rc = cm_SearchCellByDNS(cell, NULL, &ttl,
1415 afs_get_cellconfig_callback,
1416 (void*) cellconfig);
1419 cellconfig->linkedCell = strdup(linkedCell);
1424 /**************************************/
1425 /* afs_get_cellconfig_callback(): */
1426 /**************************************/
1428 afs_get_cellconfig_callback(void *cellconfig,
1429 struct sockaddr_in *addrp,
1431 unsigned short ipRank)
1433 afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
1435 cc->hostAddr[cc->numServers] = *addrp;
1436 StringCbCopyA(cc->hostName[cc->numServers],
1437 sizeof(cc->hostName[0]), namep);
1443 /**************************************/
1444 /* afs_report_error(): */
1445 /**************************************/
1447 afs_report_error(LONG rc, LPCSTR FailedFunctionName)
1450 const char *errText;
1452 // Using AFS defines as error messages for now, until Transarc
1453 // gets back to me with "string" translations of each of these
1455 if (rc == KTC_ERROR)
1456 errText = "KTC_ERROR";
1457 else if (rc == KTC_TOOBIG)
1458 errText = "KTC_TOOBIG";
1459 else if (rc == KTC_INVAL)
1460 errText = "KTC_INVAL";
1461 else if (rc == KTC_NOENT)
1462 errText = "KTC_NOENT";
1463 else if (rc == KTC_PIOCTLFAIL)
1464 errText = "KTC_PIOCTLFAIL";
1465 else if (rc == KTC_NOPIOCTL)
1466 errText = "KTC_NOPIOCTL";
1467 else if (rc == KTC_NOCELL)
1468 errText = "KTC_NOCELL";
1469 else if (rc == KTC_NOCM)
1470 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
1472 errText = "Unknown error!";
1474 StringCbPrintfA(message, sizeof(message),
1475 "%s\n(%s failed)", errText, FailedFunctionName);
1476 _report_cs1(KHERR_ERROR, L"%1!S!", _cptr(message));
1482 GetServiceStatus(LPSTR lpszMachineName,
1483 LPSTR lpszServiceName,
1484 DWORD *lpdwCurrentState,
1485 DWORD *lpdwWaitHint)
1488 SC_HANDLE schSCManager = NULL;
1489 SC_HANDLE schService = NULL;
1490 DWORD fdwDesiredAccess = 0;
1491 SERVICE_STATUS ssServiceStatus = {0};
1494 *lpdwCurrentState = 0;
1496 fdwDesiredAccess = GENERIC_READ;
1498 schSCManager = OpenSCManagerA(lpszMachineName,
1502 if(schSCManager == NULL) {
1503 hr = GetLastError();
1507 schService = OpenServiceA(schSCManager,
1511 if(schService == NULL) {
1512 hr = GetLastError();
1516 fRet = QueryServiceStatus(schService,
1520 hr = GetLastError();
1524 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
1526 *lpdwWaitHint = ssServiceStatus.dwWaitHint;
1529 CloseServiceHandle(schService);
1530 CloseServiceHandle(schSCManager);
1535 DWORD ServiceControl(LPSTR lpszMachineName,
1536 LPSTR lpszServiceName,
1540 SC_HANDLE schSCManager = NULL;
1541 SC_HANDLE schService = NULL;
1542 DWORD fdwDesiredAccess = 0;
1543 SERVICE_STATUS ssServiceStatus = {0};
1545 DWORD dwCurrentState = 0;
1549 fdwDesiredAccess = GENERIC_READ;
1551 schSCManager = OpenSCManagerA(lpszMachineName, NULL,
1554 if(schSCManager == NULL) {
1555 hr = GetLastError();
1559 fdwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
1561 schService = OpenServiceA(schSCManager, lpszServiceName,
1564 if(schService == NULL) {
1565 hr = GetLastError();
1569 fRet = QueryServiceStatus(schService, &ssServiceStatus);
1572 hr = GetLastError();
1576 dwCurrentState = ssServiceStatus.dwCurrentState;
1578 if (dwCurrentState == SERVICE_STOPPED &&
1579 dwNewState == SERVICE_RUNNING) {
1581 fRet = StartService(schService, 0, NULL);
1583 if (fRet == FALSE) {
1584 hr = GetLastError();
1589 if (dwCurrentState == SERVICE_RUNNING &&
1590 dwNewState == SERVICE_STOPPED) {
1591 fRet = ControlService(schService, SERVICE_CONTROL_STOP,
1594 if (fRet == FALSE) {
1595 hr = GetLastError();
1602 CloseServiceHandle(schService);
1603 CloseServiceHandle(schSCManager);
1609 afs_check_for_cell_realm_match(khm_handle identity, char * cell) {
1610 char local_cell[MAXCELLCHARS];
1611 wchar_t wrealm[MAXCELLCHARS];
1612 wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
1616 afs_conf_cell cellconfig;
1619 ZeroMemory(local_cell, sizeof(local_cell));
1620 ZeroMemory(&cellconfig, sizeof(cellconfig));
1622 rc = afs_get_cellconfig(cell, &cellconfig, local_cell);
1626 realm = afs_realm_of_cell(&cellconfig, FALSE);
1627 if (cellconfig.linkedCell)
1628 free(cellconfig.linkedCell);
1629 if (!realm[0]) /* referral; assume it matches */
1632 AnsiStrToUnicode(wrealm, sizeof(wrealm), realm);
1634 cb = sizeof(idname);
1636 kcdb_identity_get_name(identity, idname, &cb);
1638 atsign = wcschr(idname, L'@');
1639 if (atsign && atsign[1] && !_wcsicmp(atsign + 1, wrealm)) {