2 * Copyright (c) 2005-2011 Secure Endpoints Inc.
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 /* Disable the 'macro redefinition' warning which is getting
28 triggerred by a redefinition of the ENCRYPT and DECRYPT macros. */
29 #pragma warning (push)
30 #pragma warning (disable: 4005)
34 #include<krb5common.h>
40 static char *afs_realm_of_cell(afs_conf_cell *, BOOL);
41 static long afs_get_cellconfig_callback(void *, struct sockaddr_in *, char *, unsigned short ipRank);
42 static int afs_get_cellconfig(char *, afs_conf_cell *, char *);
45 afs_is_running(void) {
51 if (GetServiceStatus(NULL, TRANSARCAFSDAEMON,
52 &CurrentState, NULL) != NOERROR)
54 if (CurrentState != SERVICE_RUNNING)
65 if (!afs_is_running())
68 rc = ktc_ForgetAllTokens();
74 afs_unlog_cred(khm_handle cred)
77 struct ktc_principal princ;
79 wchar_t name[KCDB_MAXCCH_NAME];
81 if (!afs_is_running())
84 cbbuf = sizeof(princ);
85 if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_server_princ,
86 NULL, &princ, &cbbuf)))
89 afs_princ_to_string(&princ, name, sizeof(name));
91 _report_cs1(KHERR_INFO, L"Destroying token %1!s!",
95 rc = ktc_ForgetToken(&princ);
100 /* convert a ktc_principal to a wchar_t string form that looks like
101 name.instance@cell return 0 if it worked. non-zero otherwise
104 afs_princ_to_string(struct ktc_principal * p,
112 l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->name);
115 rv = FAILED(StringCbCopy(buf, cbbuf, wbuf));
117 StringCbCat(buf, cbbuf, L".");
118 if((l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->instance)) > 0) {
120 rv = rv || FAILED(StringCbCat(buf, cbbuf, wbuf));
126 rv = rv || FAILED(StringCbCat(buf, cbbuf, L"@"));
127 if((l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->cell)) > 0) {
129 rv = rv || FAILED(StringCbCat(buf, cbbuf, wbuf));
139 afs_list_tokens(void)
143 kcdb_credset_flush(afs_credset);
144 r = afs_list_tokens_internal();
145 kcdb_credset_collect(NULL, afs_credset, NULL, afs_credtype_id, NULL);
148 afs_icon_set_state(AFSICON_REPORT_TOKENS, afs_credset);
149 } else if (r == -1) {
150 afs_icon_set_state(AFSICON_SERVICE_STOPPED, NULL);
152 afs_icon_set_state(AFSICON_SERVICE_ERROR, NULL);
158 /* is the credential provided an AFS token and is it from the
160 static khm_int32 KHMAPI
161 afs_filter_by_cell(khm_handle cred, khm_int32 flags, void * rock)
163 wchar_t wcell[MAXCELLCHARS];
168 tcell = (wchar_t *) rock;
170 if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
171 type != afs_credtype_id)
174 cbsize = sizeof(wcell);
175 if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell,
176 NULL, wcell, &cbsize)))
179 if(wcscmp(wcell, tcell))
185 struct token_filter_data {
190 afs_filter_for_token(khm_handle cred, khm_int32 flags, void * rock) {
191 struct token_filter_data * pdata;
192 wchar_t ccell[MAXCELLCHARS];
196 pdata = (struct token_filter_data *) rock;
198 if (KHM_FAILED(kcdb_cred_get_type(cred, &ctype)) ||
199 ctype != afs_credtype_id)
205 if (KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell,
209 _wcsicmp(ccell, pdata->cell))
217 afs_find_token(khm_handle credset, wchar_t * cell) {
218 struct token_filter_data fdata;
219 khm_handle cred = NULL;
223 if (KHM_FAILED(kcdb_credset_find_filtered(credset,
225 afs_filter_for_token,
234 static khm_int32 KHMAPI
235 afs_filter_krb5_tkt(khm_handle cred, khm_int32 flags, void * rock)
237 wchar_t cname[KCDB_CRED_MAXCCH_NAME];
240 wchar_t * t, *tkt_cell;
243 tcell = (wchar_t *) rock;
245 if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
246 type != krb5_credtype_id)
249 cbsize = sizeof(cname);
250 if (KHM_FAILED(kcdb_cred_get_name(cred, cname, &cbsize)))
253 if (!wcsncmp(cname, L"afs/", 4)) {
255 tkt_cell = cname + 4;
257 t = wcschr(tkt_cell, L'@');
262 } else if (!wcsncmp(cname, L"afs@", 4)) {
264 tkt_cell = cname + 4;
270 if (_wcsicmp(tcell, tkt_cell))
276 static khm_int32 KHMAPI
277 afs_filter_krb4_tkt(khm_handle cred, khm_int32 flags, void * rock)
279 wchar_t cname[KCDB_CRED_MAXCCH_NAME];
282 wchar_t * t, *tkt_cell;
285 tcell = (wchar_t *) rock;
287 if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
288 type != krb4_credtype_id)
291 cbsize = sizeof(cname);
292 if (KHM_FAILED(kcdb_cred_get_name(cred, cname, &cbsize)))
295 if (!wcsncmp(cname, L"afs.", 4)) {
297 tkt_cell = cname + 4;
299 t = wcschr(tkt_cell, L'@');
304 } else if (!wcsncmp(cname, L"afs@", 4)) {
306 tkt_cell = cname + 4;
312 if (_wcsicmp(tcell, tkt_cell))
318 /* collects all AFS tokens to the root credential set using the
319 generic afs_credset credential set
322 afs_list_tokens_internal(void)
324 struct ktc_principal aserver;
325 struct ktc_principal aclient;
326 struct ktc_token atoken;
331 wchar_t location[256];
336 khm_handle ident = NULL;
337 khm_handle cred = NULL;
338 afs_tk_method method;
342 if (!afs_is_running())
345 kcdb_credset_flush(afs_credset);
347 LoadString(hResModule, IDS_DEF_LOCATION, location, ARRAYLENGTH(location));
353 memset(&aserver, 0, sizeof(aserver));
354 if (rc = ktc_ListTokens(cellNum, &cellNum, &aserver))
363 memset(&atoken, '\0', sizeof(atoken));
364 if (rc = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient))
373 /* failed attempt at trying to figure out the principal name from
374 the token. The ticket that is attached to the token is not
375 in a form that is useful at this point */
377 if(atoken.kvno == RXKAD_TKT_TYPE_KERBEROS_V5) {
378 krb5_context ctx = 0;
381 krb5_error_code code;
384 code = khm_krb5_initialize(&ctx, &cc);
388 k5c = (krb5_creds *) atoken.ticket;
390 code = krb5_unparse_name(ctx, k5c->client, &princ);
394 MultiByteToWideChar(CP_ACP, 0, princ, strlen(princ), idname, sizeof(idname)/sizeof(idname[0]));
396 krb5_free_unparsed_name(ctx, princ);
402 method = AFS_TOKEN_AUTO;
404 afs_princ_to_string(&aclient, idname, sizeof(idname));
406 /* We need to figure out a good client name which we can use
407 to create an identity which looks familiar to the user. No
408 good way of doing this, so we use a heuristic.
410 Note that, we use another heuristic to find out which
411 identity to associate the token with.
415 The assumption here is that the principal for the token is
418 if realm != cell : principal looks like user@realm@cell
419 if realm == cell : principal looks like user@realm
423 We strip the part of the string that follows the second '@'
424 sign to obtain the 'user@realm' part, which we use as the
425 credential name. If there is no second '@', we use the
426 whole principal name. */
430 ats = wcschr(idname, L'@');
431 if(ats && (ats = wcschr(ats + 1, L'@')))
435 afs_princ_to_string(&aserver, crname, sizeof(crname));
437 /* Ok, now we need to figure out which identity to associate
438 this token with. This is a little bit tricky, and there is
439 currently no good way of determining the original identity
440 used to obtain the token if it was done outside of
441 NetIDMgr. So we use a heuristic here.
445 Elsewhere, (actually in afsnewcreds.c) just after obtaining
446 AFS tokens through NetIDMgr, we enumerate the AFS tokens
447 and assign the root identity (used to obtain new creds)
448 with the AFS tokens. This would still be there in the root
449 credential set when we list tokens later on.
453 If there exists an AFS token in the root credential set for
454 the same cell, we associate this token with the same
455 identity as that credential.
457 cell = wcschr(crname, L'@');
468 if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
474 kcdb_cred_get_identity(c, &ident);
476 kcdb_cred_get_attr(c, afs_attr_method, NULL,
478 kcdb_cred_release(c);
482 /* If that failed, we have try another trick. If there is a
483 Krb5 ticket of the form afs/<cell>@<realm> or afs@<CELL>
484 where <cell> matches our cell, then we pick the identity
489 If Krb5 was used to obtain the token, then there is a Krb5
490 ticket of the form afs/<cell>@<REALM> or afs@<CELL> still
491 in the cache. This is also true for Krb524 token
496 If such a Krb5 ticket is found, use the identity of that
497 credential as the identity of the AFS token.
500 if (ident == NULL && cell != NULL) {
503 if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
507 kcdb_cred_get_identity(c, &ident);
508 /* this could be Krb5 or Krb524, so we leave method at
510 method = AFS_TOKEN_AUTO;
511 kcdb_cred_release(c);
515 /* If that didn't work either, we look for a Krb4 ticket of
516 the form afs.<cell>@<REALM> or afs@<CELL> which matches the
521 If Krb4 was used to obtain an AFS token, then there should
522 be a Krb4 ticket of the form afs.<cell>@<REALM> or
523 afs@<CELL> in the cache.
527 If such a ticket is found, then use the identity of that
528 credential as the identity of the AFS token.
530 if (ident == NULL && cell != NULL) {
533 if (krb4_credtype_id < 0) {
534 kcdb_credtype_get_id(KRB4_CREDTYPE_NAME,
538 if (krb4_credtype_id >= 0 &&
539 KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
544 kcdb_cred_get_identity(c, &ident);
545 kcdb_cred_release(c);
546 method = AFS_TOKEN_KRB4;
551 /* Finally, we allow any extension plugins to give this a shot */
552 if (ident == NULL && cell != NULL) {
553 afs_ext_resolve_token(cell,
561 /* One more thing to try. If we have a cell->identity
562 mapping, then we try that. */
563 if (ident == NULL && cell != NULL) {
564 khm_handle h_cellmap;
565 wchar_t tidname[KCDB_IDENT_MAXCCH_NAME];
568 cb = sizeof(tidname);
570 if (KHM_SUCCEEDED(khc_open_space(csp_afscred,
573 if (KHM_SUCCEEDED(khc_read_string(h_cellmap,
577 kcdb_identity_create(tidname,
578 KCDB_IDENT_FLAG_CREATE,
581 khc_close_space(h_cellmap);
585 /* all else failed */
587 if(KHM_FAILED(kcdb_identity_create(idname,
588 KCDB_IDENT_FLAG_CREATE,
593 if(KHM_FAILED(kcdb_cred_create(crname, ident, afs_credtype_id, &cred)))
596 kcdb_cred_set_attr(cred, afs_attr_method, &method, sizeof(method));
598 TimetToFileTime(atoken.endTime, &ft);
599 kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &ft, sizeof(ft));
600 if (atoken.startTime != 0) {
601 TimetToFileTime(atoken.startTime, &ft);
602 kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft));
604 kcdb_cred_set_attr(cred, afs_attr_client_princ,
605 &aclient, sizeof(aclient));
606 kcdb_cred_set_attr(cred, afs_attr_server_princ,
607 &aserver, sizeof(aserver));
610 kcdb_cred_set_attr(cred, afs_attr_cell, cell, (khm_size)KCDB_CBSIZE_AUTO);
613 kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION,
614 location, (khm_size)KCDB_CBSIZE_AUTO);
616 kcdb_credset_add_cred(afs_credset, cred, -1);
618 /* both these calls are NULL pointer safe */
619 kcdb_cred_release(cred);
621 kcdb_identity_release(ident);
627 kcdb_identity_release(ident);
629 kcdb_cred_release(cred);
635 #define ALLOW_REGISTER 1
637 ViceIDToUsername(char *username,
641 struct ktc_principal *aclient,
642 struct ktc_principal *aserver,
643 struct ktc_token *atoken)
645 static char lastcell[MAXCELLCHARS+1] = { 0 };
646 static char confname[512] = { 0 };
647 char username_copy[BUFSIZ];
648 long viceId = ANONYMOUSID; /* AFS uid of user */
650 #ifdef ALLOW_REGISTER
652 #endif /* ALLOW_REGISTER */
654 if (confname[0] == '\0') {
655 StringCbCopyA(confname, sizeof(confname), AFSDIR_CLIENT_ETC_DIRPATH);
658 StringCbCopyA(lastcell, sizeof(lastcell), aserver->cell);
660 if (!pr_Initialize (0, confname, aserver->cell)) {
661 char sname[PR_MAXNAMELEN];
662 StringCbCopyA(sname, sizeof(sname), username);
663 status = pr_SNameToId (sname, &viceId);
667 #ifdef AFS_ID_TO_NAME
669 * This is a crock, but it is Transarc's crock, so
670 * we have to play along in order to get the
671 * functionality. The way the afs id is stored is
672 * as a string in the username field of the token.
673 * Contrary to what you may think by looking at
674 * the code for tokens, this hack (AFS ID %d) will
675 * not work if you change %d to something else.
677 #endif /* AFS_ID_TO_NAME */
679 * This code is taken from cklog -- it lets people
680 * automatically register with the ptserver in foreign cells
683 /* copy the username because pr_CreateUser will lowercase it */
684 StringCbCopyA(username_copy, BUFSIZ, username);
686 #ifdef ALLOW_REGISTER
688 if (viceId != ANONYMOUSID) {
689 #else /* ALLOW_REGISTER */
690 if ((status == 0) && (viceId != ANONYMOUSID))
691 #endif /* ALLOW_REGISTER */
693 #ifdef AFS_ID_TO_NAME
694 StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
695 #endif /* AFS_ID_TO_NAME */
697 #ifdef ALLOW_REGISTER
698 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
700 StringCbCopyA(aclient->name, sizeof(aclient->name), username);
701 StringCbCopyA(aclient->instance, sizeof(aclient->instance), "");
702 StringCbCopyA(aclient->cell, sizeof(aclient->cell), realm_of_user);
703 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
705 if (status = pr_Initialize(1L, confname, aserver->cell))
707 status = pr_CreateUser(username, &id);
709 StringCbCopyA(username, BUFSIZ, username_copy);
710 #ifdef AFS_ID_TO_NAME
711 StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
712 #endif /* AFS_ID_TO_NAME */
715 #endif /* ALLOW_REGISTER */
721 copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) {
726 ret = decode_Ticket(v5cred->ticket.data, v5cred->ticket.length,
729 StringCbCopyA(dest, destlen, ticket.realm);
731 free_Ticket(&ticket);
736 afs_klog(khm_handle identity,
741 afs_tk_method method,
742 time_t * tok_expiration,
749 struct ktc_principal aserver;
750 struct ktc_principal aclient;
751 char realm_of_user[MAXKTCREALMLEN]; /* Kerberos realm of user */
752 char realm_of_cell[MAXKTCREALMLEN]; /* Kerberos realm of cell */
753 char local_cell[MAXCELLCHARS+1];
754 char Dmycell[MAXCELLCHARS+1];
755 struct ktc_token atoken;
756 struct ktc_token btoken;
757 afs_conf_cell ak_cellconfig; /* General information about the cell */
760 char ServiceName[128];
761 khm_handle confighandle = NULL;
763 khm_int32 supports_krb4 = (pkrb_get_tf_realm == NULL ? 0 : 1);
764 khm_int32 got524cred = 0;
768 BOOL bGotCreds = FALSE; /* got creds? */
771 *tok_expiration = (time_t) 0;
773 if (!afs_is_running()) {
774 _report_sr0(KHERR_WARNING, IDS_ERR_NOSERVICE);
778 if ( !realm ) realm = "";
779 if ( !cell ) cell = "";
780 if ( !service ) service = "";
782 memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
783 memset(RealmName, '\0', sizeof(RealmName));
784 memset(CellName, '\0', sizeof(CellName));
785 memset(ServiceName, '\0', sizeof(ServiceName));
786 memset(realm_of_user, '\0', sizeof(realm_of_user));
787 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
788 memset(Dmycell, '\0', sizeof(Dmycell));
790 // NULL or empty cell returns information on local cell
792 StringCbCopyA(Dmycell, sizeof(Dmycell), cell);
794 rc = afs_get_cellconfig(Dmycell, &ak_cellconfig, local_cell);
796 _reportf(L"afs_get_cellconfig returns %ld", rc);
798 _report_sr2(KHERR_ERROR, IDS_ERR_CELLCONFIG, _cstr(Dmycell), _int32(rc));
799 _suggest_sr(IDS_ERR_CELLCONFIG_S, KHERR_SUGGEST_NONE);
804 if (linkedCell && ak_cellconfig.linkedCell)
805 StringCbCopyA(linkedCell, MAXCELLCHARS,
806 ak_cellconfig.linkedCell);
808 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
809 afs_realm_of_cell(&ak_cellconfig, FALSE));
811 if (strlen(service) == 0)
812 StringCbCopyA(ServiceName, sizeof(ServiceName), "afs");
814 StringCbCopyA(ServiceName, sizeof(ServiceName), service);
816 if (strlen(cell) == 0)
817 StringCbCopyA(CellName, sizeof(CellName), local_cell);
819 StringCbCopyA(CellName, sizeof(CellName), cell);
821 if (strlen(realm) == 0)
822 StringCbCopyA(RealmName, sizeof(RealmName), realm_of_cell);
824 StringCbCopyA(RealmName, sizeof(RealmName), realm);
827 memset(&creds, '\0', sizeof(creds));
830 /*** Kerberos 5 and 524 ***/
832 if (method == AFS_TOKEN_AUTO ||
833 method == AFS_TOKEN_KRB5 ||
834 method == AFS_TOKEN_KRB524) {
836 krb5_context context = 0;
837 krb5_ccache k5cc = 0;
839 krb5_creds * k5creds = 0;
841 krb5_principal client_principal = 0;
842 krb5_flags flags = 0;
848 _reportf(L"Trying Kerberos 5");
850 if (!(r = khm_krb5_initialize(identity, &context, &k5cc))) {
853 memset(&increds, 0, sizeof(increds));
855 r = krb5_cc_get_principal(context, k5cc, &client_principal);
857 StringCchCopyA(realm_of_user, ARRAYLENGTH(realm_of_user),
858 krb5_principal_get_realm(context, client_principal));
860 _reportf(L"krb5_cc_get_principal returns code %d", r);
868 _reportf(L"khm_krb5_initialize returns code %d", r);
876 increds.client = client_principal;
877 increds.times.endtime = 0;
878 /* Ask for DES since that is what V4 understands */
879 increds.session.keytype = ENCTYPE_DES_CBC_CRC;
881 #ifdef KRB5_TC_NOTICKET
882 flags = KRB5_TC_OPENCLOSE;
883 r = krb5_cc_set_flags(context, k5cc, flags);
885 if (strlen(realm) != 0) {
887 /* First try Service/Cell@REALM */
888 if (r = krb5_build_principal(context, &increds.server,
894 _reportf(L"krb5_build_principal returns %d", r);
898 r = krb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
899 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
900 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
901 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
902 /* Next try Service@REALM */
903 krb5_free_principal(context, increds.server);
904 r = krb5_build_principal(context, &increds.server,
910 r = krb5_get_credentials(context, 0, k5cc,
914 /* Check to make sure we received a valid ticket; if not remove it
915 * and try again. Perhaps there are two service tickets for the
916 * same service in the ccache.
918 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
919 krb5_free_principal(context, increds.server);
920 krb5_cc_remove_cred(context, k5cc, 0, k5creds);
921 krb5_free_creds(context, k5creds);
923 goto retry_retcred_1;
927 /* First try Service/Cell@_CLIENT_REALM */
928 if (r = krb5_build_principal(context, &increds.server,
929 (int) strlen(realm_of_user),
934 _reportf(L"krb5_build_principal returns %d", r);
938 r = krb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
940 /* the user realm is a valid cell realm */
941 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell), realm_of_user);
943 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
944 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
945 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
946 krb5_free_principal(context, increds.server);
947 r = krb5_build_principal(context, &increds.server,
948 (int) strlen(realm_of_cell),
954 r = krb5_get_credentials(context, 0, k5cc,
957 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
958 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
959 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
960 strlen(realm_of_cell) == 0) {
961 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
962 afs_realm_of_cell(&ak_cellconfig, TRUE));
964 krb5_free_principal(context, increds.server);
965 r = krb5_build_principal(context, &increds.server,
966 (int) strlen(realm_of_cell),
972 r = krb5_get_credentials(context, 0, k5cc,
975 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
976 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
977 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
978 /* Next try Service@REALM */
979 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
980 afs_realm_of_cell(&ak_cellconfig, FALSE));
982 krb5_free_principal(context, increds.server);
983 r = krb5_build_principal(context, &increds.server,
984 (int) strlen(realm_of_cell),
989 r = krb5_get_credentials(context, 0, k5cc,
992 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
993 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
994 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
995 strlen(realm_of_cell) == 0) {
996 /* Next try Service@REALM */
997 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
998 afs_realm_of_cell(&ak_cellconfig, TRUE));
1000 krb5_free_principal(context, increds.server);
1001 r = krb5_build_principal(context, &increds.server,
1002 (int) strlen(realm_of_cell),
1007 r = krb5_get_credentials(context, 0, k5cc,
1008 &increds, &k5creds);
1011 if (r == 0 && strlen(realm_of_cell) == 0)
1012 copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
1014 /* Check to make sure we received a valid ticket; if not
1015 * remove it and try again. Perhaps there are two service
1016 * tickets for the same service in the ccache.
1018 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
1019 krb5_free_principal(context, increds.server);
1020 krb5_cc_remove_cred(context, k5cc, 0, k5creds);
1021 krb5_free_creds(context, k5creds);
1023 goto retry_retcred_2;
1027 krb5_free_principal(context, increds.server);
1028 krb5_free_principal(context, client_principal);
1029 client_principal = 0;
1030 #ifdef KRB5_TC_NOTICKET
1031 flags = KRB5_TC_OPENCLOSE | KRB5_TC_NOTICKET;
1032 krb5_cc_set_flags(context, k5cc, flags);
1035 (void) krb5_cc_close(context, k5cc);
1039 _reportf(L"Code %d while getting credentials", r);
1045 if ( k5creds->ticket.length > MAXKTCTICKETLEN ||
1046 method == AFS_TOKEN_KRB524) {
1051 /* This code inserts the entire K5 ticket into the token */
1053 _reportf(L"Trying K5 SetToken");
1055 memset(&aserver, '\0', sizeof(aserver));
1056 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1057 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1059 memset(&atoken, '\0', sizeof(atoken));
1060 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
1061 atoken.startTime = k5creds->times.starttime;
1062 atoken.endTime = k5creds->times.endtime;
1063 memcpy(&atoken.sessionKey,
1064 k5creds->session.keyvalue.data,
1065 k5creds->session.keyvalue.length);
1066 atoken.ticketLen = k5creds->ticket.length;
1067 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
1070 *tok_expiration = k5creds->times.endtime;
1073 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
1074 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
1075 if ( rc == KTC_NOCM && retry < 20 ) {
1078 goto retry_gettoken5;
1087 if (atoken.kvno == btoken.kvno &&
1088 atoken.ticketLen == btoken.ticketLen &&
1089 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1090 sizeof(atoken.sessionKey)) &&
1091 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1094 if (k5creds && context)
1095 krb5_free_creds(context, k5creds);
1098 krb5_free_context(context);
1100 _reportf(L"Same token already exists");
1106 // * Reset the "aclient" structure before we call ktc_SetToken.
1107 // * This structure was first set by the ktc_GetToken call when
1108 // * we were comparing whether identical tokens already existed.
1110 StringCchCopyA(aclient.name, MAXKTCNAMELEN,
1111 krb5_principal_get_comp_string(context, k5creds->client, 0));
1113 if ( krb5_principal_get_num_comp(context, k5creds->client) > 1 ) {
1114 StringCbCatA(aclient.name, sizeof(aclient.name), ".");
1115 StringCbCatA(aclient.name, sizeof(aclient.name),
1116 krb5_principal_get_comp_string(context, k5creds->client, 1));
1119 aclient.instance[0] = '\0';
1121 StringCbCopyA(aclient.cell, sizeof(aclient.cell), realm_of_cell);
1123 StringCbCatA(aclient.name, sizeof(aclient.name), "@");
1124 StringCbCatA(aclient.name, sizeof(aclient.name),
1125 krb5_principal_get_realm(context, k5creds->client));
1127 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1128 &aclient, &aserver, &atoken);
1130 rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
1134 if (k5creds && context)
1135 krb5_free_creds(context, k5creds);
1138 krb5_free_context(context);
1143 _reportf(L"SetToken returns code %d", rc);
1148 _reportf(L"Trying Krb524");
1150 if (krb524_convert_creds_kdc &&
1151 (method == AFS_TOKEN_AUTO || method == AFS_TOKEN_KRB524)) {
1152 /* This requires krb524d to be running with the KDC */
1153 r = krb524_convert_creds_kdc(context, k5creds, &creds);
1155 _reportf(L"Code %d while converting credentials", r);
1165 if (client_principal)
1166 krb5_free_principal(context, client_principal);
1168 if (k5creds && context)
1169 krb5_free_creds(context, k5creds);
1172 krb5_free_context(context);
1179 if (supports_krb4) {
1180 kcdb_identity_get_config(identity, 0, &confighandle);
1181 khc_read_int32(confighandle, L"Krb4Cred\\Krb4NewCreds", &supports_krb4);
1182 khc_close_space(confighandle);
1186 _reportf(L"Kerberos 4 not configured");
1188 if (!bGotCreds && supports_krb4 &&
1189 strlen(RealmName) < REALM_SZ &&
1190 (method == AFS_TOKEN_AUTO ||
1191 method == AFS_TOKEN_KRB4)) {
1195 _reportf(L"Trying Kerberos 4");
1197 if (!realm_of_user[0] ) {
1198 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user))
1200 /* can't determine realm of user */
1201 _reportf(L"krb_get_tf_realm returns %d", rc);
1206 _reportf(L"Trying to find %S.%S@%S", ServiceName, CellName, RealmName);
1207 rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
1208 if (rc == NO_TKT_FIL) {
1209 // if the problem is that we have no krb4 tickets
1210 // do not attempt to continue
1211 _reportf(L"krb_get_cred returns %d (no ticket file)", rc);
1215 if (rc != KSUCCESS) {
1216 _reportf(L"Trying to find %S@%S", ServiceName, RealmName);
1217 rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
1220 if (rc != KSUCCESS) {
1221 _reportf(L"Trying to obtain new ticket");
1222 if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1223 CellName, RealmName, 0))
1225 if ((rc = (*pkrb_get_cred)(ServiceName, CellName,
1226 RealmName, &creds)) != KSUCCESS) {
1229 _reportf(L"Got %S.%S@%S", ServiceName, CellName, RealmName);
1231 } else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1234 if ((rc = (*pkrb_get_cred)(ServiceName, "",
1235 RealmName, &creds)) != KSUCCESS) {
1238 _reportf(L"Got %S@%S", ServiceName, RealmName);
1253 memset(&aserver, '\0', sizeof(aserver));
1254 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1255 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1257 memset(&atoken, '\0', sizeof(atoken));
1258 atoken.kvno = (short)creds.kvno;
1259 atoken.startTime = creds.issue_date;
1260 atoken.endTime = (*pkrb_life_to_time)(creds.issue_date,creds.lifetime);
1261 memcpy(&atoken.sessionKey, creds.session, 8);
1262 atoken.ticketLen = creds.ticket_st.length;
1263 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
1266 *tok_expiration = atoken.endTime;
1268 if (!(rc = ktc_GetToken(&aserver, &btoken,
1269 sizeof(btoken), &aclient)) &&
1270 atoken.kvno == btoken.kvno &&
1271 atoken.ticketLen == btoken.ticketLen &&
1272 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1273 sizeof(atoken.sessionKey)) &&
1274 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1281 // Reset the "aclient" structure before we call ktc_SetToken.
1282 // This structure was first set by the ktc_GetToken call when
1283 // we were comparing whether identical tokens already existed.
1285 StringCchCopyA(aclient.name, MAXKTCNAMELEN, creds.pname);
1286 if (creds.pinst[0]) {
1287 StringCchCatA(aclient.name, MAXKTCNAMELEN, ".");
1288 StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.pinst);
1291 StringCbCopyA(aclient.instance, sizeof(aclient.instance), "");
1293 StringCchCatA(aclient.name, MAXKTCNAMELEN, "@");
1294 StringCchCatA(aclient.name, MAXKTCNAMELEN, got524cred ? realm_of_user : creds.realm);
1296 StringCbCopyA(aclient.cell, sizeof(aclient.cell), CellName);
1298 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1299 &aclient, &aserver, &atoken);
1301 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
1302 afs_report_error(rc, "ktc_SetToken()");
1309 (method == AFS_TOKEN_AUTO ||
1310 method >= AFS_TOKEN_USER)) {
1311 /* we couldn't get a token using Krb5, Krb524 or Krb4,
1312 either because we couldn't get the necessary
1313 credentials or because the method was set to not use
1314 those. Now we dispatch to any extensions to see if
1315 they have better luck. */
1317 rc = !afs_ext_klog(method,
1324 } else if (!bGotCreds) {
1325 /* if the return code was not set, we should set it now.
1326 Otherwise we let the code go through. */
1328 /* No tokens were obtained. We should report something */
1329 _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
1333 rc = KHM_ERROR_GENERAL;
1338 if (ak_cellconfig.linkedCell)
1339 free(ak_cellconfig.linkedCell);
1344 /**************************************/
1345 /* afs_realm_of_cell(): */
1346 /**************************************/
1348 afs_realm_of_cell(afs_conf_cell *cellconfig, BOOL referral_fallback)
1350 char krbhst[MAX_HSTNM]="";
1351 static char krbrlm[MAXKTCREALMLEN+1]="";
1352 krb5_context ctx = 0;
1353 char ** realmlist=NULL;
1354 krb5_error_code r = 0;
1359 if (referral_fallback) {
1361 p = strchr(cellconfig->hostName[0], '.');
1363 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1365 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1366 #if _MSC_VER >= 1400
1367 _strupr_s(krbrlm, sizeof(krbrlm));
1372 r = krb5_init_context(&ctx);
1374 r = krb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
1375 if ( !r && realmlist && realmlist[0] ) {
1376 StringCbCopyA(krbrlm, sizeof(krbrlm), realmlist[0]);
1377 krb5_free_host_realm(ctx, realmlist);
1380 krb5_free_context(ctx);
1384 if (pkrb_get_krbhst && pkrb_realmofhost) {
1385 StringCbCopyA(krbrlm, sizeof(krbrlm),
1386 (char *)(*pkrb_realmofhost)(cellconfig->hostName[0]));
1387 if ((*pkrb_get_krbhst)(krbhst, krbrlm, 1) != KSUCCESS)
1393 p = strchr(cellconfig->hostName[0], '.');
1395 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1397 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1398 #if _MSC_VER >= 1400
1399 _strupr_s(krbrlm, sizeof(krbrlm));
1410 /**************************************/
1411 /* afs_get_cellconfig(): */
1412 /**************************************/
1414 afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
1418 char linkedCell[MAXCELLCHARS]="";
1420 local_cell[0] = (char)0;
1421 memset(cellconfig, 0, sizeof(*cellconfig));
1423 cellconfig->cbsize = sizeof(*cellconfig);
1425 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
1426 if (rc = cm_GetRootCellName(local_cell)) {
1430 if (strlen(cell) == 0)
1431 StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
1433 StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
1435 rc = cm_SearchCellRegistry(1, cell, NULL, linkedCell,
1436 afs_get_cellconfig_callback, (void*) cellconfig);
1437 if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
1438 rc = cm_SearchCellFileEx(cell, NULL, linkedCell, afs_get_cellconfig_callback,
1441 rc = cm_SearchCellByDNS(cell, NULL, &ttl,
1442 afs_get_cellconfig_callback,
1443 (void*) cellconfig);
1446 cellconfig->linkedCell = strdup(linkedCell);
1451 /**************************************/
1452 /* afs_get_cellconfig_callback(): */
1453 /**************************************/
1455 afs_get_cellconfig_callback(void *cellconfig,
1456 struct sockaddr_in *addrp,
1458 unsigned short ipRank)
1460 afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
1462 cc->hostAddr[cc->numServers] = *addrp;
1463 StringCbCopyA(cc->hostName[cc->numServers],
1464 sizeof(cc->hostName[0]), namep);
1470 /**************************************/
1471 /* afs_report_error(): */
1472 /**************************************/
1474 afs_report_error(LONG rc, LPCSTR FailedFunctionName)
1477 const char *errText;
1479 // Using AFS defines as error messages for now, until Transarc
1480 // gets back to me with "string" translations of each of these
1482 if (rc == KTC_ERROR)
1483 errText = "KTC_ERROR";
1484 else if (rc == KTC_TOOBIG)
1485 errText = "KTC_TOOBIG";
1486 else if (rc == KTC_INVAL)
1487 errText = "KTC_INVAL";
1488 else if (rc == KTC_NOENT)
1489 errText = "KTC_NOENT";
1490 else if (rc == KTC_PIOCTLFAIL)
1491 errText = "KTC_PIOCTLFAIL";
1492 else if (rc == KTC_NOPIOCTL)
1493 errText = "KTC_NOPIOCTL";
1494 else if (rc == KTC_NOCELL)
1495 errText = "KTC_NOCELL";
1496 else if (rc == KTC_NOCM)
1497 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
1499 errText = "Unknown error!";
1501 StringCbPrintfA(message, sizeof(message),
1502 "%s\n(%s failed)", errText, FailedFunctionName);
1503 _report_cs1(KHERR_ERROR, L"%1!S!", _cptr(message));
1509 GetServiceStatus(LPSTR lpszMachineName,
1510 LPSTR lpszServiceName,
1511 DWORD *lpdwCurrentState,
1512 DWORD *lpdwWaitHint)
1515 SC_HANDLE schSCManager = NULL;
1516 SC_HANDLE schService = NULL;
1517 DWORD fdwDesiredAccess = 0;
1518 SERVICE_STATUS ssServiceStatus = {0};
1521 *lpdwCurrentState = 0;
1523 fdwDesiredAccess = GENERIC_READ;
1525 schSCManager = OpenSCManagerA(lpszMachineName,
1529 if(schSCManager == NULL) {
1530 hr = GetLastError();
1534 schService = OpenServiceA(schSCManager,
1538 if(schService == NULL) {
1539 hr = GetLastError();
1543 fRet = QueryServiceStatus(schService,
1547 hr = GetLastError();
1551 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
1553 *lpdwWaitHint = ssServiceStatus.dwWaitHint;
1556 CloseServiceHandle(schService);
1557 CloseServiceHandle(schSCManager);
1562 DWORD ServiceControl(LPSTR lpszMachineName,
1563 LPSTR lpszServiceName,
1567 SC_HANDLE schSCManager = NULL;
1568 SC_HANDLE schService = NULL;
1569 DWORD fdwDesiredAccess = 0;
1570 SERVICE_STATUS ssServiceStatus = {0};
1572 DWORD dwCurrentState = 0;
1576 fdwDesiredAccess = GENERIC_READ;
1578 schSCManager = OpenSCManagerA(lpszMachineName, NULL,
1581 if(schSCManager == NULL) {
1582 hr = GetLastError();
1586 fdwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
1588 schService = OpenServiceA(schSCManager, lpszServiceName,
1591 if(schService == NULL) {
1592 hr = GetLastError();
1596 fRet = QueryServiceStatus(schService, &ssServiceStatus);
1599 hr = GetLastError();
1603 dwCurrentState = ssServiceStatus.dwCurrentState;
1605 if (dwCurrentState == SERVICE_STOPPED &&
1606 dwNewState == SERVICE_RUNNING) {
1608 fRet = StartService(schService, 0, NULL);
1610 if (fRet == FALSE) {
1611 hr = GetLastError();
1616 if (dwCurrentState == SERVICE_RUNNING &&
1617 dwNewState == SERVICE_STOPPED) {
1618 fRet = ControlService(schService, SERVICE_CONTROL_STOP,
1621 if (fRet == FALSE) {
1622 hr = GetLastError();
1629 CloseServiceHandle(schService);
1630 CloseServiceHandle(schSCManager);
1636 afs_check_for_cell_realm_match(khm_handle identity, char * cell) {
1637 char local_cell[MAXCELLCHARS];
1638 wchar_t wrealm[MAXCELLCHARS];
1639 wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
1643 afs_conf_cell cellconfig;
1646 ZeroMemory(local_cell, sizeof(local_cell));
1647 ZeroMemory(&cellconfig, sizeof(cellconfig));
1649 rc = afs_get_cellconfig(cell, &cellconfig, local_cell);
1653 realm = afs_realm_of_cell(&cellconfig, FALSE);
1654 if (cellconfig.linkedCell)
1655 free(cellconfig.linkedCell);
1656 if (!realm[0]) /* referral; assume it matches */
1659 AnsiStrToUnicode(wrealm, sizeof(wrealm), realm);
1661 cb = sizeof(idname);
1663 kcdb_identity_get_name(identity, idname, &cb);
1665 atsign = wcschr(idname, L'@');
1666 if (atsign && atsign[1] && !_wcsicmp(atsign + 1, wrealm)) {