2 * Copyright (c) 2005,2006,2007 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 afs_klog(khm_handle identity,
712 afs_tk_method method,
713 time_t * tok_expiration) {
717 struct ktc_principal aserver;
718 struct ktc_principal aclient;
719 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
720 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
721 char local_cell[MAXCELLCHARS+1];
722 char Dmycell[MAXCELLCHARS+1];
723 struct ktc_token atoken;
724 struct ktc_token btoken;
725 afs_conf_cell ak_cellconfig; /* General information about the cell */
728 char ServiceName[128];
729 khm_handle confighandle = NULL;
730 khm_int32 supports_krb4 = 1;
731 khm_int32 got524cred = 0;
734 BOOL bGotCreds = FALSE; /* got creds? */
737 *tok_expiration = (time_t) 0;
739 if (!afs_is_running()) {
740 _report_sr0(KHERR_WARNING, IDS_ERR_NOSERVICE);
744 if ( !realm ) realm = "";
745 if ( !cell ) cell = "";
746 if ( !service ) service = "";
748 memset(RealmName, '\0', sizeof(RealmName));
749 memset(CellName, '\0', sizeof(CellName));
750 memset(ServiceName, '\0', sizeof(ServiceName));
751 memset(realm_of_user, '\0', sizeof(realm_of_user));
752 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
753 memset(Dmycell, '\0', sizeof(Dmycell));
755 // NULL or empty cell returns information on local cell
757 StringCbCopyA(Dmycell, sizeof(Dmycell), cell);
759 rc = afs_get_cellconfig(Dmycell, &ak_cellconfig, local_cell);
761 _reportf(L"afs_get_cellconfig returns %ld", rc);
763 _report_sr2(KHERR_ERROR, IDS_ERR_CELLCONFIG, _cstr(Dmycell), _int32(rc));
764 _suggest_sr(IDS_ERR_CELLCONFIG_S, KHERR_SUGGEST_NONE);
769 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
770 afs_realm_of_cell(&ak_cellconfig, FALSE));
772 if (strlen(service) == 0)
773 StringCbCopyA(ServiceName, sizeof(ServiceName), "afs");
775 StringCbCopyA(ServiceName, sizeof(ServiceName), service);
777 if (strlen(cell) == 0)
778 StringCbCopyA(CellName, sizeof(CellName), local_cell);
780 StringCbCopyA(CellName, sizeof(CellName), cell);
782 if (strlen(realm) == 0)
783 StringCbCopyA(RealmName, sizeof(RealmName), realm_of_cell);
785 StringCbCopyA(RealmName, sizeof(RealmName), realm);
787 memset(&creds, '\0', sizeof(creds));
789 /*** Kerberos 5 and 524 ***/
791 if (method == AFS_TOKEN_AUTO ||
792 method == AFS_TOKEN_KRB5 ||
793 method == AFS_TOKEN_KRB524) {
795 krb5_context context = 0;
796 krb5_ccache k5cc = 0;
798 krb5_creds * k5creds = 0;
800 krb5_principal client_principal = 0;
801 krb5_flags flags = 0;
807 _reportf(L"Trying Kerberos 5");
809 if (!(r = khm_krb5_initialize(identity, &context, &k5cc))) {
812 memset((char *)&increds, 0, sizeof(increds));
814 pkrb5_cc_get_principal(context, k5cc, &client_principal);
815 i = krb5_princ_realm(context, client_principal)->length;
818 StringCchCopyNA(realm_of_user, ARRAYLENGTH(realm_of_user),
819 krb5_princ_realm(context, client_principal)->data,
822 _reportf(L"khm_krb5_initialize returns code %d", r);
826 /* First try Service/Cell@REALM */
827 if (r = pkrb5_build_principal(context, &increds.server,
828 (int) strlen(RealmName),
833 _reportf(L"krb5_build_principal returns %d", r);
837 increds.client = client_principal;
838 increds.times.endtime = 0;
839 /* Ask for DES since that is what V4 understands */
840 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
842 #ifdef KRB5_TC_NOTICKET
843 flags = KRB5_TC_OPENCLOSE;
844 r = pkrb5_cc_set_flags(context, k5cc, flags);
847 r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
848 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
849 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
851 StringCbCopyA(RealmName, sizeof(RealmName),
852 afs_realm_of_cell(&ak_cellconfig, TRUE));
854 pkrb5_free_principal(context, increds.server);
855 r = pkrb5_build_principal(context, &increds.server,
856 (int) strlen(RealmName),
862 r = pkrb5_get_credentials(context, 0, k5cc,
865 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
866 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
867 /* Next try Service@REALM */
868 pkrb5_free_principal(context, increds.server);
869 r = pkrb5_build_principal(context, &increds.server,
870 (int) strlen(RealmName),
875 r = pkrb5_get_credentials(context, 0, k5cc,
879 /* Check to make sure we received a valid ticket; if not remove it
880 * and try again. Perhaps there are two service tickets for the
881 * same service in the ccache.
883 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
884 pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
885 pkrb5_free_creds(context, k5creds);
890 pkrb5_free_principal(context, increds.server);
891 pkrb5_free_principal(context, client_principal);
892 client_principal = 0;
893 #ifdef KRB5_TC_NOTICKET
894 flags = KRB5_TC_OPENCLOSE | KRB5_TC_NOTICKET;
895 pkrb5_cc_set_flags(context, k5cc, flags);
898 (void) pkrb5_cc_close(context, k5cc);
902 _reportf(L"Code %d while getting credentials", r);
907 if ( k5creds->ticket.length > MAXKTCTICKETLEN ||
908 method == AFS_TOKEN_KRB524) {
912 /* This code inserts the entire K5 ticket into the token */
914 _reportf(L"Trying K5 SetToken");
916 memset(&aserver, '\0', sizeof(aserver));
917 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
918 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
920 memset(&atoken, '\0', sizeof(atoken));
921 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
922 atoken.startTime = k5creds->times.starttime;
923 atoken.endTime = k5creds->times.endtime;
924 memcpy(&atoken.sessionKey,
925 k5creds->keyblock.contents,
926 k5creds->keyblock.length);
927 atoken.ticketLen = k5creds->ticket.length;
928 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
931 *tok_expiration = k5creds->times.endtime;
934 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
935 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
936 if ( rc == KTC_NOCM && retry < 20 ) {
939 goto retry_gettoken5;
944 if (atoken.kvno == btoken.kvno &&
945 atoken.ticketLen == btoken.ticketLen &&
946 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
947 sizeof(atoken.sessionKey)) &&
948 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
951 if (k5creds && context)
952 pkrb5_free_creds(context, k5creds);
955 pkrb5_free_context(context);
957 _reportf(L"Same token already exists");
962 // * Reset the "aclient" structure before we call ktc_SetToken.
963 // * This structure was first set by the ktc_GetToken call when
964 // * we were comparing whether identical tokens already existed.
966 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
967 StringCchCopyNA(aclient.name, MAXKTCNAMELEN,
968 k5creds->client->data[0].data, len);
970 if ( k5creds->client->length > 1 ) {
971 StringCbCatA(aclient.name, sizeof(aclient.name), ".");
972 p = aclient.name + strlen(aclient.name);
973 len = (int) min(k5creds->client->data[1].length,
974 MAXKTCNAMELEN - strlen(aclient.name) - 1);
975 StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
976 k5creds->client->data[1].data, len);
979 aclient.instance[0] = '\0';
981 StringCbCopyA(aclient.cell, sizeof(aclient.cell), realm_of_cell);
983 StringCbCatA(aclient.name, sizeof(aclient.name), "@");
984 p = aclient.name + strlen(aclient.name);
985 len = (int) min(k5creds->client->realm.length,
986 MAXKTCNAMELEN - strlen(aclient.name) - 1);
987 StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
988 k5creds->client->realm.data, len);
990 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
991 &aclient, &aserver, &atoken);
993 rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
997 if (k5creds && context)
998 pkrb5_free_creds(context, k5creds);
1001 pkrb5_free_context(context);
1006 _reportf(L"SetToken returns code %d", rc);
1010 _reportf(L"Trying Krb524");
1012 if (method == AFS_TOKEN_AUTO ||
1013 method == AFS_TOKEN_KRB524) {
1014 /* This requires krb524d to be running with the KDC */
1015 r = pkrb524_convert_creds_kdc(context, k5creds, &creds);
1017 _reportf(L"Code %d while converting credentials", r);
1026 if (client_principal)
1027 pkrb5_free_principal(context, client_principal);
1029 if (k5creds && context)
1030 pkrb5_free_creds(context, k5creds);
1033 pkrb5_free_context(context);
1039 kcdb_identity_get_config(identity, 0, &confighandle);
1040 khc_read_int32(confighandle, L"Krb4Cred\\Krb4NewCreds", &supports_krb4);
1041 khc_close_space(confighandle);
1043 if (!supports_krb4) {
1044 _reportf(L"Kerberos 4 not configured");
1047 if (!bGotCreds && supports_krb4 &&
1048 (method == AFS_TOKEN_AUTO ||
1049 method == AFS_TOKEN_KRB4)) {
1053 _reportf(L"Trying Kerberos 4");
1055 if (!realm_of_user[0] ) {
1056 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user))
1058 /* can't determine realm of user */
1059 _reportf(L"krb_get_tf_realm returns %d", rc);
1064 _reportf(L"Trying to find %S.%S@%S", ServiceName, CellName, RealmName);
1065 rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
1066 if (rc == NO_TKT_FIL) {
1067 // if the problem is that we have no krb4 tickets
1068 // do not attempt to continue
1069 _reportf(L"krb_get_cred returns %d (no ticket file)", rc);
1073 if (rc != KSUCCESS) {
1074 _reportf(L"Trying to find %S@%S", ServiceName, RealmName);
1075 rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
1078 if (rc != KSUCCESS) {
1079 _reportf(L"Trying to obtain new ticket");
1080 if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1081 CellName, RealmName, 0))
1083 if ((rc = (*pkrb_get_cred)(ServiceName, CellName,
1084 RealmName, &creds)) != KSUCCESS) {
1087 _reportf(L"Got %S.%S@%S", ServiceName, CellName, RealmName);
1089 } else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1092 if ((rc = (*pkrb_get_cred)(ServiceName, "",
1093 RealmName, &creds)) != KSUCCESS) {
1096 _reportf(L"Got %S@%S", ServiceName, RealmName);
1111 memset(&aserver, '\0', sizeof(aserver));
1112 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1113 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1115 memset(&atoken, '\0', sizeof(atoken));
1116 atoken.kvno = (short)creds.kvno;
1117 atoken.startTime = creds.issue_date;
1118 atoken.endTime = (*pkrb_life_to_time)(creds.issue_date,creds.lifetime);
1119 memcpy(&atoken.sessionKey, creds.session, 8);
1120 atoken.ticketLen = creds.ticket_st.length;
1121 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
1124 *tok_expiration = atoken.endTime;
1126 if (!(rc = ktc_GetToken(&aserver, &btoken,
1127 sizeof(btoken), &aclient)) &&
1128 atoken.kvno == btoken.kvno &&
1129 atoken.ticketLen == btoken.ticketLen &&
1130 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1131 sizeof(atoken.sessionKey)) &&
1132 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1138 // Reset the "aclient" structure before we call ktc_SetToken.
1139 // This structure was first set by the ktc_GetToken call when
1140 // we were comparing whether identical tokens already existed.
1142 StringCchCopyA(aclient.name, MAXKTCNAMELEN, creds.pname);
1143 if (creds.pinst[0]) {
1144 StringCchCatA(aclient.name, MAXKTCNAMELEN, ".");
1145 StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.pinst);
1148 StringCbCopyA(aclient.instance, sizeof(aclient.instance), "");
1150 StringCchCatA(aclient.name, MAXKTCNAMELEN, "@");
1151 StringCchCatA(aclient.name, MAXKTCNAMELEN, got524cred ? realm_of_user : creds.realm);
1153 StringCbCopyA(aclient.cell, sizeof(aclient.cell), CellName);
1155 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1156 &aclient, &aserver, &atoken);
1158 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
1159 afs_report_error(rc, "ktc_SetToken()");
1162 } else if (method == AFS_TOKEN_AUTO ||
1163 method >= AFS_TOKEN_USER) {
1164 /* we couldn't get a token using Krb5, Krb524 or Krb4, either
1165 because we couldn't get the necessary credentials or
1166 because the method was set to not use those. Now we
1167 dispatch to any extensions to see if they have better
1170 rc = !afs_ext_klog(method,
1178 /* if the return code was not set, we should set it now.
1179 Otherwise we let the code go through. */
1181 /* No tokens were obtained. We should report something */
1182 _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
1186 rc = KHM_ERROR_GENERAL;
1193 /**************************************/
1194 /* afs_realm_of_cell(): */
1195 /**************************************/
1197 afs_realm_of_cell(afs_conf_cell *cellconfig, BOOL referral_fallback)
1199 char krbhst[MAX_HSTNM]="";
1200 static char krbrlm[REALM_SZ+1]="";
1201 krb5_context ctx = 0;
1202 char ** realmlist=NULL;
1203 krb5_error_code r = 0;
1208 if (referral_fallback) {
1210 p = strchr(cellconfig->hostName[0], '.');
1212 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1214 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1215 #if _MSC_VER >= 1400
1216 _strupr_s(krbrlm, sizeof(krbrlm));
1221 if ( pkrb5_init_context ) {
1222 r = pkrb5_init_context(&ctx);
1224 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
1225 if ( !r && realmlist && realmlist[0] ) {
1226 StringCbCopyA(krbrlm, sizeof(krbrlm), realmlist[0]);
1227 pkrb5_free_host_realm(ctx, realmlist);
1230 pkrb5_free_context(ctx);
1234 if (pkrb_get_krbhst && pkrb_realmofhost) {
1235 StringCbCopyA(krbrlm, sizeof(krbrlm),
1236 (char *)(*pkrb_realmofhost)(cellconfig->hostName[0]));
1237 if ((*pkrb_get_krbhst)(krbhst, krbrlm, 1) != KSUCCESS)
1243 p = strchr(cellconfig->hostName[0], '.');
1245 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1247 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1248 #if _MSC_VER >= 1400
1249 _strupr_s(krbrlm, sizeof(krbrlm));
1259 /**************************************/
1260 /* afs_get_cellconfig(): */
1261 /**************************************/
1263 afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
1268 local_cell[0] = (char)0;
1269 memset(cellconfig, 0, sizeof(*cellconfig));
1271 cellconfig->cbsize = sizeof(*cellconfig);
1273 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
1274 if (rc = cm_GetRootCellName(local_cell)) {
1278 if (strlen(cell) == 0)
1279 StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
1281 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
1282 StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
1284 rc = cm_SearchCellFile(cell, NULL, afs_get_cellconfig_callback,
1287 rc = cm_SearchCellByDNS(cell, NULL, &ttl,
1288 afs_get_cellconfig_callback,
1289 (void*) cellconfig);
1294 /**************************************/
1295 /* afs_get_cellconfig_callback(): */
1296 /**************************************/
1298 afs_get_cellconfig_callback(void *cellconfig,
1299 struct sockaddr_in *addrp,
1302 afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
1304 cc->hostAddr[cc->numServers] = *addrp;
1305 StringCbCopyA(cc->hostName[cc->numServers],
1306 sizeof(cc->hostName[0]), namep);
1312 /**************************************/
1313 /* afs_report_error(): */
1314 /**************************************/
1316 afs_report_error(LONG rc, LPCSTR FailedFunctionName)
1319 const char *errText;
1321 // Using AFS defines as error messages for now, until Transarc
1322 // gets back to me with "string" translations of each of these
1324 if (rc == KTC_ERROR)
1325 errText = "KTC_ERROR";
1326 else if (rc == KTC_TOOBIG)
1327 errText = "KTC_TOOBIG";
1328 else if (rc == KTC_INVAL)
1329 errText = "KTC_INVAL";
1330 else if (rc == KTC_NOENT)
1331 errText = "KTC_NOENT";
1332 else if (rc == KTC_PIOCTLFAIL)
1333 errText = "KTC_PIOCTLFAIL";
1334 else if (rc == KTC_NOPIOCTL)
1335 errText = "KTC_NOPIOCTL";
1336 else if (rc == KTC_NOCELL)
1337 errText = "KTC_NOCELL";
1338 else if (rc == KTC_NOCM)
1339 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
1341 errText = "Unknown error!";
1343 StringCbPrintfA(message, sizeof(message),
1344 "%s\n(%s failed)", errText, FailedFunctionName);
1345 _report_cs1(KHERR_ERROR, L"%1!S!", _cptr(message));
1351 GetServiceStatus(LPSTR lpszMachineName,
1352 LPSTR lpszServiceName,
1353 DWORD *lpdwCurrentState,
1354 DWORD *lpdwWaitHint)
1357 SC_HANDLE schSCManager = NULL;
1358 SC_HANDLE schService = NULL;
1359 DWORD fdwDesiredAccess = 0;
1360 SERVICE_STATUS ssServiceStatus = {0};
1363 *lpdwCurrentState = 0;
1365 fdwDesiredAccess = GENERIC_READ;
1367 schSCManager = OpenSCManagerA(lpszMachineName,
1371 if(schSCManager == NULL) {
1372 hr = GetLastError();
1376 schService = OpenServiceA(schSCManager,
1380 if(schService == NULL) {
1381 hr = GetLastError();
1385 fRet = QueryServiceStatus(schService,
1389 hr = GetLastError();
1393 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
1395 *lpdwWaitHint = ssServiceStatus.dwWaitHint;
1398 CloseServiceHandle(schService);
1399 CloseServiceHandle(schSCManager);
1404 DWORD ServiceControl(LPSTR lpszMachineName,
1405 LPSTR lpszServiceName,
1409 SC_HANDLE schSCManager = NULL;
1410 SC_HANDLE schService = NULL;
1411 DWORD fdwDesiredAccess = 0;
1412 SERVICE_STATUS ssServiceStatus = {0};
1414 DWORD dwCurrentState = 0;
1418 fdwDesiredAccess = GENERIC_READ;
1420 schSCManager = OpenSCManagerA(lpszMachineName, NULL,
1423 if(schSCManager == NULL) {
1424 hr = GetLastError();
1428 fdwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
1430 schService = OpenServiceA(schSCManager, lpszServiceName,
1433 if(schService == NULL) {
1434 hr = GetLastError();
1438 fRet = QueryServiceStatus(schService, &ssServiceStatus);
1441 hr = GetLastError();
1445 dwCurrentState = ssServiceStatus.dwCurrentState;
1447 if (dwCurrentState == SERVICE_STOPPED &&
1448 dwNewState == SERVICE_RUNNING) {
1450 fRet = StartService(schService, 0, NULL);
1452 if (fRet == FALSE) {
1453 hr = GetLastError();
1458 if (dwCurrentState == SERVICE_RUNNING &&
1459 dwNewState == SERVICE_STOPPED) {
1460 fRet = ControlService(schService, SERVICE_CONTROL_STOP,
1463 if (fRet == FALSE) {
1464 hr = GetLastError();
1471 CloseServiceHandle(schService);
1472 CloseServiceHandle(schSCManager);
1478 afs_check_for_cell_realm_match(khm_handle identity, char * cell) {
1479 char local_cell[MAXCELLCHARS];
1480 wchar_t wrealm[MAXCELLCHARS];
1481 wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
1485 afs_conf_cell cellconfig;
1488 ZeroMemory(local_cell, sizeof(local_cell));
1490 rc = afs_get_cellconfig(cell, &cellconfig, local_cell);
1494 realm = afs_realm_of_cell(&cellconfig, FALSE);
1498 AnsiStrToUnicode(wrealm, sizeof(wrealm), realm);
1500 cb = sizeof(idname);
1502 kcdb_identity_get_name(identity, idname, &cb);
1504 atsign = wcschr(idname, L'@');
1505 if (atsign && atsign[1] && !_wcsicmp(atsign + 1, wrealm)) {