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 obatain 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 #ifdef AFS_ID_TO_NAME
634 char username_copy[BUFSIZ];
635 #endif /* AFS_ID_TO_NAME */
636 long viceId = ANONYMOUSID; /* AFS uid of user */
638 #ifdef ALLOW_REGISTER
640 #endif /* ALLOW_REGISTER */
642 if (confname[0] == '\0') {
643 StringCbCopyA(confname, sizeof(confname), AFSDIR_CLIENT_ETC_DIRPATH);
646 StringCbCopyA(lastcell, sizeof(lastcell), aserver->cell);
648 if (!pr_Initialize (0, confname, aserver->cell)) {
649 char sname[PR_MAXNAMELEN];
650 StringCbCopyA(sname, sizeof(sname), username);
651 status = pr_SNameToId (sname, &viceId);
656 * This is a crock, but it is Transarc's crock, so
657 * we have to play along in order to get the
658 * functionality. The way the afs id is stored is
659 * as a string in the username field of the token.
660 * Contrary to what you may think by looking at
661 * the code for tokens, this hack (AFS ID %d) will
662 * not work if you change %d to something else.
666 * This code is taken from cklog -- it lets people
667 * automatically register with the ptserver in foreign cells
670 #ifdef ALLOW_REGISTER
672 if (viceId != ANONYMOUSID) {
673 #else /* ALLOW_REGISTER */
674 if ((status == 0) && (viceId != ANONYMOUSID))
675 #endif /* ALLOW_REGISTER */
677 #ifdef AFS_ID_TO_NAME
678 StringCbCopyA(username_copy, BUFSIZ, username);
679 StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
680 #endif /* AFS_ID_TO_NAME */
682 #ifdef ALLOW_REGISTER
683 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
685 StringCbCopyA(aclient->name, sizeof(aclient->name), username);
686 StringCbCopyA(aclient->instance, sizeof(aclient->instance), "");
687 StringCbCopyA(aclient->cell, sizeof(aclient->cell), realm_of_user);
688 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
690 if (status = pr_Initialize(1L, confname, aserver->cell))
692 status = pr_CreateUser(username, &id);
696 #ifdef AFS_ID_TO_NAME
697 StringCbCopyA(username_copy, BUFSIZ, username);
698 StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
699 #endif /* AFS_ID_TO_NAME */
702 #endif /* ALLOW_REGISTER */
708 afs_klog(khm_handle identity,
713 afs_tk_method method,
714 time_t * tok_expiration) {
718 struct ktc_principal aserver;
719 struct ktc_principal aclient;
720 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
721 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
722 char local_cell[MAXCELLCHARS+1];
723 char Dmycell[MAXCELLCHARS+1];
724 struct ktc_token atoken;
725 struct ktc_token btoken;
726 afs_conf_cell ak_cellconfig; /* General information about the cell */
729 char ServiceName[128];
730 khm_handle confighandle;
731 khm_int32 supports_krb4 = 1;
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);
1024 if (client_principal)
1025 pkrb5_free_principal(context, client_principal);
1027 if (k5creds && context)
1028 pkrb5_free_creds(context, k5creds);
1031 pkrb5_free_context(context);
1037 kcdb_identity_get_config(identity, 0, &confighandle);
1038 khc_read_int32(confighandle, L"Krb4Cred\\Krb4NewCreds", &supports_krb4);
1039 khc_close_space(confighandle);
1041 if (!supports_krb4) {
1042 _reportf(L"Kerberos 4 not configured");
1045 if (!bGotCreds && supports_krb4 &&
1046 (method == AFS_TOKEN_AUTO ||
1047 method == AFS_TOKEN_KRB4)) {
1051 _reportf(L"Trying Kerberos 4");
1053 if (!realm_of_user[0] ) {
1054 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user))
1056 /* can't determine realm of user */
1057 _reportf(L"krb_get_tf_realm returns %d", rc);
1062 _reportf(L"Trying to find %S.%S@%S", ServiceName, CellName, RealmName);
1063 rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
1064 if (rc == NO_TKT_FIL) {
1065 // if the problem is that we have no krb4 tickets
1066 // do not attempt to continue
1067 _reportf(L"krb_get_cred returns %d (no ticket file)", rc);
1071 if (rc != KSUCCESS) {
1072 _reportf(L"Trying to find %S@%S", ServiceName, RealmName);
1073 rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
1076 if (rc != KSUCCESS) {
1077 _reportf(L"Trying to obtain new ticket");
1078 if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1079 CellName, RealmName, 0))
1081 if ((rc = (*pkrb_get_cred)(ServiceName, CellName,
1082 RealmName, &creds)) != KSUCCESS) {
1085 _reportf(L"Got %S.%S@%S", ServiceName, CellName, RealmName);
1087 } else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1090 if ((rc = (*pkrb_get_cred)(ServiceName, "",
1091 RealmName, &creds)) != KSUCCESS) {
1094 _reportf(L"Got %S@%S", ServiceName, RealmName);
1109 memset(&aserver, '\0', sizeof(aserver));
1110 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1111 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1113 memset(&atoken, '\0', sizeof(atoken));
1114 atoken.kvno = creds.kvno;
1115 atoken.startTime = creds.issue_date;
1116 atoken.endTime = (*pkrb_life_to_time)(creds.issue_date,creds.lifetime);
1117 memcpy(&atoken.sessionKey, creds.session, 8);
1118 atoken.ticketLen = creds.ticket_st.length;
1119 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
1122 *tok_expiration = atoken.endTime;
1124 if (!(rc = ktc_GetToken(&aserver, &btoken,
1125 sizeof(btoken), &aclient)) &&
1126 atoken.kvno == btoken.kvno &&
1127 atoken.ticketLen == btoken.ticketLen &&
1128 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1129 sizeof(atoken.sessionKey)) &&
1130 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1136 // Reset the "aclient" structure before we call ktc_SetToken.
1137 // This structure was first set by the ktc_GetToken call when
1138 // we were comparing whether identical tokens already existed.
1140 StringCchCopyA(aclient.name, MAXKTCNAMELEN, creds.pname);
1141 if (creds.pinst[0]) {
1142 StringCchCatA(aclient.name, MAXKTCNAMELEN, ".");
1143 StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.pinst);
1146 StringCbCopyA(aclient.instance, sizeof(aclient.instance), "");
1148 StringCchCatA(aclient.name, MAXKTCNAMELEN, "@");
1149 StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.realm);
1151 StringCbCopyA(aclient.cell, sizeof(aclient.cell), CellName);
1153 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1154 &aclient, &aserver, &atoken);
1156 // NOTE: On WIN32, the order of SetToken params changed...
1157 // to ktc_SetToken(&aserver, &aclient, &atoken, 0)
1158 // from ktc_SetToken(&aserver, &atoken, &aclient, 0) on
1159 // Unix... The afscompat ktc_SetToken provides the Unix order
1161 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
1162 afs_report_error(rc, "ktc_SetToken()");
1165 } else if (method == AFS_TOKEN_AUTO ||
1166 method >= AFS_TOKEN_USER) {
1167 /* we couldn't get a token using Krb5, Krb524 or Krb4, either
1168 because we couldn't get the necessary credentials or
1169 because the method was set to not use those. Now we
1170 dispatch to any extensions to see if they have better
1173 rc = !afs_ext_klog(method,
1181 /* if the return code was not set, we should set it now.
1182 Otherwise we let the code go through. */
1184 /* No tokens were obtained. We should report something */
1185 _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
1189 rc = KHM_ERROR_GENERAL;
1196 /**************************************/
1197 /* afs_realm_of_cell(): */
1198 /**************************************/
1200 afs_realm_of_cell(afs_conf_cell *cellconfig, BOOL referral_fallback)
1202 char krbhst[MAX_HSTNM]="";
1203 static char krbrlm[REALM_SZ+1]="";
1204 krb5_context ctx = 0;
1205 char ** realmlist=NULL;
1211 if (referral_fallback) {
1213 p = strchr(cellconfig->hostName[0], '.');
1215 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1217 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1220 if ( pkrb5_init_context ) {
1221 r = pkrb5_init_context(&ctx);
1223 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
1224 if ( !r && realmlist && realmlist[0] ) {
1225 StringCbCopyA(krbrlm, sizeof(krbrlm), realmlist[0]);
1226 pkrb5_free_host_realm(ctx, realmlist);
1229 pkrb5_free_context(ctx);
1233 if (pkrb_get_krbhst && pkrb_realmofhost) {
1234 StringCbCopyA(krbrlm, sizeof(krbrlm),
1235 (char *)(*pkrb_realmofhost)(cellconfig->hostName[0]));
1236 if ((*pkrb_get_krbhst)(krbhst, krbrlm, 1) != KSUCCESS)
1242 p = strchr(cellconfig->hostName[0], '.');
1244 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1246 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1254 /**************************************/
1255 /* afs_get_cellconfig(): */
1256 /**************************************/
1258 afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
1263 local_cell[0] = (char)0;
1264 memset(cellconfig, 0, sizeof(*cellconfig));
1266 cellconfig->cbsize = sizeof(*cellconfig);
1268 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
1269 if (rc = cm_GetRootCellName(local_cell)) {
1273 if (strlen(cell) == 0)
1274 StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
1276 /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
1277 StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
1279 rc = cm_SearchCellFile(cell, NULL, afs_get_cellconfig_callback,
1282 rc = cm_SearchCellByDNS(cell, NULL, &ttl,
1283 afs_get_cellconfig_callback,
1284 (void*) cellconfig);
1289 /**************************************/
1290 /* afs_get_cellconfig_callback(): */
1291 /**************************************/
1293 afs_get_cellconfig_callback(void *cellconfig,
1294 struct sockaddr_in *addrp,
1297 afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
1299 cc->hostAddr[cc->numServers] = *addrp;
1300 StringCbCopyA(cc->hostName[cc->numServers],
1301 sizeof(cc->hostName[0]), namep);
1307 /**************************************/
1308 /* afs_report_error(): */
1309 /**************************************/
1311 afs_report_error(LONG rc, LPCSTR FailedFunctionName)
1314 const char *errText;
1316 // Using AFS defines as error messages for now, until Transarc
1317 // gets back to me with "string" translations of each of these
1319 if (rc == KTC_ERROR)
1320 errText = "KTC_ERROR";
1321 else if (rc == KTC_TOOBIG)
1322 errText = "KTC_TOOBIG";
1323 else if (rc == KTC_INVAL)
1324 errText = "KTC_INVAL";
1325 else if (rc == KTC_NOENT)
1326 errText = "KTC_NOENT";
1327 else if (rc == KTC_PIOCTLFAIL)
1328 errText = "KTC_PIOCTLFAIL";
1329 else if (rc == KTC_NOPIOCTL)
1330 errText = "KTC_NOPIOCTL";
1331 else if (rc == KTC_NOCELL)
1332 errText = "KTC_NOCELL";
1333 else if (rc == KTC_NOCM)
1334 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
1336 errText = "Unknown error!";
1338 StringCbPrintfA(message, sizeof(message),
1339 "%s\n(%s failed)", errText, FailedFunctionName);
1340 _report_cs1(KHERR_ERROR, L"%1!S!", _cptr(message));
1346 GetServiceStatus(LPSTR lpszMachineName,
1347 LPSTR lpszServiceName,
1348 DWORD *lpdwCurrentState,
1349 DWORD *lpdwWaitHint)
1352 SC_HANDLE schSCManager = NULL;
1353 SC_HANDLE schService = NULL;
1354 DWORD fdwDesiredAccess = 0;
1355 SERVICE_STATUS ssServiceStatus = {0};
1358 *lpdwCurrentState = 0;
1360 fdwDesiredAccess = GENERIC_READ;
1362 schSCManager = OpenSCManagerA(lpszMachineName,
1366 if(schSCManager == NULL) {
1367 hr = GetLastError();
1371 schService = OpenServiceA(schSCManager,
1375 if(schService == NULL) {
1376 hr = GetLastError();
1380 fRet = QueryServiceStatus(schService,
1384 hr = GetLastError();
1388 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
1390 *lpdwWaitHint = ssServiceStatus.dwWaitHint;
1393 CloseServiceHandle(schService);
1394 CloseServiceHandle(schSCManager);
1399 DWORD ServiceControl(LPSTR lpszMachineName,
1400 LPSTR lpszServiceName,
1404 SC_HANDLE schSCManager = NULL;
1405 SC_HANDLE schService = NULL;
1406 DWORD fdwDesiredAccess = 0;
1407 SERVICE_STATUS ssServiceStatus = {0};
1409 DWORD dwCurrentState = 0;
1413 fdwDesiredAccess = GENERIC_READ;
1415 schSCManager = OpenSCManagerA(lpszMachineName, NULL,
1418 if(schSCManager == NULL) {
1419 hr = GetLastError();
1423 fdwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
1425 schService = OpenServiceA(schSCManager, lpszServiceName,
1428 if(schService == NULL) {
1429 hr = GetLastError();
1433 fRet = QueryServiceStatus(schService, &ssServiceStatus);
1436 hr = GetLastError();
1440 dwCurrentState = ssServiceStatus.dwCurrentState;
1442 if (dwCurrentState == SERVICE_STOPPED &&
1443 dwNewState == SERVICE_RUNNING) {
1445 fRet = StartService(schService, 0, NULL);
1447 if (fRet == FALSE) {
1448 hr = GetLastError();
1453 if (dwCurrentState == SERVICE_RUNNING &&
1454 dwNewState == SERVICE_STOPPED) {
1455 fRet = ControlService(schService, SERVICE_CONTROL_STOP,
1458 if (fRet == FALSE) {
1459 hr = GetLastError();
1466 CloseServiceHandle(schService);
1467 CloseServiceHandle(schSCManager);