2 * Copyright (c) 2005,2006 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, KCDB_CBSIZE_AUTO);
599 kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION,
600 location, 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
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_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);
906 if ( k5creds->ticket.length > MAXKTCTICKETLEN ||
907 method == AFS_TOKEN_KRB524) {
911 /* This code inserts the entire K5 ticket into the token */
913 _reportf(L"Trying K5 SetToken");
915 memset(&aserver, '\0', sizeof(aserver));
916 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
917 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
919 memset(&atoken, '\0', sizeof(atoken));
920 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
921 atoken.startTime = k5creds->times.starttime;
922 atoken.endTime = k5creds->times.endtime;
923 memcpy(&atoken.sessionKey,
924 k5creds->keyblock.contents,
925 k5creds->keyblock.length);
926 atoken.ticketLen = k5creds->ticket.length;
927 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
930 *tok_expiration = k5creds->times.endtime;
933 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
934 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
935 if ( rc == KTC_NOCM && retry < 20 ) {
938 goto retry_gettoken5;
943 if (atoken.kvno == btoken.kvno &&
944 atoken.ticketLen == btoken.ticketLen &&
945 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
946 sizeof(atoken.sessionKey)) &&
947 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
950 if (k5creds && context)
951 pkrb5_free_creds(context, k5creds);
954 pkrb5_free_context(context);
956 _reportf(L"Same token already exists");
961 // * Reset the "aclient" structure before we call ktc_SetToken.
962 // * This structure was first set by the ktc_GetToken call when
963 // * we were comparing whether identical tokens already existed.
965 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
966 StringCchCopyNA(aclient.name, MAXKTCNAMELEN,
967 k5creds->client->data[0].data, len);
969 if ( k5creds->client->length > 1 ) {
970 StringCbCatA(aclient.name, sizeof(aclient.name), ".");
971 p = aclient.name + strlen(aclient.name);
972 len = (int) min(k5creds->client->data[1].length,
973 MAXKTCNAMELEN - strlen(aclient.name) - 1);
974 StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
975 k5creds->client->data[1].data, len);
978 aclient.instance[0] = '\0';
980 StringCbCopyA(aclient.cell, sizeof(aclient.cell), realm_of_cell);
982 StringCbCatA(aclient.name, sizeof(aclient.name), "@");
983 p = aclient.name + strlen(aclient.name);
984 len = (int) min(k5creds->client->realm.length,
985 MAXKTCNAMELEN - strlen(aclient.name) - 1);
986 StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
987 k5creds->client->realm.data, len);
989 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
990 &aclient, &aserver, &atoken);
992 rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
996 if (k5creds && context)
997 pkrb5_free_creds(context, k5creds);
1000 pkrb5_free_context(context);
1005 _reportf(L"SetToken returns code %d", rc);
1009 _reportf(L"Trying Krb524");
1011 if (method == AFS_TOKEN_AUTO ||
1012 method == AFS_TOKEN_KRB524) {
1013 /* This requires krb524d to be running with the KDC */
1014 r = pkrb524_convert_creds_kdc(context, k5creds, &creds);
1016 _reportf(L"Code %d while converting credentials", r);
1025 if (client_principal)
1026 pkrb5_free_principal(context, client_principal);
1028 if (k5creds && context)
1029 pkrb5_free_creds(context, k5creds);
1032 pkrb5_free_context(context);
1038 kcdb_identity_get_config(identity, 0, &confighandle);
1039 khc_read_int32(confighandle, L"Krb4Cred\\Krb4NewCreds", &supports_krb4);
1040 khc_close_space(confighandle);
1042 if (!supports_krb4) {
1043 _reportf(L"Kerberos 4 not configured");
1046 if (!bGotCreds && supports_krb4 &&
1047 (method == AFS_TOKEN_AUTO ||
1048 method == AFS_TOKEN_KRB4)) {
1052 _reportf(L"Trying Kerberos 4");
1054 if (!realm_of_user[0] ) {
1055 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user))
1057 /* can't determine realm of user */
1058 _reportf(L"krb_get_tf_realm returns %d", rc);
1063 _reportf(L"Trying to find %S.%S@%S", ServiceName, CellName, RealmName);
1064 rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
1065 if (rc == NO_TKT_FIL) {
1066 // if the problem is that we have no krb4 tickets
1067 // do not attempt to continue
1068 _reportf(L"krb_get_cred returns %d (no ticket file)", rc);
1072 if (rc != KSUCCESS) {
1073 _reportf(L"Trying to find %S@%S", ServiceName, RealmName);
1074 rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
1077 if (rc != KSUCCESS) {
1078 _reportf(L"Trying to obtain new ticket");
1079 if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1080 CellName, RealmName, 0))
1082 if ((rc = (*pkrb_get_cred)(ServiceName, CellName,
1083 RealmName, &creds)) != KSUCCESS) {
1086 _reportf(L"Got %S.%S@%S", ServiceName, CellName, RealmName);
1088 } else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1091 if ((rc = (*pkrb_get_cred)(ServiceName, "",
1092 RealmName, &creds)) != KSUCCESS) {
1095 _reportf(L"Got %S@%S", ServiceName, RealmName);
1110 memset(&aserver, '\0', sizeof(aserver));
1111 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1112 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1114 memset(&atoken, '\0', sizeof(atoken));
1115 atoken.kvno = creds.kvno;
1116 atoken.startTime = creds.issue_date;
1117 atoken.endTime = (*pkrb_life_to_time)(creds.issue_date,creds.lifetime);
1118 memcpy(&atoken.sessionKey, creds.session, 8);
1119 atoken.ticketLen = creds.ticket_st.length;
1120 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
1123 *tok_expiration = atoken.endTime;
1125 if (!(rc = ktc_GetToken(&aserver, &btoken,
1126 sizeof(btoken), &aclient)) &&
1127 atoken.kvno == btoken.kvno &&
1128 atoken.ticketLen == btoken.ticketLen &&
1129 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1130 sizeof(atoken.sessionKey)) &&
1131 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1137 // Reset the "aclient" structure before we call ktc_SetToken.
1138 // This structure was first set by the ktc_GetToken call when
1139 // we were comparing whether identical tokens already existed.
1141 StringCchCopyA(aclient.name, MAXKTCNAMELEN, creds.pname);
1142 if (creds.pinst[0]) {
1143 StringCchCatA(aclient.name, MAXKTCNAMELEN, ".");
1144 StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.pinst);
1147 StringCbCopyA(aclient.instance, sizeof(aclient.instance), "");
1149 StringCchCatA(aclient.name, MAXKTCNAMELEN, "@");
1150 StringCchCatA(aclient.name, MAXKTCNAMELEN, got524cred ? realm_of_user : creds.realm);
1152 StringCbCopyA(aclient.cell, sizeof(aclient.cell), CellName);
1154 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1155 &aclient, &aserver, &atoken);
1157 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
1158 afs_report_error(rc, "ktc_SetToken()");
1161 } else if (method == AFS_TOKEN_AUTO ||
1162 method >= AFS_TOKEN_USER) {
1163 /* we couldn't get a token using Krb5, Krb524 or Krb4, either
1164 because we couldn't get the necessary credentials or
1165 because the method was set to not use those. Now we
1166 dispatch to any extensions to see if they have better
1169 rc = !afs_ext_klog(method,
1177 /* if the return code was not set, we should set it now.
1178 Otherwise we let the code go through. */
1180 /* No tokens were obtained. We should report something */
1181 _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
1185 rc = KHM_ERROR_GENERAL;
1192 /**************************************/
1193 /* afs_realm_of_cell(): */
1194 /**************************************/
1196 afs_realm_of_cell(afs_conf_cell *cellconfig, BOOL referral_fallback)
1198 char krbhst[MAX_HSTNM]="";
1199 static char krbrlm[REALM_SZ+1]="";
1200 krb5_context ctx = 0;
1201 char ** realmlist=NULL;
1207 if (referral_fallback) {
1209 p = strchr(cellconfig->hostName[0], '.');
1211 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1213 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1216 if ( pkrb5_init_context ) {
1217 r = pkrb5_init_context(&ctx);
1219 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
1220 if ( !r && realmlist && realmlist[0] ) {
1221 StringCbCopyA(krbrlm, sizeof(krbrlm), realmlist[0]);
1222 pkrb5_free_host_realm(ctx, realmlist);
1225 pkrb5_free_context(ctx);
1229 if (pkrb_get_krbhst && pkrb_realmofhost) {
1230 StringCbCopyA(krbrlm, sizeof(krbrlm),
1231 (char *)(*pkrb_realmofhost)(cellconfig->hostName[0]));
1232 if ((*pkrb_get_krbhst)(krbhst, krbrlm, 1) != KSUCCESS)
1238 p = strchr(cellconfig->hostName[0], '.');
1240 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1242 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1250 /**************************************/
1251 /* afs_get_cellconfig(): */
1252 /**************************************/
1254 afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
1259 local_cell[0] = (char)0;
1260 memset(cellconfig, 0, sizeof(*cellconfig));
1262 cellconfig->cbsize = sizeof(*cellconfig);
1264 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
1265 if (rc = cm_GetRootCellName(local_cell)) {
1269 if (strlen(cell) == 0)
1270 StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
1272 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
1273 StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
1275 rc = cm_SearchCellFile(cell, NULL, afs_get_cellconfig_callback,
1278 rc = cm_SearchCellByDNS(cell, NULL, &ttl,
1279 afs_get_cellconfig_callback,
1280 (void*) cellconfig);
1285 /**************************************/
1286 /* afs_get_cellconfig_callback(): */
1287 /**************************************/
1289 afs_get_cellconfig_callback(void *cellconfig,
1290 struct sockaddr_in *addrp,
1293 afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
1295 cc->hostAddr[cc->numServers] = *addrp;
1296 StringCbCopyA(cc->hostName[cc->numServers],
1297 sizeof(cc->hostName[0]), namep);
1303 /**************************************/
1304 /* afs_report_error(): */
1305 /**************************************/
1307 afs_report_error(LONG rc, LPCSTR FailedFunctionName)
1310 const char *errText;
1312 // Using AFS defines as error messages for now, until Transarc
1313 // gets back to me with "string" translations of each of these
1315 if (rc == KTC_ERROR)
1316 errText = "KTC_ERROR";
1317 else if (rc == KTC_TOOBIG)
1318 errText = "KTC_TOOBIG";
1319 else if (rc == KTC_INVAL)
1320 errText = "KTC_INVAL";
1321 else if (rc == KTC_NOENT)
1322 errText = "KTC_NOENT";
1323 else if (rc == KTC_PIOCTLFAIL)
1324 errText = "KTC_PIOCTLFAIL";
1325 else if (rc == KTC_NOPIOCTL)
1326 errText = "KTC_NOPIOCTL";
1327 else if (rc == KTC_NOCELL)
1328 errText = "KTC_NOCELL";
1329 else if (rc == KTC_NOCM)
1330 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
1332 errText = "Unknown error!";
1334 StringCbPrintfA(message, sizeof(message),
1335 "%s\n(%s failed)", errText, FailedFunctionName);
1336 _report_cs1(KHERR_ERROR, L"%1!S!", _cptr(message));
1342 GetServiceStatus(LPSTR lpszMachineName,
1343 LPSTR lpszServiceName,
1344 DWORD *lpdwCurrentState,
1345 DWORD *lpdwWaitHint)
1348 SC_HANDLE schSCManager = NULL;
1349 SC_HANDLE schService = NULL;
1350 DWORD fdwDesiredAccess = 0;
1351 SERVICE_STATUS ssServiceStatus = {0};
1354 *lpdwCurrentState = 0;
1356 fdwDesiredAccess = GENERIC_READ;
1358 schSCManager = OpenSCManagerA(lpszMachineName,
1362 if(schSCManager == NULL) {
1363 hr = GetLastError();
1367 schService = OpenServiceA(schSCManager,
1371 if(schService == NULL) {
1372 hr = GetLastError();
1376 fRet = QueryServiceStatus(schService,
1380 hr = GetLastError();
1384 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
1386 *lpdwWaitHint = ssServiceStatus.dwWaitHint;
1389 CloseServiceHandle(schService);
1390 CloseServiceHandle(schSCManager);
1395 DWORD ServiceControl(LPSTR lpszMachineName,
1396 LPSTR lpszServiceName,
1400 SC_HANDLE schSCManager = NULL;
1401 SC_HANDLE schService = NULL;
1402 DWORD fdwDesiredAccess = 0;
1403 SERVICE_STATUS ssServiceStatus = {0};
1405 DWORD dwCurrentState = 0;
1409 fdwDesiredAccess = GENERIC_READ;
1411 schSCManager = OpenSCManagerA(lpszMachineName, NULL,
1414 if(schSCManager == NULL) {
1415 hr = GetLastError();
1419 fdwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
1421 schService = OpenServiceA(schSCManager, lpszServiceName,
1424 if(schService == NULL) {
1425 hr = GetLastError();
1429 fRet = QueryServiceStatus(schService, &ssServiceStatus);
1432 hr = GetLastError();
1436 dwCurrentState = ssServiceStatus.dwCurrentState;
1438 if (dwCurrentState == SERVICE_STOPPED &&
1439 dwNewState == SERVICE_RUNNING) {
1441 fRet = StartService(schService, 0, NULL);
1443 if (fRet == FALSE) {
1444 hr = GetLastError();
1449 if (dwCurrentState == SERVICE_RUNNING &&
1450 dwNewState == SERVICE_STOPPED) {
1451 fRet = ControlService(schService, SERVICE_CONTROL_STOP,
1454 if (fRet == FALSE) {
1455 hr = GetLastError();
1462 CloseServiceHandle(schService);
1463 CloseServiceHandle(schSCManager);
1469 afs_check_for_cell_realm_match(khm_handle identity, char * cell) {
1470 char local_cell[MAXCELLCHARS];
1471 wchar_t wrealm[MAXCELLCHARS];
1472 wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
1476 afs_conf_cell cellconfig;
1479 ZeroMemory(local_cell, sizeof(local_cell));
1481 rc = afs_get_cellconfig(cell, &cellconfig, local_cell);
1485 realm = afs_realm_of_cell(&cellconfig, FALSE);
1489 AnsiStrToUnicode(wrealm, sizeof(wrealm), realm);
1491 cb = sizeof(idname);
1493 kcdb_identity_get_name(identity, idname, &cb);
1495 atsign = wcschr(idname, L'@');
1496 if (atsign && atsign[1] && !wcsicmp(atsign + 1, wrealm)) {