Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / WINNT / netidmgr_plugin / afsfuncs.c
blob477e0f68dc5db6978c1c240c29d0d923b2387930
1 /*
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
22 * SOFTWARE.
25 /* $Id$ */
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)
32 #include<afscred.h>
33 #include<dynimport.h>
34 #include<krb5common.h>
35 #include<winsock2.h>
36 #include<afs/cm.h>
38 #pragma warning (pop)
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 *);
44 BOOL
45 afs_is_running(void) {
46 DWORD CurrentState;
48 if (!AfsAvailable)
49 return FALSE;
51 if (GetServiceStatus(NULL, TRANSARCAFSDAEMON,
52 &CurrentState, NULL) != NOERROR)
53 return FALSE;
54 if (CurrentState != SERVICE_RUNNING)
55 return FALSE;
57 return TRUE;
60 int
61 afs_unlog(void)
63 long rc;
65 if (!afs_is_running())
66 return 0;
68 rc = ktc_ForgetAllTokens();
70 return rc;
73 int
74 afs_unlog_cred(khm_handle cred)
76 long rc;
77 struct ktc_principal princ;
78 khm_size cbbuf;
79 wchar_t name[KCDB_MAXCCH_NAME];
81 if (!afs_is_running())
82 return 0;
84 cbbuf = sizeof(princ);
85 if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_server_princ,
86 NULL, &princ, &cbbuf)))
87 return 1;
89 afs_princ_to_string(&princ, name, sizeof(name));
91 _report_cs1(KHERR_INFO, L"Destroying token %1!s!",
92 _cstr(name));
93 _resolve();
95 rc = ktc_ForgetToken(&princ);
97 return rc;
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,
105 wchar_t * buf,
106 size_t cbbuf)
108 wchar_t wbuf[256];
109 int rv = 0;
110 int l;
112 l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->name);
113 wbuf[l] = L'\0';
115 rv = FAILED(StringCbCopy(buf, cbbuf, wbuf));
116 if(p->instance[0]) {
117 StringCbCat(buf, cbbuf, L".");
118 if((l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->instance)) > 0) {
119 wbuf[l] = L'\0';
120 rv = rv || FAILED(StringCbCat(buf, cbbuf, wbuf));
122 else
123 rv = 1;
125 if(p->cell[0]) {
126 rv = rv || FAILED(StringCbCat(buf, cbbuf, L"@"));
127 if((l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->cell)) > 0) {
128 wbuf[l] = L'\0';
129 rv = rv || FAILED(StringCbCat(buf, cbbuf, wbuf));
131 else
132 rv = 1;
135 return rv;
139 afs_list_tokens(void)
141 int r;
143 kcdb_credset_flush(afs_credset);
144 r = afs_list_tokens_internal();
145 kcdb_credset_collect(NULL, afs_credset, NULL, afs_credtype_id, NULL);
147 if (r == 0) {
148 afs_icon_set_state(AFSICON_REPORT_TOKENS, afs_credset);
149 } else if (r == -1) {
150 afs_icon_set_state(AFSICON_SERVICE_STOPPED, NULL);
151 } else {
152 afs_icon_set_state(AFSICON_SERVICE_ERROR, NULL);
155 return r;
158 /* is the credential provided an AFS token and is it from the
159 specified cell? */
160 static khm_int32 KHMAPI
161 afs_filter_by_cell(khm_handle cred, khm_int32 flags, void * rock)
163 wchar_t wcell[MAXCELLCHARS];
164 wchar_t * tcell;
165 khm_size cbsize;
166 khm_int32 type;
168 tcell = (wchar_t *) rock;
170 if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
171 type != afs_credtype_id)
172 return FALSE;
174 cbsize = sizeof(wcell);
175 if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell,
176 NULL, wcell, &cbsize)))
177 return FALSE;
179 if(wcscmp(wcell, tcell))
180 return FALSE;
182 return TRUE;
185 struct token_filter_data {
186 wchar_t * cell;
189 khm_int32 KHMAPI
190 afs_filter_for_token(khm_handle cred, khm_int32 flags, void * rock) {
191 struct token_filter_data * pdata;
192 wchar_t ccell[MAXCELLCHARS];
193 khm_size cb;
194 khm_int32 ctype;
196 pdata = (struct token_filter_data *) rock;
198 if (KHM_FAILED(kcdb_cred_get_type(cred, &ctype)) ||
199 ctype != afs_credtype_id)
201 return 0;
203 cb = sizeof(ccell);
205 if (KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell,
206 NULL,
207 ccell,
208 &cb)) ||
209 _wcsicmp(ccell, pdata->cell))
211 return 0;
213 return 1;
216 khm_handle
217 afs_find_token(khm_handle credset, wchar_t * cell) {
218 struct token_filter_data fdata;
219 khm_handle cred = NULL;
221 fdata.cell = cell;
223 if (KHM_FAILED(kcdb_credset_find_filtered(credset,
225 afs_filter_for_token,
226 &fdata,
227 &cred,
228 NULL)))
229 return NULL;
230 else
231 return cred;
234 static khm_int32 KHMAPI
235 afs_filter_krb5_tkt(khm_handle cred, khm_int32 flags, void * rock)
237 wchar_t cname[KCDB_CRED_MAXCCH_NAME];
238 khm_int32 type;
239 wchar_t * tcell;
240 wchar_t * t, *tkt_cell;
241 khm_size cbsize;
243 tcell = (wchar_t *) rock;
245 if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
246 type != krb5_credtype_id)
247 return FALSE;
249 cbsize = sizeof(cname);
250 if (KHM_FAILED(kcdb_cred_get_name(cred, cname, &cbsize)))
251 return FALSE;
253 if (!wcsncmp(cname, L"afs/", 4)) {
255 tkt_cell = cname + 4;
257 t = wcschr(tkt_cell, L'@');
258 if (t == NULL)
259 return FALSE;
260 *t = L'\0';
262 } else if (!wcsncmp(cname, L"afs@", 4)) {
264 tkt_cell = cname + 4;
266 } else {
267 return FALSE;
270 if (_wcsicmp(tcell, tkt_cell))
271 return FALSE;
273 return TRUE;
276 static khm_int32 KHMAPI
277 afs_filter_krb4_tkt(khm_handle cred, khm_int32 flags, void * rock)
279 wchar_t cname[KCDB_CRED_MAXCCH_NAME];
280 khm_int32 type;
281 wchar_t * tcell;
282 wchar_t * t, *tkt_cell;
283 khm_size cbsize;
285 tcell = (wchar_t *) rock;
287 if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
288 type != krb4_credtype_id)
289 return FALSE;
291 cbsize = sizeof(cname);
292 if (KHM_FAILED(kcdb_cred_get_name(cred, cname, &cbsize)))
293 return FALSE;
295 if (!wcsncmp(cname, L"afs.", 4)) {
297 tkt_cell = cname + 4;
299 t = wcschr(tkt_cell, L'@');
300 if (t == NULL)
301 return FALSE;
302 *t = L'\0';
304 } else if (!wcsncmp(cname, L"afs@", 4)) {
306 tkt_cell = cname + 4;
308 } else {
309 return FALSE;
312 if (_wcsicmp(tcell, tkt_cell))
313 return FALSE;
315 return TRUE;
318 /* collects all AFS tokens to the root credential set using the
319 generic afs_credset credential set
322 afs_list_tokens_internal(void)
324 struct ktc_principal aserver;
325 struct ktc_principal aclient;
326 struct ktc_token atoken;
327 int cellNum;
328 int BreakAtEnd;
329 wchar_t idname[256];
330 wchar_t crname[256];
331 wchar_t location[256];
332 wchar_t *cell;
334 DWORD rc;
336 khm_handle ident = NULL;
337 khm_handle cred = NULL;
338 afs_tk_method method;
340 FILETIME ft;
342 if (!afs_is_running())
343 return -1;
345 kcdb_credset_flush(afs_credset);
347 LoadString(hResModule, IDS_DEF_LOCATION, location, ARRAYLENGTH(location));
349 BreakAtEnd = 0;
350 cellNum = 0;
351 while (1)
353 memset(&aserver, 0, sizeof(aserver));
354 if (rc = ktc_ListTokens(cellNum, &cellNum, &aserver))
356 if (rc != KTC_NOENT)
357 return(-2);
359 if (BreakAtEnd == 1)
360 break;
362 BreakAtEnd = 1;
363 memset(&atoken, '\0', sizeof(atoken));
364 if (rc = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient))
366 if (rc == KTC_ERROR)
367 return(-3);
369 continue;
372 #if 0
373 /* failed attempt at trying to figure out the principal name from
374 the token. The ticket that is attached to the token is not
375 in a form that is useful at this point */
376 idname[0] = L'\0';
377 if(atoken.kvno == RXKAD_TKT_TYPE_KERBEROS_V5) {
378 krb5_context ctx = 0;
379 krb5_ccache cc = 0;
380 krb5_creds * k5c;
381 krb5_error_code code;
382 char * princ;
384 code = khm_krb5_initialize(&ctx, &cc);
385 if(code)
386 goto _no_krb5;
388 k5c = (krb5_creds *) atoken.ticket;
390 code = pkrb5_unparse_name(ctx, k5c->client, &princ);
391 if(code)
392 goto _no_krb5;
394 MultiByteToWideChar(CP_ACP, 0, princ, strlen(princ), idname, sizeof(idname)/sizeof(idname[0]));
396 pkrb5_free_unparsed_name(ctx, princ);
397 _no_krb5:
400 #endif
402 method = AFS_TOKEN_AUTO;
404 afs_princ_to_string(&aclient, idname, sizeof(idname));
406 /* We need to figure out a good client name which we can use
407 to create an identity which looks familiar to the user. No
408 good way of doing this, so we use a heuristic.
410 Note that, we use another heuristic to find out which
411 identity to associate the token with.
413 ASSUMPTION:
415 The assumption here is that the principal for the token is
416 computed as follows:
418 if realm != cell : principal looks like user@realm@cell
419 if realm == cell : principal looks like user@realm
421 HEURISTIC:
423 We strip the part of the string that follows the second '@'
424 sign to obtain the 'user@realm' part, which we use as the
425 credential name. If there is no second '@', we use the
426 whole principal name. */
428 wchar_t * ats;
430 ats = wcschr(idname, L'@');
431 if(ats && (ats = wcschr(ats + 1, L'@')))
432 *ats = L'\0';
435 afs_princ_to_string(&aserver, crname, sizeof(crname));
437 /* Ok, now we need to figure out which identity to associate
438 this token with. This is a little bit tricky, and there is
439 currently no good way of determining the original identity
440 used to obtain the token if it was done outside of
441 NetIDMgr. So we use a heuristic here.
443 REQUIREMENT:
445 Elsewhere, (actually in afsnewcreds.c) just after obtaining
446 AFS tokens through NetIDMgr, we enumerate the AFS tokens
447 and assign the root identity (used to obtain new creds)
448 with the AFS tokens. This would still be there in the root
449 credential set when we list tokens later on.
451 HEURISTIC:
453 If there exists an AFS token in the root credential set for
454 the same cell, we associate this token with the same
455 identity as that credential.
457 cell = wcschr(crname, L'@');
458 if(cell) {
459 cell++;
460 if(!*cell)
461 cell = NULL;
464 ident = NULL;
465 if(cell) {
466 khm_handle c;
468 if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
469 afs_filter_by_cell,
470 (void *) cell,
471 &c, NULL))) {
472 khm_size cb;
474 kcdb_cred_get_identity(c, &ident);
475 cb = sizeof(method);
476 kcdb_cred_get_attr(c, afs_attr_method, NULL,
477 &method, &cb);
478 kcdb_cred_release(c);
482 /* If that failed, we have try another trick. If there is a
483 Krb5 ticket of the form afs/<cell>@<realm> or afs@<CELL>
484 where <cell> matches our cell, then we pick the identity
485 off of that.
487 ASSUMPTION:
489 If Krb5 was used to obtain the token, then there is a Krb5
490 ticket of the form afs/<cell>@<REALM> or afs@<CELL> still
491 in the cache. This is also true for Krb524 token
492 acquisition.
494 HEURISTIC:
496 If such a Krb5 ticket is found, use the identity of that
497 credential as the identity of the AFS token.
500 if (ident == NULL && cell != NULL) {
501 khm_handle c;
503 if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
504 afs_filter_krb5_tkt,
505 (void *) cell,
506 &c, NULL))) {
507 kcdb_cred_get_identity(c, &ident);
508 /* this could be Krb5 or Krb524, so we leave method at
509 AFS_TOKEN_AUTO. */
510 method = AFS_TOKEN_AUTO;
511 kcdb_cred_release(c);
515 /* If that didn't work either, we look for a Krb4 ticket of
516 the form afs.<cell>@<REALM> or afs@<CELL> which matches the
517 cell.
519 ASSUMPTION:
521 If Krb4 was used to obtain an AFS token, then there should
522 be a Krb4 ticket of the form afs.<cell>@<REALM> or
523 afs@<CELL> in the cache.
525 HEURISTIC:
527 If such a ticket is found, then use the identity of that
528 credential as the identity of the AFS token.
530 if (ident == NULL && cell != NULL) {
531 khm_handle c;
533 if (krb4_credtype_id < 0) {
534 kcdb_credtype_get_id(KRB4_CREDTYPE_NAME,
535 &krb4_credtype_id);
538 if (krb4_credtype_id >= 0 &&
539 KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
540 afs_filter_krb4_tkt,
541 (void *) cell,
542 &c, NULL))) {
544 kcdb_cred_get_identity(c, &ident);
545 kcdb_cred_release(c);
546 method = AFS_TOKEN_KRB4;
551 /* Finally, we allow any extension plugins to give this a shot */
552 if (ident == NULL && cell != NULL) {
553 afs_ext_resolve_token(cell,
554 &atoken,
555 &aserver,
556 &aclient,
557 &ident,
558 &method);
561 /* One more thing to try. If we have a cell->identity
562 mapping, then we try that. */
563 if (ident == NULL && cell != NULL) {
564 khm_handle h_cellmap;
565 wchar_t tidname[KCDB_IDENT_MAXCCH_NAME];
566 khm_size cb;
568 cb = sizeof(tidname);
570 if (KHM_SUCCEEDED(khc_open_space(csp_afscred,
571 L"Cells", 0,
572 &h_cellmap))) {
573 if (KHM_SUCCEEDED(khc_read_string(h_cellmap,
574 cell,
575 tidname,
576 &cb))) {
577 kcdb_identity_create(tidname,
578 KCDB_IDENT_FLAG_CREATE,
579 &ident);
581 khc_close_space(h_cellmap);
585 /* all else failed */
586 if(ident == NULL) {
587 if(KHM_FAILED(kcdb_identity_create(idname,
588 KCDB_IDENT_FLAG_CREATE,
589 &ident)))
590 goto _exit;
593 if(KHM_FAILED(kcdb_cred_create(crname, ident, afs_credtype_id, &cred)))
594 goto _exit;
596 kcdb_cred_set_attr(cred, afs_attr_method, &method, sizeof(method));
598 TimetToFileTime(atoken.endTime, &ft);
599 kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &ft, sizeof(ft));
600 if (atoken.startTime != 0) {
601 TimetToFileTime(atoken.startTime, &ft);
602 kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft));
604 kcdb_cred_set_attr(cred, afs_attr_client_princ,
605 &aclient, sizeof(aclient));
606 kcdb_cred_set_attr(cred, afs_attr_server_princ,
607 &aserver, sizeof(aserver));
609 if(cell) {
610 kcdb_cred_set_attr(cred, afs_attr_cell, cell, (khm_size)KCDB_CBSIZE_AUTO);
613 kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION,
614 location, (khm_size)KCDB_CBSIZE_AUTO);
616 kcdb_credset_add_cred(afs_credset, cred, -1);
618 /* both these calls are NULL pointer safe */
619 kcdb_cred_release(cred);
620 cred = NULL;
621 kcdb_identity_release(ident);
622 ident = NULL;
625 _exit:
626 if(ident)
627 kcdb_identity_release(ident);
628 if(cred)
629 kcdb_cred_release(cred);
631 return(0);
635 #define ALLOW_REGISTER 1
636 static int
637 ViceIDToUsername(char *username,
638 char *realm_of_user,
639 char *realm_of_cell,
640 char * cell_to_use,
641 struct ktc_principal *aclient,
642 struct ktc_principal *aserver,
643 struct ktc_token *atoken)
645 static char lastcell[MAXCELLCHARS+1] = { 0 };
646 static char confname[512] = { 0 };
647 char username_copy[BUFSIZ];
648 long viceId = ANONYMOUSID; /* AFS uid of user */
649 int status = 0;
650 #ifdef ALLOW_REGISTER
651 afs_int32 id;
652 #endif /* ALLOW_REGISTER */
654 if (confname[0] == '\0') {
655 StringCbCopyA(confname, sizeof(confname), AFSDIR_CLIENT_ETC_DIRPATH);
658 StringCbCopyA(lastcell, sizeof(lastcell), aserver->cell);
660 if (!pr_Initialize (0, confname, aserver->cell)) {
661 char sname[PR_MAXNAMELEN];
662 StringCbCopyA(sname, sizeof(sname), username);
663 status = pr_SNameToId (sname, &viceId);
664 pr_End();
667 #ifdef AFS_ID_TO_NAME
669 * This is a crock, but it is Transarc's crock, so
670 * we have to play along in order to get the
671 * functionality. The way the afs id is stored is
672 * as a string in the username field of the token.
673 * Contrary to what you may think by looking at
674 * the code for tokens, this hack (AFS ID %d) will
675 * not work if you change %d to something else.
677 #endif /* AFS_ID_TO_NAME */
679 * This code is taken from cklog -- it lets people
680 * automatically register with the ptserver in foreign cells
683 /* copy the username because pr_CreateUser will lowercase it */
684 StringCbCopyA(username_copy, BUFSIZ, username);
686 #ifdef ALLOW_REGISTER
687 if (status == 0) {
688 if (viceId != ANONYMOUSID) {
689 #else /* ALLOW_REGISTER */
690 if ((status == 0) && (viceId != ANONYMOUSID))
691 #endif /* ALLOW_REGISTER */
693 #ifdef AFS_ID_TO_NAME
694 StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
695 #endif /* AFS_ID_TO_NAME */
697 #ifdef ALLOW_REGISTER
698 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
699 id = 0;
700 StringCbCopyA(aclient->name, sizeof(aclient->name), username);
701 StringCbCopyA(aclient->instance, sizeof(aclient->instance), "");
702 StringCbCopyA(aclient->cell, sizeof(aclient->cell), realm_of_user);
703 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
704 return status;
705 if (status = pr_Initialize(1L, confname, aserver->cell))
706 return status;
707 status = pr_CreateUser(username, &id);
708 pr_End();
709 StringCbCopyA(username, BUFSIZ, username_copy);
710 #ifdef AFS_ID_TO_NAME
711 StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
712 #endif /* AFS_ID_TO_NAME */
715 #endif /* ALLOW_REGISTER */
716 return status;
720 static void
721 copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) {
722 krb5_error_code code;
723 krb5_ticket *ticket;
724 size_t len;
726 code = pkrb5_decode_ticket(&v5cred->ticket, &ticket);
727 if (code == 0) {
728 len = krb5_princ_realm(context, ticket->server)->length;
729 if (len > destlen - 1)
730 len = destlen - 1;
732 StringCbCopyA(dest, len, krb5_princ_realm(context, ticket->server)->data);
734 pkrb5_free_ticket(context, ticket);
739 afs_klog(khm_handle identity,
740 char *service,
741 char *cell,
742 char *realm,
743 int LifeTime,
744 afs_tk_method method,
745 time_t * tok_expiration,
746 char *linkedCell) {
748 long rc;
749 CREDENTIALS creds;
750 struct ktc_principal aserver;
751 struct ktc_principal aclient;
752 char realm_of_user[MAXKTCREALMLEN]; /* Kerberos realm of user */
753 char realm_of_cell[MAXKTCREALMLEN]; /* Kerberos realm of cell */
754 char local_cell[MAXCELLCHARS+1];
755 char Dmycell[MAXCELLCHARS+1];
756 struct ktc_token atoken;
757 struct ktc_token btoken;
758 afs_conf_cell ak_cellconfig; /* General information about the cell */
759 char RealmName[128];
760 char CellName[128];
761 char ServiceName[128];
762 khm_handle confighandle = NULL;
763 khm_int32 supports_krb4 = (pkrb_get_tf_realm == NULL ? 0 : 1);
764 khm_int32 got524cred = 0;
766 /* signalling */
767 BOOL bGotCreds = FALSE; /* got creds? */
769 if (tok_expiration)
770 *tok_expiration = (time_t) 0;
772 if (!afs_is_running()) {
773 _report_sr0(KHERR_WARNING, IDS_ERR_NOSERVICE);
774 return(0);
777 if ( !realm ) realm = "";
778 if ( !cell ) cell = "";
779 if ( !service ) service = "";
781 memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
782 memset(RealmName, '\0', sizeof(RealmName));
783 memset(CellName, '\0', sizeof(CellName));
784 memset(ServiceName, '\0', sizeof(ServiceName));
785 memset(realm_of_user, '\0', sizeof(realm_of_user));
786 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
787 memset(Dmycell, '\0', sizeof(Dmycell));
789 // NULL or empty cell returns information on local cell
790 if (cell && cell[0])
791 StringCbCopyA(Dmycell, sizeof(Dmycell), cell);
793 rc = afs_get_cellconfig(Dmycell, &ak_cellconfig, local_cell);
794 if (rc) {
795 _reportf(L"afs_get_cellconfig returns %ld", rc);
797 _report_sr2(KHERR_ERROR, IDS_ERR_CELLCONFIG, _cstr(Dmycell), _int32(rc));
798 _suggest_sr(IDS_ERR_CELLCONFIG_S, KHERR_SUGGEST_NONE);
799 _resolve();
800 return(rc);
803 if (linkedCell && ak_cellconfig.linkedCell)
804 StringCbCopyA(linkedCell, MAXCELLCHARS,
805 ak_cellconfig.linkedCell);
807 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
808 afs_realm_of_cell(&ak_cellconfig, FALSE));
810 if (strlen(service) == 0)
811 StringCbCopyA(ServiceName, sizeof(ServiceName), "afs");
812 else
813 StringCbCopyA(ServiceName, sizeof(ServiceName), service);
815 if (strlen(cell) == 0)
816 StringCbCopyA(CellName, sizeof(CellName), local_cell);
817 else
818 StringCbCopyA(CellName, sizeof(CellName), cell);
820 if (strlen(realm) == 0)
821 StringCbCopyA(RealmName, sizeof(RealmName), realm_of_cell);
822 else
823 StringCbCopyA(RealmName, sizeof(RealmName), realm);
825 memset(&creds, '\0', sizeof(creds));
827 /*** Kerberos 5 and 524 ***/
829 if (method == AFS_TOKEN_AUTO ||
830 method == AFS_TOKEN_KRB5 ||
831 method == AFS_TOKEN_KRB524) {
833 krb5_context context = 0;
834 krb5_ccache k5cc = 0;
835 krb5_creds increds;
836 krb5_creds * k5creds = 0;
837 krb5_error_code r;
838 krb5_principal client_principal = 0;
839 krb5_flags flags = 0;
841 int retry = 0;
842 int len;
843 char *p;
845 _reportf(L"Trying Kerberos 5");
847 if (!(r = khm_krb5_initialize(identity, &context, &k5cc))) {
848 int i;
850 memset(&increds, 0, sizeof(increds));
852 r = pkrb5_cc_get_principal(context, k5cc, &client_principal);
853 if (!r) {
854 i = krb5_princ_realm(context, client_principal)->length;
855 if (i > MAXKTCREALMLEN-1)
856 i = MAXKTCREALMLEN-1;
857 StringCchCopyNA(realm_of_user, ARRAYLENGTH(realm_of_user),
858 krb5_princ_realm(context, client_principal)->data,
860 } else {
861 _reportf(L"krb5_cc_get_principal returns code %d", r);
862 goto try_krb4;
864 } else {
865 _reportf(L"khm_krb5_initialize returns code %d", r);
866 goto try_krb4;
869 increds.client = client_principal;
870 increds.times.endtime = 0;
871 /* Ask for DES since that is what V4 understands */
872 increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
874 #ifdef KRB5_TC_NOTICKET
875 flags = KRB5_TC_OPENCLOSE;
876 r = pkrb5_cc_set_flags(context, k5cc, flags);
877 #endif
878 if (strlen(realm) != 0) {
879 retry_retcred_1:
880 /* First try Service/Cell@REALM */
881 if (r = pkrb5_build_principal(context, &increds.server,
882 (int) strlen(realm),
883 realm,
884 ServiceName,
885 CellName,
886 0)) {
887 _reportf(L"krb5_build_principal returns %d", r);
888 goto end_krb5;
891 r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
892 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
893 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
894 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
895 /* Next try Service@REALM */
896 pkrb5_free_principal(context, increds.server);
897 r = pkrb5_build_principal(context, &increds.server,
898 (int) strlen(realm),
899 realm,
900 ServiceName,
902 if (r == 0)
903 r = pkrb5_get_credentials(context, 0, k5cc,
904 &increds, &k5creds);
907 /* Check to make sure we received a valid ticket; if not remove it
908 * and try again. Perhaps there are two service tickets for the
909 * same service in the ccache.
911 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
912 pkrb5_free_principal(context, increds.server);
913 pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
914 pkrb5_free_creds(context, k5creds);
915 k5creds = NULL;
916 goto retry_retcred_1;
918 } else {
919 retry_retcred_2:
920 /* First try Service/Cell@_CLIENT_REALM */
921 if (r = pkrb5_build_principal(context, &increds.server,
922 (int) strlen(realm_of_user),
923 realm_of_user,
924 ServiceName,
925 CellName,
926 0)) {
927 _reportf(L"krb5_build_principal returns %d", r);
928 goto end_krb5;
931 r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
932 if (r == 0) {
933 /* the user realm is a valid cell realm */
934 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell), realm_of_user);
936 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
937 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
938 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
939 pkrb5_free_principal(context, increds.server);
940 r = pkrb5_build_principal(context, &increds.server,
941 (int) strlen(realm_of_cell),
942 realm_of_cell,
943 ServiceName,
944 CellName,
946 if (r == 0)
947 r = pkrb5_get_credentials(context, 0, k5cc,
948 &increds, &k5creds);
950 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
951 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
952 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
953 strlen(realm_of_cell) == 0) {
954 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
955 afs_realm_of_cell(&ak_cellconfig, TRUE));
957 pkrb5_free_principal(context, increds.server);
958 r = pkrb5_build_principal(context, &increds.server,
959 (int) strlen(realm_of_cell),
960 realm_of_cell,
961 ServiceName,
962 CellName,
964 if (r == 0)
965 r = pkrb5_get_credentials(context, 0, k5cc,
966 &increds, &k5creds);
968 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
969 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
970 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
971 /* Next try Service@REALM */
972 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
973 afs_realm_of_cell(&ak_cellconfig, FALSE));
975 pkrb5_free_principal(context, increds.server);
976 r = pkrb5_build_principal(context, &increds.server,
977 (int) strlen(realm_of_cell),
978 realm_of_cell,
979 ServiceName,
981 if (r == 0)
982 r = pkrb5_get_credentials(context, 0, k5cc,
983 &increds, &k5creds);
985 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
986 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
987 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
988 strlen(realm_of_cell) == 0) {
989 /* Next try Service@REALM */
990 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
991 afs_realm_of_cell(&ak_cellconfig, TRUE));
993 pkrb5_free_principal(context, increds.server);
994 r = pkrb5_build_principal(context, &increds.server,
995 (int) strlen(realm_of_cell),
996 realm_of_cell,
997 ServiceName,
999 if (r == 0)
1000 r = pkrb5_get_credentials(context, 0, k5cc,
1001 &increds, &k5creds);
1004 if (r == 0 && strlen(realm_of_cell) == 0)
1005 copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
1007 /* Check to make sure we received a valid ticket; if not remove it
1008 * and try again. Perhaps there are two service tickets for the
1009 * same service in the ccache.
1011 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
1012 pkrb5_free_principal(context, increds.server);
1013 pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
1014 pkrb5_free_creds(context, k5creds);
1015 k5creds = NULL;
1016 goto retry_retcred_2;
1020 pkrb5_free_principal(context, increds.server);
1021 pkrb5_free_principal(context, client_principal);
1022 client_principal = 0;
1023 #ifdef KRB5_TC_NOTICKET
1024 flags = KRB5_TC_OPENCLOSE | KRB5_TC_NOTICKET;
1025 pkrb5_cc_set_flags(context, k5cc, flags);
1026 #endif
1028 (void) pkrb5_cc_close(context, k5cc);
1029 k5cc = 0;
1031 if (r) {
1032 _reportf(L"Code %d while getting credentials", r);
1033 k5creds = NULL;
1034 goto end_krb5;
1037 if ( k5creds->ticket.length > MAXKTCTICKETLEN ||
1038 method == AFS_TOKEN_KRB524) {
1039 goto try_krb524d;
1042 /* This code inserts the entire K5 ticket into the token */
1044 _reportf(L"Trying K5 SetToken");
1046 memset(&aserver, '\0', sizeof(aserver));
1047 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1048 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1050 memset(&atoken, '\0', sizeof(atoken));
1051 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
1052 atoken.startTime = k5creds->times.starttime;
1053 atoken.endTime = k5creds->times.endtime;
1054 memcpy(&atoken.sessionKey,
1055 k5creds->keyblock.contents,
1056 k5creds->keyblock.length);
1057 atoken.ticketLen = k5creds->ticket.length;
1058 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
1060 if (tok_expiration)
1061 *tok_expiration = k5creds->times.endtime;
1063 retry_gettoken5:
1064 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
1065 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
1066 if ( rc == KTC_NOCM && retry < 20 ) {
1067 Sleep(500);
1068 retry++;
1069 goto retry_gettoken5;
1071 goto try_krb524d;
1074 if (atoken.kvno == btoken.kvno &&
1075 atoken.ticketLen == btoken.ticketLen &&
1076 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1077 sizeof(atoken.sessionKey)) &&
1078 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1080 /* success */
1081 if (k5creds && context)
1082 pkrb5_free_creds(context, k5creds);
1084 if (context)
1085 pkrb5_free_context(context);
1087 _reportf(L"Same token already exists");
1089 rc = 0;
1090 goto cleanup;
1093 // * Reset the "aclient" structure before we call ktc_SetToken.
1094 // * This structure was first set by the ktc_GetToken call when
1095 // * we were comparing whether identical tokens already existed.
1097 len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
1098 StringCchCopyNA(aclient.name, MAXKTCNAMELEN,
1099 k5creds->client->data[0].data, len);
1101 if ( k5creds->client->length > 1 ) {
1102 StringCbCatA(aclient.name, sizeof(aclient.name), ".");
1103 p = aclient.name + strlen(aclient.name);
1104 len = (int) min(k5creds->client->data[1].length,
1105 MAXKTCNAMELEN - strlen(aclient.name) - 1);
1106 StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
1107 k5creds->client->data[1].data, len);
1110 aclient.instance[0] = '\0';
1112 StringCbCopyA(aclient.cell, sizeof(aclient.cell), realm_of_cell);
1114 StringCbCatA(aclient.name, sizeof(aclient.name), "@");
1115 p = aclient.name + strlen(aclient.name);
1116 len = (int) min(k5creds->client->realm.length,
1117 MAXKTCNAMELEN - strlen(aclient.name) - 1);
1118 StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
1119 k5creds->client->realm.data, len);
1121 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1122 &aclient, &aserver, &atoken);
1124 rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
1125 if (!rc) {
1126 /* success */
1128 if (k5creds && context)
1129 pkrb5_free_creds(context, k5creds);
1131 if (context)
1132 pkrb5_free_context(context);
1134 goto cleanup;
1137 _reportf(L"SetToken returns code %d", rc);
1139 try_krb524d:
1141 _reportf(L"Trying Krb524");
1143 if (pkrb524_convert_creds_kdc &&
1144 (method == AFS_TOKEN_AUTO || method == AFS_TOKEN_KRB524)) {
1145 /* This requires krb524d to be running with the KDC */
1146 r = pkrb524_convert_creds_kdc(context, k5creds, &creds);
1147 if (r) {
1148 _reportf(L"Code %d while converting credentials", r);
1149 goto end_krb5;
1151 rc = KSUCCESS;
1152 got524cred = 1;
1153 bGotCreds = TRUE;
1156 end_krb5:
1157 if (client_principal)
1158 pkrb5_free_principal(context, client_principal);
1160 if (k5creds && context)
1161 pkrb5_free_creds(context, k5creds);
1163 if (context)
1164 pkrb5_free_context(context);
1167 /* Kerberos 4 */
1168 try_krb4:
1170 if (supports_krb4) {
1171 kcdb_identity_get_config(identity, 0, &confighandle);
1172 khc_read_int32(confighandle, L"Krb4Cred\\Krb4NewCreds", &supports_krb4);
1173 khc_close_space(confighandle);
1176 if (!supports_krb4)
1177 _reportf(L"Kerberos 4 not configured");
1179 if (!bGotCreds && supports_krb4 &&
1180 strlen(RealmName) < REALM_SZ &&
1181 (method == AFS_TOKEN_AUTO ||
1182 method == AFS_TOKEN_KRB4)) {
1184 KTEXT_ST ticket;
1186 _reportf(L"Trying Kerberos 4");
1188 if (!realm_of_user[0] ) {
1189 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user))
1190 != KSUCCESS) {
1191 /* can't determine realm of user */
1192 _reportf(L"krb_get_tf_realm returns %d", rc);
1193 goto end_krb4;
1197 _reportf(L"Trying to find %S.%S@%S", ServiceName, CellName, RealmName);
1198 rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
1199 if (rc == NO_TKT_FIL) {
1200 // if the problem is that we have no krb4 tickets
1201 // do not attempt to continue
1202 _reportf(L"krb_get_cred returns %d (no ticket file)", rc);
1203 goto end_krb4;
1206 if (rc != KSUCCESS) {
1207 _reportf(L"Trying to find %S@%S", ServiceName, RealmName);
1208 rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
1211 if (rc != KSUCCESS) {
1212 _reportf(L"Trying to obtain new ticket");
1213 if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1214 CellName, RealmName, 0))
1215 == KSUCCESS) {
1216 if ((rc = (*pkrb_get_cred)(ServiceName, CellName,
1217 RealmName, &creds)) != KSUCCESS) {
1218 goto end_krb4;
1219 } else {
1220 _reportf(L"Got %S.%S@%S", ServiceName, CellName, RealmName);
1222 } else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1223 "", RealmName, 0))
1224 == KSUCCESS) {
1225 if ((rc = (*pkrb_get_cred)(ServiceName, "",
1226 RealmName, &creds)) != KSUCCESS) {
1227 goto end_krb4;
1228 } else {
1229 _reportf(L"Got %S@%S", ServiceName, RealmName);
1231 } else {
1232 goto end_krb4;
1236 bGotCreds = TRUE;
1238 end_krb4:
1242 if (bGotCreds) {
1244 memset(&aserver, '\0', sizeof(aserver));
1245 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1246 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1248 memset(&atoken, '\0', sizeof(atoken));
1249 atoken.kvno = (short)creds.kvno;
1250 atoken.startTime = creds.issue_date;
1251 atoken.endTime = (*pkrb_life_to_time)(creds.issue_date,creds.lifetime);
1252 memcpy(&atoken.sessionKey, creds.session, 8);
1253 atoken.ticketLen = creds.ticket_st.length;
1254 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
1256 if (tok_expiration)
1257 *tok_expiration = atoken.endTime;
1259 if (!(rc = ktc_GetToken(&aserver, &btoken,
1260 sizeof(btoken), &aclient)) &&
1261 atoken.kvno == btoken.kvno &&
1262 atoken.ticketLen == btoken.ticketLen &&
1263 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1264 sizeof(atoken.sessionKey)) &&
1265 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1267 /* success! */
1268 rc = 0;
1269 goto cleanup;
1272 // Reset the "aclient" structure before we call ktc_SetToken.
1273 // This structure was first set by the ktc_GetToken call when
1274 // we were comparing whether identical tokens already existed.
1276 StringCchCopyA(aclient.name, MAXKTCNAMELEN, creds.pname);
1277 if (creds.pinst[0]) {
1278 StringCchCatA(aclient.name, MAXKTCNAMELEN, ".");
1279 StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.pinst);
1282 StringCbCopyA(aclient.instance, sizeof(aclient.instance), "");
1284 StringCchCatA(aclient.name, MAXKTCNAMELEN, "@");
1285 StringCchCatA(aclient.name, MAXKTCNAMELEN, got524cred ? realm_of_user : creds.realm);
1287 StringCbCopyA(aclient.cell, sizeof(aclient.cell), CellName);
1289 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1290 &aclient, &aserver, &atoken);
1292 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
1293 afs_report_error(rc, "ktc_SetToken()");
1294 goto cleanup;
1296 } else if (method == AFS_TOKEN_AUTO ||
1297 method >= AFS_TOKEN_USER) {
1298 /* we couldn't get a token using Krb5, Krb524 or Krb4, either
1299 because we couldn't get the necessary credentials or
1300 because the method was set to not use those. Now we
1301 dispatch to any extensions to see if they have better
1302 luck. */
1304 rc = !afs_ext_klog(method,
1305 identity,
1306 ServiceName,
1307 CellName,
1308 RealmName,
1309 &ak_cellconfig,
1310 LifeTime);
1311 } else {
1312 /* if the return code was not set, we should set it now.
1313 Otherwise we let the code go through. */
1314 if (!rc) {
1315 /* No tokens were obtained. We should report something */
1316 _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
1317 _cptr(CellName));
1318 _resolve();
1320 rc = KHM_ERROR_GENERAL;
1324 cleanup:
1325 if (ak_cellconfig.linkedCell)
1326 free(ak_cellconfig.linkedCell);
1328 return rc;
1331 /**************************************/
1332 /* afs_realm_of_cell(): */
1333 /**************************************/
1334 static char *
1335 afs_realm_of_cell(afs_conf_cell *cellconfig, BOOL referral_fallback)
1337 char krbhst[MAX_HSTNM]="";
1338 static char krbrlm[MAXKTCREALMLEN+1]="";
1339 krb5_context ctx = 0;
1340 char ** realmlist=NULL;
1341 krb5_error_code r = 0;
1343 if (!cellconfig)
1344 return 0;
1346 if (referral_fallback) {
1347 char * p;
1348 p = strchr(cellconfig->hostName[0], '.');
1349 if (p++)
1350 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1351 else
1352 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1353 #if _MSC_VER >= 1400
1354 _strupr_s(krbrlm, sizeof(krbrlm));
1355 #else
1356 _strupr(krbrlm);
1357 #endif
1358 } else {
1359 if ( pkrb5_init_context ) {
1360 r = pkrb5_init_context(&ctx);
1361 if ( !r )
1362 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
1363 if ( !r && realmlist && realmlist[0] ) {
1364 StringCbCopyA(krbrlm, sizeof(krbrlm), realmlist[0]);
1365 pkrb5_free_host_realm(ctx, realmlist);
1367 if (ctx)
1368 pkrb5_free_context(ctx);
1371 if (r) {
1372 if (pkrb_get_krbhst && pkrb_realmofhost) {
1373 StringCbCopyA(krbrlm, sizeof(krbrlm),
1374 (char *)(*pkrb_realmofhost)(cellconfig->hostName[0]));
1375 if ((*pkrb_get_krbhst)(krbhst, krbrlm, 1) != KSUCCESS)
1376 krbrlm[0] = '\0';
1379 if ( !krbrlm[0] ) {
1380 char * p;
1381 p = strchr(cellconfig->hostName[0], '.');
1382 if (p++)
1383 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1384 else
1385 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1386 #if _MSC_VER >= 1400
1387 _strupr_s(krbrlm, sizeof(krbrlm));
1388 #else
1389 _strupr(krbrlm);
1390 #endif
1394 return(krbrlm);
1397 /**************************************/
1398 /* afs_get_cellconfig(): */
1399 /**************************************/
1400 static int
1401 afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
1403 int rc;
1404 int ttl = 0;
1405 char linkedCell[MAXCELLCHARS]="";
1407 local_cell[0] = (char)0;
1408 memset(cellconfig, 0, sizeof(*cellconfig));
1410 cellconfig->cbsize = sizeof(*cellconfig);
1412 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
1413 if (rc = cm_GetRootCellName(local_cell)) {
1414 return(rc);
1417 if (strlen(cell) == 0)
1418 StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
1420 StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
1422 rc = cm_SearchCellRegistry(1, cell, NULL, linkedCell,
1423 afs_get_cellconfig_callback, (void*) cellconfig);
1424 if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
1425 rc = cm_SearchCellFileEx(cell, NULL, linkedCell, afs_get_cellconfig_callback,
1426 (void*)cellconfig);
1427 if(rc)
1428 rc = cm_SearchCellByDNS(cell, NULL, &ttl,
1429 afs_get_cellconfig_callback,
1430 (void*) cellconfig);
1432 if (linkedCell[0])
1433 cellconfig->linkedCell = _strdup(linkedCell);
1435 return rc;
1438 /**************************************/
1439 /* afs_get_cellconfig_callback(): */
1440 /**************************************/
1441 static long
1442 afs_get_cellconfig_callback(void *cellconfig,
1443 struct sockaddr_in *addrp,
1444 char *namep,
1445 unsigned short ipRank)
1447 afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
1449 cc->hostAddr[cc->numServers] = *addrp;
1450 StringCbCopyA(cc->hostName[cc->numServers],
1451 sizeof(cc->hostName[0]), namep);
1452 cc->numServers++;
1453 return(0);
1457 /**************************************/
1458 /* afs_report_error(): */
1459 /**************************************/
1460 void
1461 afs_report_error(LONG rc, LPCSTR FailedFunctionName)
1463 char message[256];
1464 const char *errText;
1466 // Using AFS defines as error messages for now, until Transarc
1467 // gets back to me with "string" translations of each of these
1468 // const. defines.
1469 if (rc == KTC_ERROR)
1470 errText = "KTC_ERROR";
1471 else if (rc == KTC_TOOBIG)
1472 errText = "KTC_TOOBIG";
1473 else if (rc == KTC_INVAL)
1474 errText = "KTC_INVAL";
1475 else if (rc == KTC_NOENT)
1476 errText = "KTC_NOENT";
1477 else if (rc == KTC_PIOCTLFAIL)
1478 errText = "KTC_PIOCTLFAIL";
1479 else if (rc == KTC_NOPIOCTL)
1480 errText = "KTC_NOPIOCTL";
1481 else if (rc == KTC_NOCELL)
1482 errText = "KTC_NOCELL";
1483 else if (rc == KTC_NOCM)
1484 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
1485 else
1486 errText = "Unknown error!";
1488 StringCbPrintfA(message, sizeof(message),
1489 "%s\n(%s failed)", errText, FailedFunctionName);
1490 _report_cs1(KHERR_ERROR, L"%1!S!", _cptr(message));
1491 _resolve();
1492 return;
1495 DWORD
1496 GetServiceStatus(LPSTR lpszMachineName,
1497 LPSTR lpszServiceName,
1498 DWORD *lpdwCurrentState,
1499 DWORD *lpdwWaitHint)
1501 DWORD hr = NOERROR;
1502 SC_HANDLE schSCManager = NULL;
1503 SC_HANDLE schService = NULL;
1504 DWORD fdwDesiredAccess = 0;
1505 SERVICE_STATUS ssServiceStatus = {0};
1506 BOOL fRet = FALSE;
1508 *lpdwCurrentState = 0;
1510 fdwDesiredAccess = GENERIC_READ;
1512 schSCManager = OpenSCManagerA(lpszMachineName,
1513 NULL,
1514 fdwDesiredAccess);
1516 if(schSCManager == NULL) {
1517 hr = GetLastError();
1518 goto cleanup;
1521 schService = OpenServiceA(schSCManager,
1522 lpszServiceName,
1523 fdwDesiredAccess);
1525 if(schService == NULL) {
1526 hr = GetLastError();
1527 goto cleanup;
1530 fRet = QueryServiceStatus(schService,
1531 &ssServiceStatus);
1533 if(fRet == FALSE) {
1534 hr = GetLastError();
1535 goto cleanup;
1538 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
1539 if (lpdwWaitHint)
1540 *lpdwWaitHint = ssServiceStatus.dwWaitHint;
1541 cleanup:
1543 CloseServiceHandle(schService);
1544 CloseServiceHandle(schSCManager);
1546 return(hr);
1549 DWORD ServiceControl(LPSTR lpszMachineName,
1550 LPSTR lpszServiceName,
1551 DWORD dwNewState) {
1553 DWORD hr = NOERROR;
1554 SC_HANDLE schSCManager = NULL;
1555 SC_HANDLE schService = NULL;
1556 DWORD fdwDesiredAccess = 0;
1557 SERVICE_STATUS ssServiceStatus = {0};
1558 BOOL fRet = FALSE;
1559 DWORD dwCurrentState = 0;
1561 dwCurrentState = 0;
1563 fdwDesiredAccess = GENERIC_READ;
1565 schSCManager = OpenSCManagerA(lpszMachineName, NULL,
1566 fdwDesiredAccess);
1568 if(schSCManager == NULL) {
1569 hr = GetLastError();
1570 goto cleanup;
1573 fdwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
1575 schService = OpenServiceA(schSCManager, lpszServiceName,
1576 fdwDesiredAccess);
1578 if(schService == NULL) {
1579 hr = GetLastError();
1580 goto cleanup;
1583 fRet = QueryServiceStatus(schService, &ssServiceStatus);
1585 if(fRet == FALSE) {
1586 hr = GetLastError();
1587 goto cleanup;
1590 dwCurrentState = ssServiceStatus.dwCurrentState;
1592 if (dwCurrentState == SERVICE_STOPPED &&
1593 dwNewState == SERVICE_RUNNING) {
1595 fRet = StartService(schService, 0, NULL);
1597 if (fRet == FALSE) {
1598 hr = GetLastError();
1599 goto cleanup;
1603 if (dwCurrentState == SERVICE_RUNNING &&
1604 dwNewState == SERVICE_STOPPED) {
1605 fRet = ControlService(schService, SERVICE_CONTROL_STOP,
1606 &ssServiceStatus);
1608 if (fRet == FALSE) {
1609 hr = GetLastError();
1610 goto cleanup;
1614 cleanup:
1616 CloseServiceHandle(schService);
1617 CloseServiceHandle(schSCManager);
1619 return(hr);
1622 khm_boolean
1623 afs_check_for_cell_realm_match(khm_handle identity, char * cell) {
1624 char local_cell[MAXCELLCHARS];
1625 wchar_t wrealm[MAXCELLCHARS];
1626 wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
1627 wchar_t * atsign;
1628 khm_size cb;
1629 char * realm;
1630 afs_conf_cell cellconfig;
1631 int rc;
1633 ZeroMemory(local_cell, sizeof(local_cell));
1634 ZeroMemory(&cellconfig, sizeof(cellconfig));
1636 rc = afs_get_cellconfig(cell, &cellconfig, local_cell);
1637 if (rc)
1638 return FALSE;
1640 realm = afs_realm_of_cell(&cellconfig, FALSE);
1641 if (cellconfig.linkedCell)
1642 free(cellconfig.linkedCell);
1643 if (!realm[0]) /* referral; assume it matches */
1644 return TRUE;
1646 AnsiStrToUnicode(wrealm, sizeof(wrealm), realm);
1648 cb = sizeof(idname);
1649 idname[0] = L'\0';
1650 kcdb_identity_get_name(identity, idname, &cb);
1652 atsign = wcschr(idname, L'@');
1653 if (atsign && atsign[1] && !_wcsicmp(atsign + 1, wrealm)) {
1654 return TRUE;
1655 } else {
1656 return FALSE;