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) {
735 struct ktc_principal aserver;
736 struct ktc_principal aclient;
737 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
738 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
739 char local_cell[MAXCELLCHARS+1];
740 char Dmycell[MAXCELLCHARS+1];
741 struct ktc_token atoken;
742 struct ktc_token btoken;
743 afs_conf_cell ak_cellconfig; /* General information about the cell */
746 char ServiceName[128];
747 khm_handle confighandle = NULL;
748 khm_int32 supports_krb4 = (pkrb_get_tf_realm == NULL ? 0 : 1);
749 khm_int32 got524cred = 0;
752 BOOL bGotCreds = FALSE; /* got creds? */
755 *tok_expiration = (time_t) 0;
757 if (!afs_is_running()) {
758 _report_sr0(KHERR_WARNING, IDS_ERR_NOSERVICE);
762 if ( !realm ) realm = "";
763 if ( !cell ) cell = "";
764 if ( !service ) service = "";
766 memset(RealmName, '\0', sizeof(RealmName));
767 memset(CellName, '\0', sizeof(CellName));
768 memset(ServiceName, '\0', sizeof(ServiceName));
769 memset(realm_of_user, '\0', sizeof(realm_of_user));
770 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
771 memset(Dmycell, '\0', sizeof(Dmycell));
773 // NULL or empty cell returns information on local cell
775 StringCbCopyA(Dmycell, sizeof(Dmycell), cell);
777 rc = afs_get_cellconfig(Dmycell, &ak_cellconfig, local_cell);
779 _reportf(L"afs_get_cellconfig returns %ld", rc);
781 _report_sr2(KHERR_ERROR, IDS_ERR_CELLCONFIG, _cstr(Dmycell), _int32(rc));
782 _suggest_sr(IDS_ERR_CELLCONFIG_S, KHERR_SUGGEST_NONE);
787 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
788 afs_realm_of_cell(&ak_cellconfig, FALSE));
790 if (strlen(service) == 0)
791 StringCbCopyA(ServiceName, sizeof(ServiceName), "afs");
793 StringCbCopyA(ServiceName, sizeof(ServiceName), service);
795 if (strlen(cell) == 0)
796 StringCbCopyA(CellName, sizeof(CellName), local_cell);
798 StringCbCopyA(CellName, sizeof(CellName), cell);
800 if (strlen(realm) == 0)
801 StringCbCopyA(RealmName, sizeof(RealmName), realm_of_cell);
803 StringCbCopyA(RealmName, sizeof(RealmName), realm);
805 memset(&creds, '\0', sizeof(creds));
807 /*** Kerberos 5 and 524 ***/
809 if (method == AFS_TOKEN_AUTO ||
810 method == AFS_TOKEN_KRB5 ||
811 method == AFS_TOKEN_KRB524) {
813 krb5_context context = 0;
814 krb5_ccache k5cc = 0;
816 krb5_creds * k5creds = 0;
818 krb5_principal client_principal = 0;
819 krb5_flags flags = 0;
825 _reportf(L"Trying Kerberos 5");
827 if (!(r = khm_krb5_initialize(identity, &context, &k5cc))) {
830 memset((char *)&increds, 0, sizeof(increds));
832 pkrb5_cc_get_principal(context, k5cc, &client_principal);
833 i = krb5_princ_realm(context, client_principal)->length;
836 StringCchCopyNA(realm_of_user, ARRAYLENGTH(realm_of_user),
837 krb5_princ_realm(context, client_principal)->data,
840 _reportf(L"khm_krb5_initialize returns code %d", r);
844 /* First try Service/Cell@REALM */
845 if (r = pkrb5_build_principal(context, &increds.server,
846 (int) strlen(RealmName),
851 _reportf(L"krb5_build_principal returns %d", r);
855 increds.client = client_principal;
856 increds.times.endtime = 0;
857 /* Ask for DES since that is what V4 understands */
858 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
860 #ifdef KRB5_TC_NOTICKET
861 flags = KRB5_TC_OPENCLOSE;
862 r = pkrb5_cc_set_flags(context, k5cc, flags);
865 r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
866 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
867 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
869 StringCbCopyA(RealmName, sizeof(RealmName),
870 afs_realm_of_cell(&ak_cellconfig, TRUE));
872 pkrb5_free_principal(context, increds.server);
873 r = pkrb5_build_principal(context, &increds.server,
874 (int) strlen(RealmName),
880 r = pkrb5_get_credentials(context, 0, k5cc,
883 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
884 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
885 /* Next try Service@REALM */
886 pkrb5_free_principal(context, increds.server);
887 r = pkrb5_build_principal(context, &increds.server,
888 (int) strlen(RealmName),
893 r = pkrb5_get_credentials(context, 0, k5cc,
897 /* Check to make sure we received a valid ticket; if not remove it
898 * and try again. Perhaps there are two service tickets for the
899 * same service in the ccache.
901 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
902 pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
903 pkrb5_free_creds(context, k5creds);
908 if (r == 0 && strlen(RealmName) == 0)
909 copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
911 pkrb5_free_principal(context, increds.server);
912 pkrb5_free_principal(context, client_principal);
913 client_principal = 0;
914 #ifdef KRB5_TC_NOTICKET
915 flags = KRB5_TC_OPENCLOSE | KRB5_TC_NOTICKET;
916 pkrb5_cc_set_flags(context, k5cc, flags);
919 (void) pkrb5_cc_close(context, k5cc);
923 _reportf(L"Code %d while getting credentials", r);
928 if ( k5creds->ticket.length > MAXKTCTICKETLEN ||
929 method == AFS_TOKEN_KRB524) {
933 /* This code inserts the entire K5 ticket into the token */
935 _reportf(L"Trying K5 SetToken");
937 memset(&aserver, '\0', sizeof(aserver));
938 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
939 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
941 memset(&atoken, '\0', sizeof(atoken));
942 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
943 atoken.startTime = k5creds->times.starttime;
944 atoken.endTime = k5creds->times.endtime;
945 memcpy(&atoken.sessionKey,
946 k5creds->keyblock.contents,
947 k5creds->keyblock.length);
948 atoken.ticketLen = k5creds->ticket.length;
949 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
952 *tok_expiration = k5creds->times.endtime;
955 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
956 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
957 if ( rc == KTC_NOCM && retry < 20 ) {
960 goto retry_gettoken5;
965 if (atoken.kvno == btoken.kvno &&
966 atoken.ticketLen == btoken.ticketLen &&
967 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
968 sizeof(atoken.sessionKey)) &&
969 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
972 if (k5creds && context)
973 pkrb5_free_creds(context, k5creds);
976 pkrb5_free_context(context);
978 _reportf(L"Same token already exists");
983 // * Reset the "aclient" structure before we call ktc_SetToken.
984 // * This structure was first set by the ktc_GetToken call when
985 // * we were comparing whether identical tokens already existed.
987 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
988 StringCchCopyNA(aclient.name, MAXKTCNAMELEN,
989 k5creds->client->data[0].data, len);
991 if ( k5creds->client->length > 1 ) {
992 StringCbCatA(aclient.name, sizeof(aclient.name), ".");
993 p = aclient.name + strlen(aclient.name);
994 len = (int) min(k5creds->client->data[1].length,
995 MAXKTCNAMELEN - strlen(aclient.name) - 1);
996 StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
997 k5creds->client->data[1].data, len);
1000 aclient.instance[0] = '\0';
1002 StringCbCopyA(aclient.cell, sizeof(aclient.cell), realm_of_cell);
1004 StringCbCatA(aclient.name, sizeof(aclient.name), "@");
1005 p = aclient.name + strlen(aclient.name);
1006 len = (int) min(k5creds->client->realm.length,
1007 MAXKTCNAMELEN - strlen(aclient.name) - 1);
1008 StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
1009 k5creds->client->realm.data, len);
1011 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1012 &aclient, &aserver, &atoken);
1014 rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
1018 if (k5creds && context)
1019 pkrb5_free_creds(context, k5creds);
1022 pkrb5_free_context(context);
1027 _reportf(L"SetToken returns code %d", rc);
1031 _reportf(L"Trying Krb524");
1033 if (pkrb524_convert_creds_kdc &&
1034 (method == AFS_TOKEN_AUTO || method == AFS_TOKEN_KRB524)) {
1035 /* This requires krb524d to be running with the KDC */
1036 r = pkrb524_convert_creds_kdc(context, k5creds, &creds);
1038 _reportf(L"Code %d while converting credentials", r);
1047 if (client_principal)
1048 pkrb5_free_principal(context, client_principal);
1050 if (k5creds && context)
1051 pkrb5_free_creds(context, k5creds);
1054 pkrb5_free_context(context);
1060 if (supports_krb4) {
1061 kcdb_identity_get_config(identity, 0, &confighandle);
1062 khc_read_int32(confighandle, L"Krb4Cred\\Krb4NewCreds", &supports_krb4);
1063 khc_close_space(confighandle);
1067 _reportf(L"Kerberos 4 not configured");
1069 if (!bGotCreds && supports_krb4 &&
1070 (method == AFS_TOKEN_AUTO ||
1071 method == AFS_TOKEN_KRB4)) {
1075 _reportf(L"Trying Kerberos 4");
1077 if (!realm_of_user[0] ) {
1078 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user))
1080 /* can't determine realm of user */
1081 _reportf(L"krb_get_tf_realm returns %d", rc);
1086 _reportf(L"Trying to find %S.%S@%S", ServiceName, CellName, RealmName);
1087 rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
1088 if (rc == NO_TKT_FIL) {
1089 // if the problem is that we have no krb4 tickets
1090 // do not attempt to continue
1091 _reportf(L"krb_get_cred returns %d (no ticket file)", rc);
1095 if (rc != KSUCCESS) {
1096 _reportf(L"Trying to find %S@%S", ServiceName, RealmName);
1097 rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
1100 if (rc != KSUCCESS) {
1101 _reportf(L"Trying to obtain new ticket");
1102 if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1103 CellName, RealmName, 0))
1105 if ((rc = (*pkrb_get_cred)(ServiceName, CellName,
1106 RealmName, &creds)) != KSUCCESS) {
1109 _reportf(L"Got %S.%S@%S", ServiceName, CellName, RealmName);
1111 } else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1114 if ((rc = (*pkrb_get_cred)(ServiceName, "",
1115 RealmName, &creds)) != KSUCCESS) {
1118 _reportf(L"Got %S@%S", ServiceName, RealmName);
1133 memset(&aserver, '\0', sizeof(aserver));
1134 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1135 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1137 memset(&atoken, '\0', sizeof(atoken));
1138 atoken.kvno = (short)creds.kvno;
1139 atoken.startTime = creds.issue_date;
1140 atoken.endTime = (*pkrb_life_to_time)(creds.issue_date,creds.lifetime);
1141 memcpy(&atoken.sessionKey, creds.session, 8);
1142 atoken.ticketLen = creds.ticket_st.length;
1143 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
1146 *tok_expiration = atoken.endTime;
1148 if (!(rc = ktc_GetToken(&aserver, &btoken,
1149 sizeof(btoken), &aclient)) &&
1150 atoken.kvno == btoken.kvno &&
1151 atoken.ticketLen == btoken.ticketLen &&
1152 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1153 sizeof(atoken.sessionKey)) &&
1154 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1160 // Reset the "aclient" structure before we call ktc_SetToken.
1161 // This structure was first set by the ktc_GetToken call when
1162 // we were comparing whether identical tokens already existed.
1164 StringCchCopyA(aclient.name, MAXKTCNAMELEN, creds.pname);
1165 if (creds.pinst[0]) {
1166 StringCchCatA(aclient.name, MAXKTCNAMELEN, ".");
1167 StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.pinst);
1170 StringCbCopyA(aclient.instance, sizeof(aclient.instance), "");
1172 StringCchCatA(aclient.name, MAXKTCNAMELEN, "@");
1173 StringCchCatA(aclient.name, MAXKTCNAMELEN, got524cred ? realm_of_user : creds.realm);
1175 StringCbCopyA(aclient.cell, sizeof(aclient.cell), CellName);
1177 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1178 &aclient, &aserver, &atoken);
1180 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
1181 afs_report_error(rc, "ktc_SetToken()");
1184 } else if (method == AFS_TOKEN_AUTO ||
1185 method >= AFS_TOKEN_USER) {
1186 /* we couldn't get a token using Krb5, Krb524 or Krb4, either
1187 because we couldn't get the necessary credentials or
1188 because the method was set to not use those. Now we
1189 dispatch to any extensions to see if they have better
1192 rc = !afs_ext_klog(method,
1200 /* if the return code was not set, we should set it now.
1201 Otherwise we let the code go through. */
1203 /* No tokens were obtained. We should report something */
1204 _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
1208 rc = KHM_ERROR_GENERAL;
1215 /**************************************/
1216 /* afs_realm_of_cell(): */
1217 /**************************************/
1219 afs_realm_of_cell(afs_conf_cell *cellconfig, BOOL referral_fallback)
1221 char krbhst[MAX_HSTNM]="";
1222 static char krbrlm[REALM_SZ+1]="";
1223 krb5_context ctx = 0;
1224 char ** realmlist=NULL;
1225 krb5_error_code r = 0;
1230 if (referral_fallback) {
1232 p = strchr(cellconfig->hostName[0], '.');
1234 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1236 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1237 #if _MSC_VER >= 1400
1238 _strupr_s(krbrlm, sizeof(krbrlm));
1243 if ( pkrb5_init_context ) {
1244 r = pkrb5_init_context(&ctx);
1246 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
1247 if ( !r && realmlist && realmlist[0] ) {
1248 StringCbCopyA(krbrlm, sizeof(krbrlm), realmlist[0]);
1249 pkrb5_free_host_realm(ctx, realmlist);
1252 pkrb5_free_context(ctx);
1256 if (pkrb_get_krbhst && pkrb_realmofhost) {
1257 StringCbCopyA(krbrlm, sizeof(krbrlm),
1258 (char *)(*pkrb_realmofhost)(cellconfig->hostName[0]));
1259 if ((*pkrb_get_krbhst)(krbhst, krbrlm, 1) != KSUCCESS)
1265 p = strchr(cellconfig->hostName[0], '.');
1267 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1269 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1270 #if _MSC_VER >= 1400
1271 _strupr_s(krbrlm, sizeof(krbrlm));
1281 /**************************************/
1282 /* afs_get_cellconfig(): */
1283 /**************************************/
1285 afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
1290 local_cell[0] = (char)0;
1291 memset(cellconfig, 0, sizeof(*cellconfig));
1293 cellconfig->cbsize = sizeof(*cellconfig);
1295 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
1296 if (rc = cm_GetRootCellName(local_cell)) {
1300 if (strlen(cell) == 0)
1301 StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
1303 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
1304 StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
1306 rc = cm_SearchCellFile(cell, NULL, afs_get_cellconfig_callback,
1309 rc = cm_SearchCellByDNS(cell, NULL, &ttl,
1310 afs_get_cellconfig_callback,
1311 (void*) cellconfig);
1316 /**************************************/
1317 /* afs_get_cellconfig_callback(): */
1318 /**************************************/
1320 afs_get_cellconfig_callback(void *cellconfig,
1321 struct sockaddr_in *addrp,
1324 afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
1326 cc->hostAddr[cc->numServers] = *addrp;
1327 StringCbCopyA(cc->hostName[cc->numServers],
1328 sizeof(cc->hostName[0]), namep);
1334 /**************************************/
1335 /* afs_report_error(): */
1336 /**************************************/
1338 afs_report_error(LONG rc, LPCSTR FailedFunctionName)
1341 const char *errText;
1343 // Using AFS defines as error messages for now, until Transarc
1344 // gets back to me with "string" translations of each of these
1346 if (rc == KTC_ERROR)
1347 errText = "KTC_ERROR";
1348 else if (rc == KTC_TOOBIG)
1349 errText = "KTC_TOOBIG";
1350 else if (rc == KTC_INVAL)
1351 errText = "KTC_INVAL";
1352 else if (rc == KTC_NOENT)
1353 errText = "KTC_NOENT";
1354 else if (rc == KTC_PIOCTLFAIL)
1355 errText = "KTC_PIOCTLFAIL";
1356 else if (rc == KTC_NOPIOCTL)
1357 errText = "KTC_NOPIOCTL";
1358 else if (rc == KTC_NOCELL)
1359 errText = "KTC_NOCELL";
1360 else if (rc == KTC_NOCM)
1361 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
1363 errText = "Unknown error!";
1365 StringCbPrintfA(message, sizeof(message),
1366 "%s\n(%s failed)", errText, FailedFunctionName);
1367 _report_cs1(KHERR_ERROR, L"%1!S!", _cptr(message));
1373 GetServiceStatus(LPSTR lpszMachineName,
1374 LPSTR lpszServiceName,
1375 DWORD *lpdwCurrentState,
1376 DWORD *lpdwWaitHint)
1379 SC_HANDLE schSCManager = NULL;
1380 SC_HANDLE schService = NULL;
1381 DWORD fdwDesiredAccess = 0;
1382 SERVICE_STATUS ssServiceStatus = {0};
1385 *lpdwCurrentState = 0;
1387 fdwDesiredAccess = GENERIC_READ;
1389 schSCManager = OpenSCManagerA(lpszMachineName,
1393 if(schSCManager == NULL) {
1394 hr = GetLastError();
1398 schService = OpenServiceA(schSCManager,
1402 if(schService == NULL) {
1403 hr = GetLastError();
1407 fRet = QueryServiceStatus(schService,
1411 hr = GetLastError();
1415 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
1417 *lpdwWaitHint = ssServiceStatus.dwWaitHint;
1420 CloseServiceHandle(schService);
1421 CloseServiceHandle(schSCManager);
1426 DWORD ServiceControl(LPSTR lpszMachineName,
1427 LPSTR lpszServiceName,
1431 SC_HANDLE schSCManager = NULL;
1432 SC_HANDLE schService = NULL;
1433 DWORD fdwDesiredAccess = 0;
1434 SERVICE_STATUS ssServiceStatus = {0};
1436 DWORD dwCurrentState = 0;
1440 fdwDesiredAccess = GENERIC_READ;
1442 schSCManager = OpenSCManagerA(lpszMachineName, NULL,
1445 if(schSCManager == NULL) {
1446 hr = GetLastError();
1450 fdwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
1452 schService = OpenServiceA(schSCManager, lpszServiceName,
1455 if(schService == NULL) {
1456 hr = GetLastError();
1460 fRet = QueryServiceStatus(schService, &ssServiceStatus);
1463 hr = GetLastError();
1467 dwCurrentState = ssServiceStatus.dwCurrentState;
1469 if (dwCurrentState == SERVICE_STOPPED &&
1470 dwNewState == SERVICE_RUNNING) {
1472 fRet = StartService(schService, 0, NULL);
1474 if (fRet == FALSE) {
1475 hr = GetLastError();
1480 if (dwCurrentState == SERVICE_RUNNING &&
1481 dwNewState == SERVICE_STOPPED) {
1482 fRet = ControlService(schService, SERVICE_CONTROL_STOP,
1485 if (fRet == FALSE) {
1486 hr = GetLastError();
1493 CloseServiceHandle(schService);
1494 CloseServiceHandle(schSCManager);
1500 afs_check_for_cell_realm_match(khm_handle identity, char * cell) {
1501 char local_cell[MAXCELLCHARS];
1502 wchar_t wrealm[MAXCELLCHARS];
1503 wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
1507 afs_conf_cell cellconfig;
1510 ZeroMemory(local_cell, sizeof(local_cell));
1512 rc = afs_get_cellconfig(cell, &cellconfig, local_cell);
1516 realm = afs_realm_of_cell(&cellconfig, FALSE);
1520 AnsiStrToUnicode(wrealm, sizeof(wrealm), realm);
1522 cb = sizeof(idname);
1524 kcdb_identity_get_name(identity, idname, &cb);
1526 atsign = wcschr(idname, L'@');
1527 if (atsign && atsign[1] && !_wcsicmp(atsign + 1, wrealm)) {