2 * Copyright (c) 2005,2006,2007, 2008 Secure Endpoints Inc.
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 /* Disable the 'macro redefinition' warning which is getting
28 triggerred by a redefinition of the ENCRYPT and DECRYPT macros. */
29 #pragma warning (push)
30 #pragma warning (disable: 4005)
34 #include<krb5common.h>
39 afs_is_running(void) {
45 if (GetServiceStatus(NULL, TRANSARCAFSDAEMON,
46 &CurrentState, NULL) != NOERROR)
48 if (CurrentState != SERVICE_RUNNING)
59 if (!afs_is_running())
62 rc = ktc_ForgetAllTokens();
68 afs_unlog_cred(khm_handle cred)
71 struct ktc_principal princ;
73 wchar_t name[KCDB_MAXCCH_NAME];
75 if (!afs_is_running())
78 cbbuf = sizeof(princ);
79 if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_server_princ,
80 NULL, &princ, &cbbuf)))
83 afs_princ_to_string(&princ, name, sizeof(name));
85 _report_cs1(KHERR_INFO, L"Destroying token %1!s!",
89 rc = ktc_ForgetToken(&princ);
94 /* convert a ktc_principal to a wchar_t string form that looks like
95 name.instance@cell return 0 if it worked. non-zero otherwise
98 afs_princ_to_string(struct ktc_principal * p,
106 l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->name);
109 rv = FAILED(StringCbCopy(buf, cbbuf, wbuf));
111 StringCbCat(buf, cbbuf, L".");
112 if((l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->instance)) > 0) {
114 rv = rv || FAILED(StringCbCat(buf, cbbuf, wbuf));
120 rv = rv || FAILED(StringCbCat(buf, cbbuf, L"@"));
121 if((l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->cell)) > 0) {
123 rv = rv || FAILED(StringCbCat(buf, cbbuf, wbuf));
133 afs_list_tokens(void)
137 kcdb_credset_flush(afs_credset);
138 r = afs_list_tokens_internal();
139 kcdb_credset_collect(NULL, afs_credset, NULL, afs_credtype_id, NULL);
144 /* is the credential provided an AFS token and is it from the
146 static khm_int32 KHMAPI
147 afs_filter_by_cell(khm_handle cred, khm_int32 flags, void * rock)
149 wchar_t wcell[MAXCELLCHARS];
154 tcell = (wchar_t *) rock;
156 if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
157 type != afs_credtype_id)
160 cbsize = sizeof(wcell);
161 if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell,
162 NULL, wcell, &cbsize)))
165 if(wcscmp(wcell, tcell))
171 struct token_filter_data {
176 afs_filter_for_token(khm_handle cred, khm_int32 flags, void * rock) {
177 struct token_filter_data * pdata;
178 wchar_t ccell[MAXCELLCHARS];
182 pdata = (struct token_filter_data *) rock;
184 if (KHM_FAILED(kcdb_cred_get_type(cred, &ctype)) ||
185 ctype != afs_credtype_id)
191 if (KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell,
195 _wcsicmp(ccell, pdata->cell))
203 afs_find_token(khm_handle credset, wchar_t * cell) {
204 struct token_filter_data fdata;
205 khm_handle cred = NULL;
209 if (KHM_FAILED(kcdb_credset_find_filtered(credset,
211 afs_filter_for_token,
220 static khm_int32 KHMAPI
221 afs_filter_krb5_tkt(khm_handle cred, khm_int32 flags, void * rock)
223 wchar_t cname[KCDB_CRED_MAXCCH_NAME];
226 wchar_t * t, *tkt_cell;
229 tcell = (wchar_t *) rock;
231 if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
232 type != krb5_credtype_id)
235 cbsize = sizeof(cname);
236 if (KHM_FAILED(kcdb_cred_get_name(cred, cname, &cbsize)))
239 if (!wcsncmp(cname, L"afs/", 4)) {
241 tkt_cell = cname + 4;
243 t = wcschr(tkt_cell, L'@');
248 } else if (!wcsncmp(cname, L"afs@", 4)) {
250 tkt_cell = cname + 4;
256 if (_wcsicmp(tcell, tkt_cell))
262 static khm_int32 KHMAPI
263 afs_filter_krb4_tkt(khm_handle cred, khm_int32 flags, void * rock)
265 wchar_t cname[KCDB_CRED_MAXCCH_NAME];
268 wchar_t * t, *tkt_cell;
271 tcell = (wchar_t *) rock;
273 if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
274 type != krb4_credtype_id)
277 cbsize = sizeof(cname);
278 if (KHM_FAILED(kcdb_cred_get_name(cred, cname, &cbsize)))
281 if (!wcsncmp(cname, L"afs.", 4)) {
283 tkt_cell = cname + 4;
285 t = wcschr(tkt_cell, L'@');
290 } else if (!wcsncmp(cname, L"afs@", 4)) {
292 tkt_cell = cname + 4;
298 if (_wcsicmp(tcell, tkt_cell))
304 /* collects all AFS tokens to the root credential set using the
305 generic afs_credset credential set
308 afs_list_tokens_internal(void)
310 struct ktc_principal aserver;
311 struct ktc_principal aclient;
312 struct ktc_token atoken;
317 wchar_t location[256];
322 khm_handle ident = NULL;
323 khm_handle cred = NULL;
324 afs_tk_method method;
328 if (!afs_is_running())
331 kcdb_credset_flush(afs_credset);
333 LoadString(hResModule, IDS_DEF_LOCATION, location, ARRAYLENGTH(location));
339 memset(&aserver, 0, sizeof(aserver));
340 if (rc = ktc_ListTokens(cellNum, &cellNum, &aserver))
349 memset(&atoken, '\0', sizeof(atoken));
350 if (rc = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient))
359 /* failed attempt at trying to figure out the principal name from
360 the token. The ticket that is attached to the token is not
361 in a form that is useful at this point */
363 if(atoken.kvno == RXKAD_TKT_TYPE_KERBEROS_V5) {
364 krb5_context ctx = 0;
367 krb5_error_code code;
370 code = khm_krb5_initialize(&ctx, &cc);
374 k5c = (krb5_creds *) atoken.ticket;
376 code = pkrb5_unparse_name(ctx, k5c->client, &princ);
380 MultiByteToWideChar(CP_ACP, 0, princ, strlen(princ), idname, sizeof(idname)/sizeof(idname[0]));
382 pkrb5_free_unparsed_name(ctx, princ);
388 method = AFS_TOKEN_AUTO;
390 afs_princ_to_string(&aclient, idname, sizeof(idname));
392 /* We need to figure out a good client name which we can use
393 to create an identity which looks familiar to the user. No
394 good way of doing this, so we use a heuristic.
396 Note that, we use another heuristic to find out which
397 identity to associate the token with.
401 The assumption here is that the principal for the token is
404 if realm != cell : principal looks like user@realm@cell
405 if realm == cell : principal looks like user@realm
409 We strip the part of the string that follows the second '@'
410 sign to obtain the 'user@realm' part, which we use as the
411 credential name. If there is no second '@', we use the
412 whole principal name. */
416 ats = wcschr(idname, L'@');
417 if(ats && (ats = wcschr(ats + 1, L'@')))
421 afs_princ_to_string(&aserver, crname, sizeof(crname));
423 /* Ok, now we need to figure out which identity to associate
424 this token with. This is a little bit tricky, and there is
425 currently no good way of determining the original identity
426 used to obtain the token if it was done outside of
427 NetIDMgr. So we use a heuristic here.
431 Elsewhere, (actually in afsnewcreds.c) just after obtaining
432 AFS tokens through NetIDMgr, we enumerate the AFS tokens
433 and assign the root identity (used to obtain new creds)
434 with the AFS tokens. This would still be there in the root
435 credential set when we list tokens later on.
439 If there exists an AFS token in the root credential set for
440 the same cell, we associate this token with the same
441 identity as that credential.
443 cell = wcschr(crname, L'@');
454 if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
460 kcdb_cred_get_identity(c, &ident);
462 kcdb_cred_get_attr(c, afs_attr_method, NULL,
464 kcdb_cred_release(c);
468 /* If that failed, we have try another trick. If there is a
469 Krb5 ticket of the form afs/<cell>@<realm> or afs@<CELL>
470 where <cell> matches our cell, then we pick the identity
475 If Krb5 was used to obtain the token, then there is a Krb5
476 ticket of the form afs/<cell>@<REALM> or afs@<CELL> still
477 in the cache. This is also true for Krb524 token
482 If such a Krb5 ticket is found, use the identity of that
483 credential as the identity of the AFS token.
486 if (ident == NULL && cell != NULL) {
489 if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
493 kcdb_cred_get_identity(c, &ident);
494 /* this could be Krb5 or Krb524, so we leave method at
496 method = AFS_TOKEN_AUTO;
497 kcdb_cred_release(c);
501 /* If that didn't work either, we look for a Krb4 ticket of
502 the form afs.<cell>@<REALM> or afs@<CELL> which matches the
507 If Krb4 was used to obtain an AFS token, then there should
508 be a Krb4 ticket of the form afs.<cell>@<REALM> or
509 afs@<CELL> in the cache.
513 If such a ticket is found, then use the identity of that
514 credential as the identity of the AFS token.
516 if (ident == NULL && cell != NULL) {
519 if (krb4_credtype_id < 0) {
520 kcdb_credtype_get_id(KRB4_CREDTYPE_NAME,
524 if (krb4_credtype_id >= 0 &&
525 KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
530 kcdb_cred_get_identity(c, &ident);
531 kcdb_cred_release(c);
532 method = AFS_TOKEN_KRB4;
537 /* Finally, we allow any extension plugins to give this a shot */
538 if (ident == NULL && cell != NULL) {
539 afs_ext_resolve_token(cell,
547 /* One more thing to try. If we have a cell->identity
548 mapping, then we try that. */
549 if (ident == NULL && cell != NULL) {
550 khm_handle h_cellmap;
551 wchar_t tidname[KCDB_IDENT_MAXCCH_NAME];
554 cb = sizeof(tidname);
556 if (KHM_SUCCEEDED(khc_open_space(csp_afscred,
559 if (KHM_SUCCEEDED(khc_read_string(h_cellmap,
563 kcdb_identity_create(tidname,
564 KCDB_IDENT_FLAG_CREATE,
567 khc_close_space(h_cellmap);
571 /* all else failed */
573 if(KHM_FAILED(kcdb_identity_create(idname,
574 KCDB_IDENT_FLAG_CREATE,
579 if(KHM_FAILED(kcdb_cred_create(crname, ident, afs_credtype_id, &cred)))
582 kcdb_cred_set_attr(cred, afs_attr_method, &method, sizeof(method));
584 TimetToFileTime(atoken.endTime, &ft);
585 kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &ft, sizeof(ft));
586 if (atoken.startTime != 0) {
587 TimetToFileTime(atoken.startTime, &ft);
588 kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft));
590 kcdb_cred_set_attr(cred, afs_attr_client_princ,
591 &aclient, sizeof(aclient));
592 kcdb_cred_set_attr(cred, afs_attr_server_princ,
593 &aserver, sizeof(aserver));
596 kcdb_cred_set_attr(cred, afs_attr_cell, cell, (khm_size)KCDB_CBSIZE_AUTO);
599 kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION,
600 location, (khm_size)KCDB_CBSIZE_AUTO);
602 kcdb_credset_add_cred(afs_credset, cred, -1);
604 /* both these calls are NULL pointer safe */
605 kcdb_cred_release(cred);
607 kcdb_identity_release(ident);
613 kcdb_identity_release(ident);
615 kcdb_cred_release(cred);
621 #define ALLOW_REGISTER 1
623 ViceIDToUsername(char *username,
627 struct ktc_principal *aclient,
628 struct ktc_principal *aserver,
629 struct ktc_token *atoken)
631 static char lastcell[MAXCELLCHARS+1] = { 0 };
632 static char confname[512] = { 0 };
633 char username_copy[BUFSIZ];
634 long viceId = ANONYMOUSID; /* AFS uid of user */
636 #ifdef ALLOW_REGISTER
638 #endif /* ALLOW_REGISTER */
640 if (confname[0] == '\0') {
641 StringCbCopyA(confname, sizeof(confname), AFSDIR_CLIENT_ETC_DIRPATH);
644 StringCbCopyA(lastcell, sizeof(lastcell), aserver->cell);
646 if (!pr_Initialize (0, confname, aserver->cell)) {
647 char sname[PR_MAXNAMELEN];
648 StringCbCopyA(sname, sizeof(sname), username);
649 status = pr_SNameToId (sname, &viceId);
653 #ifdef AFS_ID_TO_NAME
655 * This is a crock, but it is Transarc's crock, so
656 * we have to play along in order to get the
657 * functionality. The way the afs id is stored is
658 * as a string in the username field of the token.
659 * Contrary to what you may think by looking at
660 * the code for tokens, this hack (AFS ID %d) will
661 * not work if you change %d to something else.
663 #endif /* AFS_ID_TO_NAME */
665 * This code is taken from cklog -- it lets people
666 * automatically register with the ptserver in foreign cells
669 /* copy the username because pr_CreateUser will lowercase it */
670 StringCbCopyA(username_copy, BUFSIZ, username);
672 #ifdef ALLOW_REGISTER
674 if (viceId != ANONYMOUSID) {
675 #else /* ALLOW_REGISTER */
676 if ((status == 0) && (viceId != ANONYMOUSID))
677 #endif /* ALLOW_REGISTER */
679 #ifdef AFS_ID_TO_NAME
680 StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
681 #endif /* AFS_ID_TO_NAME */
683 #ifdef ALLOW_REGISTER
684 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
686 StringCbCopyA(aclient->name, sizeof(aclient->name), username);
687 StringCbCopyA(aclient->instance, sizeof(aclient->instance), "");
688 StringCbCopyA(aclient->cell, sizeof(aclient->cell), realm_of_user);
689 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
691 if (status = pr_Initialize(1L, confname, aserver->cell))
693 status = pr_CreateUser(username, &id);
695 StringCbCopyA(username, BUFSIZ, username_copy);
696 #ifdef AFS_ID_TO_NAME
697 StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
698 #endif /* AFS_ID_TO_NAME */
701 #endif /* ALLOW_REGISTER */
707 copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) {
708 krb5_error_code code;
712 code = pkrb5_decode_ticket(&v5cred->ticket, &ticket);
714 len = krb5_princ_realm(context, ticket->server)->length;
715 if (len > destlen - 1)
718 StringCbCopyA(dest, len, krb5_princ_realm(context, ticket->server)->data);
720 pkrb5_free_ticket(context, ticket);
725 afs_klog(khm_handle identity,
730 afs_tk_method method,
731 time_t * tok_expiration,
736 struct ktc_principal aserver;
737 struct ktc_principal aclient;
738 char realm_of_user[MAXKTCREALMLEN]; /* Kerberos realm of user */
739 char realm_of_cell[MAXKTCREALMLEN]; /* Kerberos realm of cell */
740 char local_cell[MAXCELLCHARS+1];
741 char Dmycell[MAXCELLCHARS+1];
742 struct ktc_token atoken;
743 struct ktc_token btoken;
744 afs_conf_cell ak_cellconfig; /* General information about the cell */
747 char ServiceName[128];
748 khm_handle confighandle = NULL;
749 khm_int32 supports_krb4 = (pkrb_get_tf_realm == NULL ? 0 : 1);
750 khm_int32 got524cred = 0;
753 BOOL bGotCreds = FALSE; /* got creds? */
756 *tok_expiration = (time_t) 0;
758 if (!afs_is_running()) {
759 _report_sr0(KHERR_WARNING, IDS_ERR_NOSERVICE);
763 if ( !realm ) realm = "";
764 if ( !cell ) cell = "";
765 if ( !service ) service = "";
767 memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
768 memset(RealmName, '\0', sizeof(RealmName));
769 memset(CellName, '\0', sizeof(CellName));
770 memset(ServiceName, '\0', sizeof(ServiceName));
771 memset(realm_of_user, '\0', sizeof(realm_of_user));
772 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
773 memset(Dmycell, '\0', sizeof(Dmycell));
775 // NULL or empty cell returns information on local cell
777 StringCbCopyA(Dmycell, sizeof(Dmycell), cell);
779 rc = afs_get_cellconfig(Dmycell, &ak_cellconfig, local_cell);
781 _reportf(L"afs_get_cellconfig returns %ld", rc);
783 _report_sr2(KHERR_ERROR, IDS_ERR_CELLCONFIG, _cstr(Dmycell), _int32(rc));
784 _suggest_sr(IDS_ERR_CELLCONFIG_S, KHERR_SUGGEST_NONE);
789 if (linkedCell && ak_cellconfig.linkedCell)
790 StringCbCopyA(linkedCell, MAXCELLCHARS,
791 ak_cellconfig.linkedCell);
793 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
794 afs_realm_of_cell(&ak_cellconfig, FALSE));
796 if (strlen(service) == 0)
797 StringCbCopyA(ServiceName, sizeof(ServiceName), "afs");
799 StringCbCopyA(ServiceName, sizeof(ServiceName), service);
801 if (strlen(cell) == 0)
802 StringCbCopyA(CellName, sizeof(CellName), local_cell);
804 StringCbCopyA(CellName, sizeof(CellName), cell);
806 if (strlen(realm) == 0)
807 StringCbCopyA(RealmName, sizeof(RealmName), realm_of_cell);
809 StringCbCopyA(RealmName, sizeof(RealmName), realm);
811 memset(&creds, '\0', sizeof(creds));
813 /*** Kerberos 5 and 524 ***/
815 if (method == AFS_TOKEN_AUTO ||
816 method == AFS_TOKEN_KRB5 ||
817 method == AFS_TOKEN_KRB524) {
819 krb5_context context = 0;
820 krb5_ccache k5cc = 0;
822 krb5_creds * k5creds = 0;
824 krb5_principal client_principal = 0;
825 krb5_flags flags = 0;
831 _reportf(L"Trying Kerberos 5");
833 if (!(r = khm_krb5_initialize(identity, &context, &k5cc))) {
836 memset((char *)&increds, 0, sizeof(increds));
838 pkrb5_cc_get_principal(context, k5cc, &client_principal);
839 i = krb5_princ_realm(context, client_principal)->length;
840 if (i > MAXKTCREALMLEN-1)
841 i = MAXKTCREALMLEN-1;
842 StringCchCopyNA(realm_of_user, ARRAYLENGTH(realm_of_user),
843 krb5_princ_realm(context, client_principal)->data,
846 _reportf(L"khm_krb5_initialize returns code %d", r);
850 increds.client = client_principal;
851 increds.times.endtime = 0;
852 /* Ask for DES since that is what V4 understands */
853 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
855 #ifdef KRB5_TC_NOTICKET
856 flags = KRB5_TC_OPENCLOSE;
857 r = pkrb5_cc_set_flags(context, k5cc, flags);
859 if (strlen(realm) != 0) {
861 /* First try Service/Cell@REALM */
862 if (r = pkrb5_build_principal(context, &increds.server,
868 _reportf(L"krb5_build_principal returns %d", r);
872 r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
873 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
874 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
875 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
876 /* Next try Service@REALM */
877 pkrb5_free_principal(context, increds.server);
878 r = pkrb5_build_principal(context, &increds.server,
884 r = pkrb5_get_credentials(context, 0, k5cc,
888 /* Check to make sure we received a valid ticket; if not remove it
889 * and try again. Perhaps there are two service tickets for the
890 * same service in the ccache.
892 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
893 pkrb5_free_principal(context, increds.server);
894 pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
895 pkrb5_free_creds(context, k5creds);
897 goto retry_retcred_1;
901 /* First try Service/Cell@_CLIENT_REALM */
902 if (r = pkrb5_build_principal(context, &increds.server,
903 (int) strlen(realm_of_user),
908 _reportf(L"krb5_build_principal returns %d", r);
912 r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
914 /* the user realm is a valid cell realm */
915 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell), realm_of_user);
917 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
918 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
919 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
920 pkrb5_free_principal(context, increds.server);
921 r = pkrb5_build_principal(context, &increds.server,
922 (int) strlen(realm_of_cell),
928 r = pkrb5_get_credentials(context, 0, k5cc,
931 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
932 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
933 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
934 strlen(realm_of_cell) == 0) {
935 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
936 afs_realm_of_cell(&ak_cellconfig, TRUE));
938 pkrb5_free_principal(context, increds.server);
939 r = pkrb5_build_principal(context, &increds.server,
940 (int) strlen(realm_of_cell),
946 r = pkrb5_get_credentials(context, 0, k5cc,
949 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
950 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
951 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
952 /* Next try Service@REALM */
953 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
954 afs_realm_of_cell(&ak_cellconfig, FALSE));
956 pkrb5_free_principal(context, increds.server);
957 r = pkrb5_build_principal(context, &increds.server,
958 (int) strlen(realm_of_cell),
963 r = pkrb5_get_credentials(context, 0, k5cc,
966 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
967 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
968 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
969 strlen(realm_of_cell) == 0) {
970 /* Next try Service@REALM */
971 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
972 afs_realm_of_cell(&ak_cellconfig, TRUE));
974 pkrb5_free_principal(context, increds.server);
975 r = pkrb5_build_principal(context, &increds.server,
976 (int) strlen(realm_of_cell),
981 r = pkrb5_get_credentials(context, 0, k5cc,
985 if (r == 0 && strlen(realm_of_cell) == 0)
986 copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
988 /* Check to make sure we received a valid ticket; if not remove it
989 * and try again. Perhaps there are two service tickets for the
990 * same service in the ccache.
992 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
993 pkrb5_free_principal(context, increds.server);
994 pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
995 pkrb5_free_creds(context, k5creds);
997 goto retry_retcred_2;
1001 pkrb5_free_principal(context, increds.server);
1002 pkrb5_free_principal(context, client_principal);
1003 client_principal = 0;
1004 #ifdef KRB5_TC_NOTICKET
1005 flags = KRB5_TC_OPENCLOSE | KRB5_TC_NOTICKET;
1006 pkrb5_cc_set_flags(context, k5cc, flags);
1009 (void) pkrb5_cc_close(context, k5cc);
1013 _reportf(L"Code %d while getting credentials", r);
1018 if ( k5creds->ticket.length > MAXKTCTICKETLEN ||
1019 method == AFS_TOKEN_KRB524) {
1023 /* This code inserts the entire K5 ticket into the token */
1025 _reportf(L"Trying K5 SetToken");
1027 memset(&aserver, '\0', sizeof(aserver));
1028 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1029 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1031 memset(&atoken, '\0', sizeof(atoken));
1032 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
1033 atoken.startTime = k5creds->times.starttime;
1034 atoken.endTime = k5creds->times.endtime;
1035 memcpy(&atoken.sessionKey,
1036 k5creds->keyblock.contents,
1037 k5creds->keyblock.length);
1038 atoken.ticketLen = k5creds->ticket.length;
1039 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
1042 *tok_expiration = k5creds->times.endtime;
1045 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
1046 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
1047 if ( rc == KTC_NOCM && retry < 20 ) {
1050 goto retry_gettoken5;
1055 if (atoken.kvno == btoken.kvno &&
1056 atoken.ticketLen == btoken.ticketLen &&
1057 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1058 sizeof(atoken.sessionKey)) &&
1059 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1062 if (k5creds && context)
1063 pkrb5_free_creds(context, k5creds);
1066 pkrb5_free_context(context);
1068 _reportf(L"Same token already exists");
1074 // * Reset the "aclient" structure before we call ktc_SetToken.
1075 // * This structure was first set by the ktc_GetToken call when
1076 // * we were comparing whether identical tokens already existed.
1078 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
1079 StringCchCopyNA(aclient.name, MAXKTCNAMELEN,
1080 k5creds->client->data[0].data, len);
1082 if ( k5creds->client->length > 1 ) {
1083 StringCbCatA(aclient.name, sizeof(aclient.name), ".");
1084 p = aclient.name + strlen(aclient.name);
1085 len = (int) min(k5creds->client->data[1].length,
1086 MAXKTCNAMELEN - strlen(aclient.name) - 1);
1087 StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
1088 k5creds->client->data[1].data, len);
1091 aclient.instance[0] = '\0';
1093 StringCbCopyA(aclient.cell, sizeof(aclient.cell), realm_of_cell);
1095 StringCbCatA(aclient.name, sizeof(aclient.name), "@");
1096 p = aclient.name + strlen(aclient.name);
1097 len = (int) min(k5creds->client->realm.length,
1098 MAXKTCNAMELEN - strlen(aclient.name) - 1);
1099 StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
1100 k5creds->client->realm.data, len);
1102 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1103 &aclient, &aserver, &atoken);
1105 rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
1109 if (k5creds && context)
1110 pkrb5_free_creds(context, k5creds);
1113 pkrb5_free_context(context);
1118 _reportf(L"SetToken returns code %d", rc);
1122 _reportf(L"Trying Krb524");
1124 if (pkrb524_convert_creds_kdc &&
1125 (method == AFS_TOKEN_AUTO || method == AFS_TOKEN_KRB524)) {
1126 /* This requires krb524d to be running with the KDC */
1127 r = pkrb524_convert_creds_kdc(context, k5creds, &creds);
1129 _reportf(L"Code %d while converting credentials", r);
1138 if (client_principal)
1139 pkrb5_free_principal(context, client_principal);
1141 if (k5creds && context)
1142 pkrb5_free_creds(context, k5creds);
1145 pkrb5_free_context(context);
1151 if (supports_krb4) {
1152 kcdb_identity_get_config(identity, 0, &confighandle);
1153 khc_read_int32(confighandle, L"Krb4Cred\\Krb4NewCreds", &supports_krb4);
1154 khc_close_space(confighandle);
1158 _reportf(L"Kerberos 4 not configured");
1160 if (!bGotCreds && supports_krb4 &&
1161 strlen(RealmName) < REALM_SZ &&
1162 (method == AFS_TOKEN_AUTO ||
1163 method == AFS_TOKEN_KRB4)) {
1167 _reportf(L"Trying Kerberos 4");
1169 if (!realm_of_user[0] ) {
1170 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user))
1172 /* can't determine realm of user */
1173 _reportf(L"krb_get_tf_realm returns %d", rc);
1178 _reportf(L"Trying to find %S.%S@%S", ServiceName, CellName, RealmName);
1179 rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
1180 if (rc == NO_TKT_FIL) {
1181 // if the problem is that we have no krb4 tickets
1182 // do not attempt to continue
1183 _reportf(L"krb_get_cred returns %d (no ticket file)", rc);
1187 if (rc != KSUCCESS) {
1188 _reportf(L"Trying to find %S@%S", ServiceName, RealmName);
1189 rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
1192 if (rc != KSUCCESS) {
1193 _reportf(L"Trying to obtain new ticket");
1194 if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1195 CellName, RealmName, 0))
1197 if ((rc = (*pkrb_get_cred)(ServiceName, CellName,
1198 RealmName, &creds)) != KSUCCESS) {
1201 _reportf(L"Got %S.%S@%S", ServiceName, CellName, RealmName);
1203 } else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1206 if ((rc = (*pkrb_get_cred)(ServiceName, "",
1207 RealmName, &creds)) != KSUCCESS) {
1210 _reportf(L"Got %S@%S", ServiceName, RealmName);
1225 memset(&aserver, '\0', sizeof(aserver));
1226 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1227 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1229 memset(&atoken, '\0', sizeof(atoken));
1230 atoken.kvno = (short)creds.kvno;
1231 atoken.startTime = creds.issue_date;
1232 atoken.endTime = (*pkrb_life_to_time)(creds.issue_date,creds.lifetime);
1233 memcpy(&atoken.sessionKey, creds.session, 8);
1234 atoken.ticketLen = creds.ticket_st.length;
1235 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
1238 *tok_expiration = atoken.endTime;
1240 if (!(rc = ktc_GetToken(&aserver, &btoken,
1241 sizeof(btoken), &aclient)) &&
1242 atoken.kvno == btoken.kvno &&
1243 atoken.ticketLen == btoken.ticketLen &&
1244 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1245 sizeof(atoken.sessionKey)) &&
1246 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1253 // Reset the "aclient" structure before we call ktc_SetToken.
1254 // This structure was first set by the ktc_GetToken call when
1255 // we were comparing whether identical tokens already existed.
1257 StringCchCopyA(aclient.name, MAXKTCNAMELEN, creds.pname);
1258 if (creds.pinst[0]) {
1259 StringCchCatA(aclient.name, MAXKTCNAMELEN, ".");
1260 StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.pinst);
1263 StringCbCopyA(aclient.instance, sizeof(aclient.instance), "");
1265 StringCchCatA(aclient.name, MAXKTCNAMELEN, "@");
1266 StringCchCatA(aclient.name, MAXKTCNAMELEN, got524cred ? realm_of_user : creds.realm);
1268 StringCbCopyA(aclient.cell, sizeof(aclient.cell), CellName);
1270 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1271 &aclient, &aserver, &atoken);
1273 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
1274 afs_report_error(rc, "ktc_SetToken()");
1277 } else if (method == AFS_TOKEN_AUTO ||
1278 method >= AFS_TOKEN_USER) {
1279 /* we couldn't get a token using Krb5, Krb524 or Krb4, either
1280 because we couldn't get the necessary credentials or
1281 because the method was set to not use those. Now we
1282 dispatch to any extensions to see if they have better
1285 rc = !afs_ext_klog(method,
1293 /* if the return code was not set, we should set it now.
1294 Otherwise we let the code go through. */
1296 /* No tokens were obtained. We should report something */
1297 _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
1301 rc = KHM_ERROR_GENERAL;
1306 if (ak_cellconfig.linkedCell)
1307 free(ak_cellconfig.linkedCell);
1312 /**************************************/
1313 /* afs_realm_of_cell(): */
1314 /**************************************/
1316 afs_realm_of_cell(afs_conf_cell *cellconfig, BOOL referral_fallback)
1318 char krbhst[MAX_HSTNM]="";
1319 static char krbrlm[MAXKTCREALMLEN+1]="";
1320 krb5_context ctx = 0;
1321 char ** realmlist=NULL;
1322 krb5_error_code r = 0;
1327 if (referral_fallback) {
1329 p = strchr(cellconfig->hostName[0], '.');
1331 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1333 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1334 #if _MSC_VER >= 1400
1335 _strupr_s(krbrlm, sizeof(krbrlm));
1340 if ( pkrb5_init_context ) {
1341 r = pkrb5_init_context(&ctx);
1343 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
1344 if ( !r && realmlist && realmlist[0] ) {
1345 StringCbCopyA(krbrlm, sizeof(krbrlm), realmlist[0]);
1346 pkrb5_free_host_realm(ctx, realmlist);
1349 pkrb5_free_context(ctx);
1353 if (pkrb_get_krbhst && pkrb_realmofhost) {
1354 StringCbCopyA(krbrlm, sizeof(krbrlm),
1355 (char *)(*pkrb_realmofhost)(cellconfig->hostName[0]));
1356 if ((*pkrb_get_krbhst)(krbhst, krbrlm, 1) != KSUCCESS)
1362 p = strchr(cellconfig->hostName[0], '.');
1364 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1366 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1367 #if _MSC_VER >= 1400
1368 _strupr_s(krbrlm, sizeof(krbrlm));
1378 /**************************************/
1379 /* afs_get_cellconfig(): */
1380 /**************************************/
1382 afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
1387 local_cell[0] = (char)0;
1388 memset(cellconfig, 0, sizeof(*cellconfig));
1390 cellconfig->cbsize = sizeof(*cellconfig);
1392 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
1393 if (rc = cm_GetRootCellName(local_cell)) {
1397 if (strlen(cell) == 0)
1398 StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
1400 /* WIN32: cm_SearchCellFile(cell, newcell, pcallback, pdata) */
1401 StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
1403 rc = cm_SearchCellFile(cell, NULL, afs_get_cellconfig_callback,
1406 rc = cm_SearchCellByDNS(cell, NULL, &ttl,
1407 afs_get_cellconfig_callback,
1408 (void*) cellconfig);
1413 /**************************************/
1414 /* afs_get_cellconfig_callback(): */
1415 /**************************************/
1417 afs_get_cellconfig_callback(void *cellconfig,
1418 struct sockaddr_in *addrp,
1421 afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
1423 cc->hostAddr[cc->numServers] = *addrp;
1424 StringCbCopyA(cc->hostName[cc->numServers],
1425 sizeof(cc->hostName[0]), namep);
1431 /**************************************/
1432 /* afs_report_error(): */
1433 /**************************************/
1435 afs_report_error(LONG rc, LPCSTR FailedFunctionName)
1438 const char *errText;
1440 // Using AFS defines as error messages for now, until Transarc
1441 // gets back to me with "string" translations of each of these
1443 if (rc == KTC_ERROR)
1444 errText = "KTC_ERROR";
1445 else if (rc == KTC_TOOBIG)
1446 errText = "KTC_TOOBIG";
1447 else if (rc == KTC_INVAL)
1448 errText = "KTC_INVAL";
1449 else if (rc == KTC_NOENT)
1450 errText = "KTC_NOENT";
1451 else if (rc == KTC_PIOCTLFAIL)
1452 errText = "KTC_PIOCTLFAIL";
1453 else if (rc == KTC_NOPIOCTL)
1454 errText = "KTC_NOPIOCTL";
1455 else if (rc == KTC_NOCELL)
1456 errText = "KTC_NOCELL";
1457 else if (rc == KTC_NOCM)
1458 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
1460 errText = "Unknown error!";
1462 StringCbPrintfA(message, sizeof(message),
1463 "%s\n(%s failed)", errText, FailedFunctionName);
1464 _report_cs1(KHERR_ERROR, L"%1!S!", _cptr(message));
1470 GetServiceStatus(LPSTR lpszMachineName,
1471 LPSTR lpszServiceName,
1472 DWORD *lpdwCurrentState,
1473 DWORD *lpdwWaitHint)
1476 SC_HANDLE schSCManager = NULL;
1477 SC_HANDLE schService = NULL;
1478 DWORD fdwDesiredAccess = 0;
1479 SERVICE_STATUS ssServiceStatus = {0};
1482 *lpdwCurrentState = 0;
1484 fdwDesiredAccess = GENERIC_READ;
1486 schSCManager = OpenSCManagerA(lpszMachineName,
1490 if(schSCManager == NULL) {
1491 hr = GetLastError();
1495 schService = OpenServiceA(schSCManager,
1499 if(schService == NULL) {
1500 hr = GetLastError();
1504 fRet = QueryServiceStatus(schService,
1508 hr = GetLastError();
1512 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
1514 *lpdwWaitHint = ssServiceStatus.dwWaitHint;
1517 CloseServiceHandle(schService);
1518 CloseServiceHandle(schSCManager);
1523 DWORD ServiceControl(LPSTR lpszMachineName,
1524 LPSTR lpszServiceName,
1528 SC_HANDLE schSCManager = NULL;
1529 SC_HANDLE schService = NULL;
1530 DWORD fdwDesiredAccess = 0;
1531 SERVICE_STATUS ssServiceStatus = {0};
1533 DWORD dwCurrentState = 0;
1537 fdwDesiredAccess = GENERIC_READ;
1539 schSCManager = OpenSCManagerA(lpszMachineName, NULL,
1542 if(schSCManager == NULL) {
1543 hr = GetLastError();
1547 fdwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
1549 schService = OpenServiceA(schSCManager, lpszServiceName,
1552 if(schService == NULL) {
1553 hr = GetLastError();
1557 fRet = QueryServiceStatus(schService, &ssServiceStatus);
1560 hr = GetLastError();
1564 dwCurrentState = ssServiceStatus.dwCurrentState;
1566 if (dwCurrentState == SERVICE_STOPPED &&
1567 dwNewState == SERVICE_RUNNING) {
1569 fRet = StartService(schService, 0, NULL);
1571 if (fRet == FALSE) {
1572 hr = GetLastError();
1577 if (dwCurrentState == SERVICE_RUNNING &&
1578 dwNewState == SERVICE_STOPPED) {
1579 fRet = ControlService(schService, SERVICE_CONTROL_STOP,
1582 if (fRet == FALSE) {
1583 hr = GetLastError();
1590 CloseServiceHandle(schService);
1591 CloseServiceHandle(schSCManager);
1597 afs_check_for_cell_realm_match(khm_handle identity, char * cell) {
1598 char local_cell[MAXCELLCHARS];
1599 wchar_t wrealm[MAXCELLCHARS];
1600 wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
1604 afs_conf_cell cellconfig;
1607 ZeroMemory(local_cell, sizeof(local_cell));
1608 ZeroMemory(&cellconfig, sizeof(cellconfig));
1610 rc = afs_get_cellconfig(cell, &cellconfig, local_cell);
1614 realm = afs_realm_of_cell(&cellconfig, FALSE);
1615 if (cellconfig.linkedCell)
1616 free(cellconfig.linkedCell);
1620 AnsiStrToUnicode(wrealm, sizeof(wrealm), realm);
1622 cb = sizeof(idname);
1624 kcdb_identity_get_name(identity, idname, &cb);
1626 atsign = wcschr(idname, L'@');
1627 if (atsign && atsign[1] && !_wcsicmp(atsign + 1, wrealm)) {