2 * Copyright (c) 2005,2006,2007, 2008 Secure Endpoints Inc.
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 /* Disable the 'macro redefinition' warning which is getting
28 triggerred by a redefinition of the ENCRYPT and DECRYPT macros. */
29 #pragma warning (push)
30 #pragma warning (disable: 4005)
36 #include<krb5common.h>
40 static char *afs_realm_of_cell(afs_conf_cell *, BOOL);
41 static long afs_get_cellconfig_callback(void *, struct sockaddr_in *, char *, unsigned short ipRank);
42 static int afs_get_cellconfig(char *, afs_conf_cell *, char *);
45 afs_is_running(void) {
51 if (GetServiceStatus(NULL, TRANSARCAFSDAEMON,
52 &CurrentState, NULL) != NOERROR)
54 if (CurrentState != SERVICE_RUNNING)
65 if (!afs_is_running())
68 rc = ktc_ForgetAllTokens();
74 afs_unlog_cred(khm_handle cred)
77 struct ktc_principal princ;
79 wchar_t name[KCDB_MAXCCH_NAME];
81 if (!afs_is_running())
84 cbbuf = sizeof(princ);
85 if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_server_princ,
86 NULL, &princ, &cbbuf)))
89 afs_princ_to_string(&princ, name, sizeof(name));
91 _report_cs1(KHERR_INFO, L"Destroying token %1!s!",
95 rc = ktc_ForgetToken(&princ);
100 /* convert a ktc_principal to a wchar_t string form that looks like
101 name.instance@cell return 0 if it worked. non-zero otherwise
104 afs_princ_to_string(struct ktc_principal * p,
112 l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->name);
115 rv = FAILED(StringCbCopy(buf, cbbuf, wbuf));
117 StringCbCat(buf, cbbuf, L".");
118 if((l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->instance)) > 0) {
120 rv = rv || FAILED(StringCbCat(buf, cbbuf, wbuf));
126 rv = rv || FAILED(StringCbCat(buf, cbbuf, L"@"));
127 if((l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->cell)) > 0) {
129 rv = rv || FAILED(StringCbCat(buf, cbbuf, wbuf));
139 afs_list_tokens(void)
143 kcdb_credset_flush(afs_credset);
144 r = afs_list_tokens_internal();
145 kcdb_credset_collect(NULL, afs_credset, NULL, afs_credtype_id, NULL);
150 /* is the credential provided an AFS token and is it from the
152 static khm_int32 KHMAPI
153 afs_filter_by_cell(khm_handle cred, khm_int32 flags, void * rock)
155 wchar_t wcell[MAXCELLCHARS];
160 tcell = (wchar_t *) rock;
162 if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
163 type != afs_credtype_id)
166 cbsize = sizeof(wcell);
167 if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell,
168 NULL, wcell, &cbsize)))
171 if(wcscmp(wcell, tcell))
177 struct token_filter_data {
182 afs_filter_for_token(khm_handle cred, khm_int32 flags, void * rock) {
183 struct token_filter_data * pdata;
184 wchar_t ccell[MAXCELLCHARS];
188 pdata = (struct token_filter_data *) rock;
190 if (KHM_FAILED(kcdb_cred_get_type(cred, &ctype)) ||
191 ctype != afs_credtype_id)
197 if (KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell,
201 _wcsicmp(ccell, pdata->cell))
209 afs_find_token(khm_handle credset, wchar_t * cell) {
210 struct token_filter_data fdata;
211 khm_handle cred = NULL;
215 if (KHM_FAILED(kcdb_credset_find_filtered(credset,
217 afs_filter_for_token,
226 static khm_int32 KHMAPI
227 afs_filter_krb5_tkt(khm_handle cred, khm_int32 flags, void * rock)
229 wchar_t cname[KCDB_CRED_MAXCCH_NAME];
232 wchar_t * t, *tkt_cell;
235 tcell = (wchar_t *) rock;
237 if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
238 type != krb5_credtype_id)
241 cbsize = sizeof(cname);
242 if (KHM_FAILED(kcdb_cred_get_name(cred, cname, &cbsize)))
245 if (!wcsncmp(cname, L"afs/", 4)) {
247 tkt_cell = cname + 4;
249 t = wcschr(tkt_cell, L'@');
254 } else if (!wcsncmp(cname, L"afs@", 4)) {
256 tkt_cell = cname + 4;
262 if (_wcsicmp(tcell, tkt_cell))
268 static khm_int32 KHMAPI
269 afs_filter_krb4_tkt(khm_handle cred, khm_int32 flags, void * rock)
271 wchar_t cname[KCDB_CRED_MAXCCH_NAME];
274 wchar_t * t, *tkt_cell;
277 tcell = (wchar_t *) rock;
279 if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
280 type != krb4_credtype_id)
283 cbsize = sizeof(cname);
284 if (KHM_FAILED(kcdb_cred_get_name(cred, cname, &cbsize)))
287 if (!wcsncmp(cname, L"afs.", 4)) {
289 tkt_cell = cname + 4;
291 t = wcschr(tkt_cell, L'@');
296 } else if (!wcsncmp(cname, L"afs@", 4)) {
298 tkt_cell = cname + 4;
304 if (_wcsicmp(tcell, tkt_cell))
310 /* collects all AFS tokens to the root credential set using the
311 generic afs_credset credential set
314 afs_list_tokens_internal(void)
316 struct ktc_principal aserver;
317 struct ktc_principal aclient;
318 struct ktc_token atoken;
323 wchar_t location[256];
328 khm_handle ident = NULL;
329 khm_handle cred = NULL;
330 afs_tk_method method;
334 if (!afs_is_running())
337 kcdb_credset_flush(afs_credset);
339 LoadString(hResModule, IDS_DEF_LOCATION, location, ARRAYLENGTH(location));
345 memset(&aserver, 0, sizeof(aserver));
346 if (rc = ktc_ListTokens(cellNum, &cellNum, &aserver))
355 memset(&atoken, '\0', sizeof(atoken));
356 if (rc = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient))
365 /* failed attempt at trying to figure out the principal name from
366 the token. The ticket that is attached to the token is not
367 in a form that is useful at this point */
369 if(atoken.kvno == RXKAD_TKT_TYPE_KERBEROS_V5) {
370 krb5_context ctx = 0;
373 krb5_error_code code;
376 code = khm_krb5_initialize(&ctx, &cc);
380 k5c = (krb5_creds *) atoken.ticket;
382 code = pkrb5_unparse_name(ctx, k5c->client, &princ);
386 MultiByteToWideChar(CP_ACP, 0, princ, strlen(princ), idname, sizeof(idname)/sizeof(idname[0]));
388 pkrb5_free_unparsed_name(ctx, princ);
394 method = AFS_TOKEN_AUTO;
396 afs_princ_to_string(&aclient, idname, sizeof(idname));
398 /* We need to figure out a good client name which we can use
399 to create an identity which looks familiar to the user. No
400 good way of doing this, so we use a heuristic.
402 Note that, we use another heuristic to find out which
403 identity to associate the token with.
407 The assumption here is that the principal for the token is
410 if realm != cell : principal looks like user@realm@cell
411 if realm == cell : principal looks like user@realm
415 We strip the part of the string that follows the second '@'
416 sign to obtain the 'user@realm' part, which we use as the
417 credential name. If there is no second '@', we use the
418 whole principal name. */
422 ats = wcschr(idname, L'@');
423 if(ats && (ats = wcschr(ats + 1, L'@')))
427 afs_princ_to_string(&aserver, crname, sizeof(crname));
429 /* Ok, now we need to figure out which identity to associate
430 this token with. This is a little bit tricky, and there is
431 currently no good way of determining the original identity
432 used to obtain the token if it was done outside of
433 NetIDMgr. So we use a heuristic here.
437 Elsewhere, (actually in afsnewcreds.c) just after obtaining
438 AFS tokens through NetIDMgr, we enumerate the AFS tokens
439 and assign the root identity (used to obtain new creds)
440 with the AFS tokens. This would still be there in the root
441 credential set when we list tokens later on.
445 If there exists an AFS token in the root credential set for
446 the same cell, we associate this token with the same
447 identity as that credential.
449 cell = wcschr(crname, L'@');
460 if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
466 kcdb_cred_get_identity(c, &ident);
468 kcdb_cred_get_attr(c, afs_attr_method, NULL,
470 kcdb_cred_release(c);
474 /* If that failed, we have try another trick. If there is a
475 Krb5 ticket of the form afs/<cell>@<realm> or afs@<CELL>
476 where <cell> matches our cell, then we pick the identity
481 If Krb5 was used to obtain the token, then there is a Krb5
482 ticket of the form afs/<cell>@<REALM> or afs@<CELL> still
483 in the cache. This is also true for Krb524 token
488 If such a Krb5 ticket is found, use the identity of that
489 credential as the identity of the AFS token.
492 if (ident == NULL && cell != NULL) {
495 if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
499 kcdb_cred_get_identity(c, &ident);
500 /* this could be Krb5 or Krb524, so we leave method at
502 method = AFS_TOKEN_AUTO;
503 kcdb_cred_release(c);
507 /* If that didn't work either, we look for a Krb4 ticket of
508 the form afs.<cell>@<REALM> or afs@<CELL> which matches the
513 If Krb4 was used to obtain an AFS token, then there should
514 be a Krb4 ticket of the form afs.<cell>@<REALM> or
515 afs@<CELL> in the cache.
519 If such a ticket is found, then use the identity of that
520 credential as the identity of the AFS token.
522 if (ident == NULL && cell != NULL) {
525 if (krb4_credtype_id < 0) {
526 kcdb_credtype_get_id(KRB4_CREDTYPE_NAME,
530 if (krb4_credtype_id >= 0 &&
531 KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
536 kcdb_cred_get_identity(c, &ident);
537 kcdb_cred_release(c);
538 method = AFS_TOKEN_KRB4;
543 /* Finally, we allow any extension plugins to give this a shot */
544 if (ident == NULL && cell != NULL) {
545 afs_ext_resolve_token(cell,
553 /* One more thing to try. If we have a cell->identity
554 mapping, then we try that. */
555 if (ident == NULL && cell != NULL) {
556 khm_handle h_cellmap;
557 wchar_t tidname[KCDB_IDENT_MAXCCH_NAME];
560 cb = sizeof(tidname);
562 if (KHM_SUCCEEDED(khc_open_space(csp_afscred,
565 if (KHM_SUCCEEDED(khc_read_string(h_cellmap,
569 kcdb_identity_create(tidname,
570 KCDB_IDENT_FLAG_CREATE,
573 khc_close_space(h_cellmap);
577 /* all else failed */
579 if(KHM_FAILED(kcdb_identity_create(idname,
580 KCDB_IDENT_FLAG_CREATE,
585 if(KHM_FAILED(kcdb_cred_create(crname, ident, afs_credtype_id, &cred)))
588 kcdb_cred_set_attr(cred, afs_attr_method, &method, sizeof(method));
590 TimetToFileTime(atoken.endTime, &ft);
591 kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &ft, sizeof(ft));
592 if (atoken.startTime != 0) {
593 TimetToFileTime(atoken.startTime, &ft);
594 kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft));
596 kcdb_cred_set_attr(cred, afs_attr_client_princ,
597 &aclient, sizeof(aclient));
598 kcdb_cred_set_attr(cred, afs_attr_server_princ,
599 &aserver, sizeof(aserver));
602 kcdb_cred_set_attr(cred, afs_attr_cell, cell, (khm_size)KCDB_CBSIZE_AUTO);
605 kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION,
606 location, (khm_size)KCDB_CBSIZE_AUTO);
608 kcdb_credset_add_cred(afs_credset, cred, -1);
610 /* both these calls are NULL pointer safe */
611 kcdb_cred_release(cred);
613 kcdb_identity_release(ident);
619 kcdb_identity_release(ident);
621 kcdb_cred_release(cred);
627 #define ALLOW_REGISTER 1
629 ViceIDToUsername(char *username,
633 struct ktc_principal *aclient,
634 struct ktc_principal *aserver,
635 struct ktc_token *atoken)
637 static char lastcell[MAXCELLCHARS+1] = { 0 };
638 static char confname[512] = { 0 };
639 char username_copy[BUFSIZ];
640 long viceId = ANONYMOUSID; /* AFS uid of user */
642 #ifdef ALLOW_REGISTER
644 #endif /* ALLOW_REGISTER */
646 if (confname[0] == '\0') {
647 StringCbCopyA(confname, sizeof(confname), AFSDIR_CLIENT_ETC_DIRPATH);
650 StringCbCopyA(lastcell, sizeof(lastcell), aserver->cell);
652 if (!pr_Initialize (0, confname, aserver->cell)) {
653 char sname[PR_MAXNAMELEN];
654 StringCbCopyA(sname, sizeof(sname), username);
655 status = pr_SNameToId (sname, &viceId);
659 #ifdef AFS_ID_TO_NAME
661 * This is a crock, but it is Transarc's crock, so
662 * we have to play along in order to get the
663 * functionality. The way the afs id is stored is
664 * as a string in the username field of the token.
665 * Contrary to what you may think by looking at
666 * the code for tokens, this hack (AFS ID %d) will
667 * not work if you change %d to something else.
669 #endif /* AFS_ID_TO_NAME */
671 * This code is taken from cklog -- it lets people
672 * automatically register with the ptserver in foreign cells
675 /* copy the username because pr_CreateUser will lowercase it */
676 StringCbCopyA(username_copy, BUFSIZ, username);
678 #ifdef ALLOW_REGISTER
680 if (viceId != ANONYMOUSID) {
681 #else /* ALLOW_REGISTER */
682 if ((status == 0) && (viceId != ANONYMOUSID))
683 #endif /* ALLOW_REGISTER */
685 #ifdef AFS_ID_TO_NAME
686 StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
687 #endif /* AFS_ID_TO_NAME */
689 #ifdef ALLOW_REGISTER
690 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
692 StringCbCopyA(aclient->name, sizeof(aclient->name), username);
693 StringCbCopyA(aclient->instance, sizeof(aclient->instance), "");
694 StringCbCopyA(aclient->cell, sizeof(aclient->cell), realm_of_user);
695 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
697 if (status = pr_Initialize(1L, confname, aserver->cell))
699 status = pr_CreateUser(username, &id);
701 StringCbCopyA(username, BUFSIZ, username_copy);
702 #ifdef AFS_ID_TO_NAME
703 StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
704 #endif /* AFS_ID_TO_NAME */
707 #endif /* ALLOW_REGISTER */
713 copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) {
714 krb5_error_code code;
718 code = pkrb5_decode_ticket(&v5cred->ticket, &ticket);
720 len = krb5_princ_realm(context, ticket->server)->length;
721 if (len > destlen - 1)
724 StringCbCopyA(dest, len, krb5_princ_realm(context, ticket->server)->data);
726 pkrb5_free_ticket(context, ticket);
731 afs_klog(khm_handle identity,
736 afs_tk_method method,
737 time_t * tok_expiration,
742 struct ktc_principal aserver;
743 struct ktc_principal aclient;
744 char realm_of_user[MAXKTCREALMLEN]; /* Kerberos realm of user */
745 char realm_of_cell[MAXKTCREALMLEN]; /* Kerberos realm of cell */
746 char local_cell[MAXCELLCHARS+1];
747 char Dmycell[MAXCELLCHARS+1];
748 struct ktc_token atoken;
749 struct ktc_token btoken;
750 afs_conf_cell ak_cellconfig; /* General information about the cell */
753 char ServiceName[128];
754 khm_handle confighandle = NULL;
755 khm_int32 supports_krb4 = (pkrb_get_tf_realm == NULL ? 0 : 1);
756 khm_int32 got524cred = 0;
759 BOOL bGotCreds = FALSE; /* got creds? */
762 *tok_expiration = (time_t) 0;
764 if (!afs_is_running()) {
765 _report_sr0(KHERR_WARNING, IDS_ERR_NOSERVICE);
769 if ( !realm ) realm = "";
770 if ( !cell ) cell = "";
771 if ( !service ) service = "";
773 memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
774 memset(RealmName, '\0', sizeof(RealmName));
775 memset(CellName, '\0', sizeof(CellName));
776 memset(ServiceName, '\0', sizeof(ServiceName));
777 memset(realm_of_user, '\0', sizeof(realm_of_user));
778 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
779 memset(Dmycell, '\0', sizeof(Dmycell));
781 // NULL or empty cell returns information on local cell
783 StringCbCopyA(Dmycell, sizeof(Dmycell), cell);
785 rc = afs_get_cellconfig(Dmycell, &ak_cellconfig, local_cell);
787 _reportf(L"afs_get_cellconfig returns %ld", rc);
789 _report_sr2(KHERR_ERROR, IDS_ERR_CELLCONFIG, _cstr(Dmycell), _int32(rc));
790 _suggest_sr(IDS_ERR_CELLCONFIG_S, KHERR_SUGGEST_NONE);
795 if (linkedCell && ak_cellconfig.linkedCell)
796 StringCbCopyA(linkedCell, MAXCELLCHARS,
797 ak_cellconfig.linkedCell);
799 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
800 afs_realm_of_cell(&ak_cellconfig, FALSE));
802 if (strlen(service) == 0)
803 StringCbCopyA(ServiceName, sizeof(ServiceName), "afs");
805 StringCbCopyA(ServiceName, sizeof(ServiceName), service);
807 if (strlen(cell) == 0)
808 StringCbCopyA(CellName, sizeof(CellName), local_cell);
810 StringCbCopyA(CellName, sizeof(CellName), cell);
812 if (strlen(realm) == 0)
813 StringCbCopyA(RealmName, sizeof(RealmName), realm_of_cell);
815 StringCbCopyA(RealmName, sizeof(RealmName), realm);
817 memset(&creds, '\0', sizeof(creds));
819 /*** Kerberos 5 and 524 ***/
821 if (method == AFS_TOKEN_AUTO ||
822 method == AFS_TOKEN_KRB5 ||
823 method == AFS_TOKEN_KRB524) {
825 krb5_context context = 0;
826 krb5_ccache k5cc = 0;
828 krb5_creds * k5creds = 0;
830 krb5_principal client_principal = 0;
831 krb5_flags flags = 0;
837 _reportf(L"Trying Kerberos 5");
839 if (!(r = khm_krb5_initialize(identity, &context, &k5cc))) {
842 memset((char *)&increds, 0, sizeof(increds));
844 pkrb5_cc_get_principal(context, k5cc, &client_principal);
845 i = krb5_princ_realm(context, client_principal)->length;
846 if (i > MAXKTCREALMLEN-1)
847 i = MAXKTCREALMLEN-1;
848 StringCchCopyNA(realm_of_user, ARRAYLENGTH(realm_of_user),
849 krb5_princ_realm(context, client_principal)->data,
852 _reportf(L"khm_krb5_initialize returns code %d", r);
856 increds.client = client_principal;
857 increds.times.endtime = 0;
858 /* Ask for DES since that is what V4 understands */
859 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
861 #ifdef KRB5_TC_NOTICKET
862 flags = KRB5_TC_OPENCLOSE;
863 r = pkrb5_cc_set_flags(context, k5cc, flags);
865 if (strlen(realm) != 0) {
867 /* First try Service/Cell@REALM */
868 if (r = pkrb5_build_principal(context, &increds.server,
874 _reportf(L"krb5_build_principal returns %d", r);
878 r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
879 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
880 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
881 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
882 /* Next try Service@REALM */
883 pkrb5_free_principal(context, increds.server);
884 r = pkrb5_build_principal(context, &increds.server,
890 r = pkrb5_get_credentials(context, 0, k5cc,
894 /* Check to make sure we received a valid ticket; if not remove it
895 * and try again. Perhaps there are two service tickets for the
896 * same service in the ccache.
898 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
899 pkrb5_free_principal(context, increds.server);
900 pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
901 pkrb5_free_creds(context, k5creds);
903 goto retry_retcred_1;
907 /* First try Service/Cell@_CLIENT_REALM */
908 if (r = pkrb5_build_principal(context, &increds.server,
909 (int) strlen(realm_of_user),
914 _reportf(L"krb5_build_principal returns %d", r);
918 r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
920 /* the user realm is a valid cell realm */
921 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell), realm_of_user);
923 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
924 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
925 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
926 pkrb5_free_principal(context, increds.server);
927 r = pkrb5_build_principal(context, &increds.server,
928 (int) strlen(realm_of_cell),
934 r = pkrb5_get_credentials(context, 0, k5cc,
937 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
938 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
939 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
940 strlen(realm_of_cell) == 0) {
941 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
942 afs_realm_of_cell(&ak_cellconfig, TRUE));
944 pkrb5_free_principal(context, increds.server);
945 r = pkrb5_build_principal(context, &increds.server,
946 (int) strlen(realm_of_cell),
952 r = pkrb5_get_credentials(context, 0, k5cc,
955 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
956 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
957 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
958 /* Next try Service@REALM */
959 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
960 afs_realm_of_cell(&ak_cellconfig, FALSE));
962 pkrb5_free_principal(context, increds.server);
963 r = pkrb5_build_principal(context, &increds.server,
964 (int) strlen(realm_of_cell),
969 r = pkrb5_get_credentials(context, 0, k5cc,
972 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
973 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
974 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
975 strlen(realm_of_cell) == 0) {
976 /* Next try Service@REALM */
977 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
978 afs_realm_of_cell(&ak_cellconfig, TRUE));
980 pkrb5_free_principal(context, increds.server);
981 r = pkrb5_build_principal(context, &increds.server,
982 (int) strlen(realm_of_cell),
987 r = pkrb5_get_credentials(context, 0, k5cc,
991 if (r == 0 && strlen(realm_of_cell) == 0)
992 copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
994 /* Check to make sure we received a valid ticket; if not remove it
995 * and try again. Perhaps there are two service tickets for the
996 * same service in the ccache.
998 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
999 pkrb5_free_principal(context, increds.server);
1000 pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
1001 pkrb5_free_creds(context, k5creds);
1003 goto retry_retcred_2;
1007 pkrb5_free_principal(context, increds.server);
1008 pkrb5_free_principal(context, client_principal);
1009 client_principal = 0;
1010 #ifdef KRB5_TC_NOTICKET
1011 flags = KRB5_TC_OPENCLOSE | KRB5_TC_NOTICKET;
1012 pkrb5_cc_set_flags(context, k5cc, flags);
1015 (void) pkrb5_cc_close(context, k5cc);
1019 _reportf(L"Code %d while getting credentials", r);
1024 if ( k5creds->ticket.length > MAXKTCTICKETLEN ||
1025 method == AFS_TOKEN_KRB524) {
1029 /* This code inserts the entire K5 ticket into the token */
1031 _reportf(L"Trying K5 SetToken");
1033 memset(&aserver, '\0', sizeof(aserver));
1034 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1035 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1037 memset(&atoken, '\0', sizeof(atoken));
1038 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
1039 atoken.startTime = k5creds->times.starttime;
1040 atoken.endTime = k5creds->times.endtime;
1041 memcpy(&atoken.sessionKey,
1042 k5creds->keyblock.contents,
1043 k5creds->keyblock.length);
1044 atoken.ticketLen = k5creds->ticket.length;
1045 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
1048 *tok_expiration = k5creds->times.endtime;
1051 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
1052 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
1053 if ( rc == KTC_NOCM && retry < 20 ) {
1056 goto retry_gettoken5;
1061 if (atoken.kvno == btoken.kvno &&
1062 atoken.ticketLen == btoken.ticketLen &&
1063 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1064 sizeof(atoken.sessionKey)) &&
1065 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1068 if (k5creds && context)
1069 pkrb5_free_creds(context, k5creds);
1072 pkrb5_free_context(context);
1074 _reportf(L"Same token already exists");
1080 // * Reset the "aclient" structure before we call ktc_SetToken.
1081 // * This structure was first set by the ktc_GetToken call when
1082 // * we were comparing whether identical tokens already existed.
1084 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
1085 StringCchCopyNA(aclient.name, MAXKTCNAMELEN,
1086 k5creds->client->data[0].data, len);
1088 if ( k5creds->client->length > 1 ) {
1089 StringCbCatA(aclient.name, sizeof(aclient.name), ".");
1090 p = aclient.name + strlen(aclient.name);
1091 len = (int) min(k5creds->client->data[1].length,
1092 MAXKTCNAMELEN - strlen(aclient.name) - 1);
1093 StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
1094 k5creds->client->data[1].data, len);
1097 aclient.instance[0] = '\0';
1099 StringCbCopyA(aclient.cell, sizeof(aclient.cell), realm_of_cell);
1101 StringCbCatA(aclient.name, sizeof(aclient.name), "@");
1102 p = aclient.name + strlen(aclient.name);
1103 len = (int) min(k5creds->client->realm.length,
1104 MAXKTCNAMELEN - strlen(aclient.name) - 1);
1105 StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
1106 k5creds->client->realm.data, len);
1108 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1109 &aclient, &aserver, &atoken);
1111 rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
1115 if (k5creds && context)
1116 pkrb5_free_creds(context, k5creds);
1119 pkrb5_free_context(context);
1124 _reportf(L"SetToken returns code %d", rc);
1128 _reportf(L"Trying Krb524");
1130 if (pkrb524_convert_creds_kdc &&
1131 (method == AFS_TOKEN_AUTO || method == AFS_TOKEN_KRB524)) {
1132 /* This requires krb524d to be running with the KDC */
1133 r = pkrb524_convert_creds_kdc(context, k5creds, &creds);
1135 _reportf(L"Code %d while converting credentials", r);
1144 if (client_principal)
1145 pkrb5_free_principal(context, client_principal);
1147 if (k5creds && context)
1148 pkrb5_free_creds(context, k5creds);
1151 pkrb5_free_context(context);
1157 if (supports_krb4) {
1158 kcdb_identity_get_config(identity, 0, &confighandle);
1159 khc_read_int32(confighandle, L"Krb4Cred\\Krb4NewCreds", &supports_krb4);
1160 khc_close_space(confighandle);
1164 _reportf(L"Kerberos 4 not configured");
1166 if (!bGotCreds && supports_krb4 &&
1167 strlen(RealmName) < REALM_SZ &&
1168 (method == AFS_TOKEN_AUTO ||
1169 method == AFS_TOKEN_KRB4)) {
1173 _reportf(L"Trying Kerberos 4");
1175 if (!realm_of_user[0] ) {
1176 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user))
1178 /* can't determine realm of user */
1179 _reportf(L"krb_get_tf_realm returns %d", rc);
1184 _reportf(L"Trying to find %S.%S@%S", ServiceName, CellName, RealmName);
1185 rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
1186 if (rc == NO_TKT_FIL) {
1187 // if the problem is that we have no krb4 tickets
1188 // do not attempt to continue
1189 _reportf(L"krb_get_cred returns %d (no ticket file)", rc);
1193 if (rc != KSUCCESS) {
1194 _reportf(L"Trying to find %S@%S", ServiceName, RealmName);
1195 rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
1198 if (rc != KSUCCESS) {
1199 _reportf(L"Trying to obtain new ticket");
1200 if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1201 CellName, RealmName, 0))
1203 if ((rc = (*pkrb_get_cred)(ServiceName, CellName,
1204 RealmName, &creds)) != KSUCCESS) {
1207 _reportf(L"Got %S.%S@%S", ServiceName, CellName, RealmName);
1209 } else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1212 if ((rc = (*pkrb_get_cred)(ServiceName, "",
1213 RealmName, &creds)) != KSUCCESS) {
1216 _reportf(L"Got %S@%S", ServiceName, RealmName);
1231 memset(&aserver, '\0', sizeof(aserver));
1232 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1233 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1235 memset(&atoken, '\0', sizeof(atoken));
1236 atoken.kvno = (short)creds.kvno;
1237 atoken.startTime = creds.issue_date;
1238 atoken.endTime = (*pkrb_life_to_time)(creds.issue_date,creds.lifetime);
1239 memcpy(&atoken.sessionKey, creds.session, 8);
1240 atoken.ticketLen = creds.ticket_st.length;
1241 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
1244 *tok_expiration = atoken.endTime;
1246 if (!(rc = ktc_GetToken(&aserver, &btoken,
1247 sizeof(btoken), &aclient)) &&
1248 atoken.kvno == btoken.kvno &&
1249 atoken.ticketLen == btoken.ticketLen &&
1250 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1251 sizeof(atoken.sessionKey)) &&
1252 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1259 // Reset the "aclient" structure before we call ktc_SetToken.
1260 // This structure was first set by the ktc_GetToken call when
1261 // we were comparing whether identical tokens already existed.
1263 StringCchCopyA(aclient.name, MAXKTCNAMELEN, creds.pname);
1264 if (creds.pinst[0]) {
1265 StringCchCatA(aclient.name, MAXKTCNAMELEN, ".");
1266 StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.pinst);
1269 StringCbCopyA(aclient.instance, sizeof(aclient.instance), "");
1271 StringCchCatA(aclient.name, MAXKTCNAMELEN, "@");
1272 StringCchCatA(aclient.name, MAXKTCNAMELEN, got524cred ? realm_of_user : creds.realm);
1274 StringCbCopyA(aclient.cell, sizeof(aclient.cell), CellName);
1276 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1277 &aclient, &aserver, &atoken);
1279 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
1280 afs_report_error(rc, "ktc_SetToken()");
1283 } else if (method == AFS_TOKEN_AUTO ||
1284 method >= AFS_TOKEN_USER) {
1285 /* we couldn't get a token using Krb5, Krb524 or Krb4, either
1286 because we couldn't get the necessary credentials or
1287 because the method was set to not use those. Now we
1288 dispatch to any extensions to see if they have better
1291 rc = !afs_ext_klog(method,
1299 /* if the return code was not set, we should set it now.
1300 Otherwise we let the code go through. */
1302 /* No tokens were obtained. We should report something */
1303 _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
1307 rc = KHM_ERROR_GENERAL;
1312 if (ak_cellconfig.linkedCell)
1313 free(ak_cellconfig.linkedCell);
1318 /**************************************/
1319 /* afs_realm_of_cell(): */
1320 /**************************************/
1322 afs_realm_of_cell(afs_conf_cell *cellconfig, BOOL referral_fallback)
1324 char krbhst[MAX_HSTNM]="";
1325 static char krbrlm[MAXKTCREALMLEN+1]="";
1326 krb5_context ctx = 0;
1327 char ** realmlist=NULL;
1328 krb5_error_code r = 0;
1333 if (referral_fallback) {
1335 p = strchr(cellconfig->hostName[0], '.');
1337 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1339 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1340 #if _MSC_VER >= 1400
1341 _strupr_s(krbrlm, sizeof(krbrlm));
1346 if ( pkrb5_init_context ) {
1347 r = pkrb5_init_context(&ctx);
1349 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
1350 if ( !r && realmlist && realmlist[0] ) {
1351 StringCbCopyA(krbrlm, sizeof(krbrlm), realmlist[0]);
1352 pkrb5_free_host_realm(ctx, realmlist);
1355 pkrb5_free_context(ctx);
1359 if (pkrb_get_krbhst && pkrb_realmofhost) {
1360 StringCbCopyA(krbrlm, sizeof(krbrlm),
1361 (char *)(*pkrb_realmofhost)(cellconfig->hostName[0]));
1362 if ((*pkrb_get_krbhst)(krbhst, krbrlm, 1) != KSUCCESS)
1368 p = strchr(cellconfig->hostName[0], '.');
1370 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1372 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1373 #if _MSC_VER >= 1400
1374 _strupr_s(krbrlm, sizeof(krbrlm));
1384 /**************************************/
1385 /* afs_get_cellconfig(): */
1386 /**************************************/
1388 afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
1392 char linkedCell[MAXCELLCHARS]="";
1394 local_cell[0] = (char)0;
1395 memset(cellconfig, 0, sizeof(*cellconfig));
1397 cellconfig->cbsize = sizeof(*cellconfig);
1399 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
1400 if (rc = cm_GetRootCellName(local_cell)) {
1404 if (strlen(cell) == 0)
1405 StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
1407 StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
1409 rc = cm_SearchCellRegistry(1, cell, NULL, linkedCell,
1410 afs_get_cellconfig_callback, (void*) cellconfig);
1411 if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
1412 rc = cm_SearchCellFileEx(cell, NULL, linkedCell, afs_get_cellconfig_callback,
1415 rc = cm_SearchCellByDNS(cell, NULL, &ttl,
1416 afs_get_cellconfig_callback,
1417 (void*) cellconfig);
1420 cellconfig->linkedCell = strdup(linkedCell);
1425 /**************************************/
1426 /* afs_get_cellconfig_callback(): */
1427 /**************************************/
1429 afs_get_cellconfig_callback(void *cellconfig,
1430 struct sockaddr_in *addrp,
1432 unsigned short ipRank)
1434 afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
1436 cc->hostAddr[cc->numServers] = *addrp;
1437 StringCbCopyA(cc->hostName[cc->numServers],
1438 sizeof(cc->hostName[0]), namep);
1444 /**************************************/
1445 /* afs_report_error(): */
1446 /**************************************/
1448 afs_report_error(LONG rc, LPCSTR FailedFunctionName)
1451 const char *errText;
1453 // Using AFS defines as error messages for now, until Transarc
1454 // gets back to me with "string" translations of each of these
1456 if (rc == KTC_ERROR)
1457 errText = "KTC_ERROR";
1458 else if (rc == KTC_TOOBIG)
1459 errText = "KTC_TOOBIG";
1460 else if (rc == KTC_INVAL)
1461 errText = "KTC_INVAL";
1462 else if (rc == KTC_NOENT)
1463 errText = "KTC_NOENT";
1464 else if (rc == KTC_PIOCTLFAIL)
1465 errText = "KTC_PIOCTLFAIL";
1466 else if (rc == KTC_NOPIOCTL)
1467 errText = "KTC_NOPIOCTL";
1468 else if (rc == KTC_NOCELL)
1469 errText = "KTC_NOCELL";
1470 else if (rc == KTC_NOCM)
1471 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
1473 errText = "Unknown error!";
1475 StringCbPrintfA(message, sizeof(message),
1476 "%s\n(%s failed)", errText, FailedFunctionName);
1477 _report_cs1(KHERR_ERROR, L"%1!S!", _cptr(message));
1483 GetServiceStatus(LPSTR lpszMachineName,
1484 LPSTR lpszServiceName,
1485 DWORD *lpdwCurrentState,
1486 DWORD *lpdwWaitHint)
1489 SC_HANDLE schSCManager = NULL;
1490 SC_HANDLE schService = NULL;
1491 DWORD fdwDesiredAccess = 0;
1492 SERVICE_STATUS ssServiceStatus = {0};
1495 *lpdwCurrentState = 0;
1497 fdwDesiredAccess = GENERIC_READ;
1499 schSCManager = OpenSCManagerA(lpszMachineName,
1503 if(schSCManager == NULL) {
1504 hr = GetLastError();
1508 schService = OpenServiceA(schSCManager,
1512 if(schService == NULL) {
1513 hr = GetLastError();
1517 fRet = QueryServiceStatus(schService,
1521 hr = GetLastError();
1525 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
1527 *lpdwWaitHint = ssServiceStatus.dwWaitHint;
1530 CloseServiceHandle(schService);
1531 CloseServiceHandle(schSCManager);
1536 DWORD ServiceControl(LPSTR lpszMachineName,
1537 LPSTR lpszServiceName,
1541 SC_HANDLE schSCManager = NULL;
1542 SC_HANDLE schService = NULL;
1543 DWORD fdwDesiredAccess = 0;
1544 SERVICE_STATUS ssServiceStatus = {0};
1546 DWORD dwCurrentState = 0;
1550 fdwDesiredAccess = GENERIC_READ;
1552 schSCManager = OpenSCManagerA(lpszMachineName, NULL,
1555 if(schSCManager == NULL) {
1556 hr = GetLastError();
1560 fdwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
1562 schService = OpenServiceA(schSCManager, lpszServiceName,
1565 if(schService == NULL) {
1566 hr = GetLastError();
1570 fRet = QueryServiceStatus(schService, &ssServiceStatus);
1573 hr = GetLastError();
1577 dwCurrentState = ssServiceStatus.dwCurrentState;
1579 if (dwCurrentState == SERVICE_STOPPED &&
1580 dwNewState == SERVICE_RUNNING) {
1582 fRet = StartService(schService, 0, NULL);
1584 if (fRet == FALSE) {
1585 hr = GetLastError();
1590 if (dwCurrentState == SERVICE_RUNNING &&
1591 dwNewState == SERVICE_STOPPED) {
1592 fRet = ControlService(schService, SERVICE_CONTROL_STOP,
1595 if (fRet == FALSE) {
1596 hr = GetLastError();
1603 CloseServiceHandle(schService);
1604 CloseServiceHandle(schSCManager);
1610 afs_check_for_cell_realm_match(khm_handle identity, char * cell) {
1611 char local_cell[MAXCELLCHARS];
1612 wchar_t wrealm[MAXCELLCHARS];
1613 wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
1617 afs_conf_cell cellconfig;
1620 ZeroMemory(local_cell, sizeof(local_cell));
1621 ZeroMemory(&cellconfig, sizeof(cellconfig));
1623 rc = afs_get_cellconfig(cell, &cellconfig, local_cell);
1627 realm = afs_realm_of_cell(&cellconfig, FALSE);
1628 if (cellconfig.linkedCell)
1629 free(cellconfig.linkedCell);
1630 if (!realm[0]) /* referral; assume it matches */
1633 AnsiStrToUnicode(wrealm, sizeof(wrealm), realm);
1635 cb = sizeof(idname);
1637 kcdb_identity_get_name(identity, idname, &cb);
1639 atsign = wcschr(idname, L'@');
1640 if (atsign && atsign[1] && !_wcsicmp(atsign + 1, wrealm)) {