LINUX: afs_create infinite fetchStatus loop
[pkg-k5-afs_openafs.git] / src / WINNT / netidmgr_plugin / afsfuncs.c
blobdb9b72550b0709479946c21be2c55ea4d93a332a
1 /*
2 * Copyright (c) 2005-2011 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 = krb5_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 krb5_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 Ticket ticket;
723 size_t len;
724 int ret;
726 ret = decode_Ticket(v5cred->ticket.data, v5cred->ticket.length,
727 &ticket, &len);
728 if (ret == 0) {
729 StringCbCopyA(dest, destlen, ticket.realm);
731 free_Ticket(&ticket);
736 afs_klog(khm_handle identity,
737 char *service,
738 char *cell,
739 char *realm,
740 int LifeTime,
741 afs_tk_method method,
742 time_t * tok_expiration,
743 char *linkedCell) {
745 long rc;
746 #ifdef USE_KRB4
747 CREDENTIALS creds;
748 #endif
749 struct ktc_principal aserver;
750 struct ktc_principal aclient;
751 char realm_of_user[MAXKTCREALMLEN]; /* Kerberos realm of user */
752 char realm_of_cell[MAXKTCREALMLEN]; /* Kerberos realm of cell */
753 char local_cell[MAXCELLCHARS+1];
754 char Dmycell[MAXCELLCHARS+1];
755 struct ktc_token atoken;
756 struct ktc_token btoken;
757 afs_conf_cell ak_cellconfig; /* General information about the cell */
758 char RealmName[128];
759 char CellName[128];
760 char ServiceName[128];
761 khm_handle confighandle = NULL;
762 #ifdef USE_KRB4
763 khm_int32 supports_krb4 = (pkrb_get_tf_realm == NULL ? 0 : 1);
764 khm_int32 got524cred = 0;
765 #endif
767 /* signalling */
768 BOOL bGotCreds = FALSE; /* got creds? */
770 if (tok_expiration)
771 *tok_expiration = (time_t) 0;
773 if (!afs_is_running()) {
774 _report_sr0(KHERR_WARNING, IDS_ERR_NOSERVICE);
775 return(0);
778 if ( !realm ) realm = "";
779 if ( !cell ) cell = "";
780 if ( !service ) service = "";
782 memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
783 memset(RealmName, '\0', sizeof(RealmName));
784 memset(CellName, '\0', sizeof(CellName));
785 memset(ServiceName, '\0', sizeof(ServiceName));
786 memset(realm_of_user, '\0', sizeof(realm_of_user));
787 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
788 memset(Dmycell, '\0', sizeof(Dmycell));
790 // NULL or empty cell returns information on local cell
791 if (cell && cell[0])
792 StringCbCopyA(Dmycell, sizeof(Dmycell), cell);
794 rc = afs_get_cellconfig(Dmycell, &ak_cellconfig, local_cell);
795 if (rc) {
796 _reportf(L"afs_get_cellconfig returns %ld", rc);
798 _report_sr2(KHERR_ERROR, IDS_ERR_CELLCONFIG, _cstr(Dmycell), _int32(rc));
799 _suggest_sr(IDS_ERR_CELLCONFIG_S, KHERR_SUGGEST_NONE);
800 _resolve();
801 return(rc);
804 if (linkedCell && ak_cellconfig.linkedCell)
805 StringCbCopyA(linkedCell, MAXCELLCHARS,
806 ak_cellconfig.linkedCell);
808 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
809 afs_realm_of_cell(&ak_cellconfig, FALSE));
811 if (strlen(service) == 0)
812 StringCbCopyA(ServiceName, sizeof(ServiceName), "afs");
813 else
814 StringCbCopyA(ServiceName, sizeof(ServiceName), service);
816 if (strlen(cell) == 0)
817 StringCbCopyA(CellName, sizeof(CellName), local_cell);
818 else
819 StringCbCopyA(CellName, sizeof(CellName), cell);
821 if (strlen(realm) == 0)
822 StringCbCopyA(RealmName, sizeof(RealmName), realm_of_cell);
823 else
824 StringCbCopyA(RealmName, sizeof(RealmName), realm);
826 #ifdef USE_KRB4
827 memset(&creds, '\0', sizeof(creds));
828 #endif
830 /*** Kerberos 5 and 524 ***/
832 if (method == AFS_TOKEN_AUTO ||
833 method == AFS_TOKEN_KRB5 ||
834 method == AFS_TOKEN_KRB524) {
836 krb5_context context = 0;
837 krb5_ccache k5cc = 0;
838 krb5_creds increds;
839 krb5_creds * k5creds = 0;
840 krb5_error_code r;
841 krb5_principal client_principal = 0;
842 krb5_flags flags = 0;
844 int retry = 0;
845 int len;
846 char *p;
848 _reportf(L"Trying Kerberos 5");
850 if (!(r = khm_krb5_initialize(identity, &context, &k5cc))) {
851 int i;
853 memset(&increds, 0, sizeof(increds));
855 r = krb5_cc_get_principal(context, k5cc, &client_principal);
856 if (!r) {
857 StringCchCopyA(realm_of_user, ARRAYLENGTH(realm_of_user),
858 krb5_principal_get_realm(context, client_principal));
859 } else {
860 _reportf(L"krb5_cc_get_principal returns code %d", r);
861 #ifdef USE_KRB4
862 goto try_krb4;
863 #else
864 goto end_krb5;
865 #endif
867 } else {
868 _reportf(L"khm_krb5_initialize returns code %d", r);
869 #ifdef USE_KRB4
870 goto try_krb4;
871 #else
872 goto end_krb5;
873 #endif
876 increds.client = client_principal;
877 increds.times.endtime = 0;
878 /* Ask for DES since that is what V4 understands */
879 if (method == AFS_TOKEN_KRB524)
880 increds.session.keytype = ENCTYPE_DES_CBC_CRC;
882 #ifdef KRB5_TC_NOTICKET
883 flags = KRB5_TC_OPENCLOSE;
884 r = krb5_cc_set_flags(context, k5cc, flags);
885 #endif
886 if (strlen(realm) != 0) {
887 retry_retcred_1:
888 /* First try Service/Cell@REALM */
889 if (r = krb5_build_principal(context, &increds.server,
890 (int) strlen(realm),
891 realm,
892 ServiceName,
893 CellName,
894 0)) {
895 _reportf(L"krb5_build_principal returns %d", r);
896 goto end_krb5;
899 r = krb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
900 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
901 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
902 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
903 /* Next try Service@REALM */
904 krb5_free_principal(context, increds.server);
905 r = krb5_build_principal(context, &increds.server,
906 (int) strlen(realm),
907 realm,
908 ServiceName,
910 if (r == 0)
911 r = krb5_get_credentials(context, 0, k5cc,
912 &increds, &k5creds);
915 /* Check to make sure we received a valid ticket; if not remove it
916 * and try again. Perhaps there are two service tickets for the
917 * same service in the ccache.
919 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
920 krb5_free_principal(context, increds.server);
921 krb5_cc_remove_cred(context, k5cc, 0, k5creds);
922 krb5_free_creds(context, k5creds);
923 k5creds = NULL;
924 goto retry_retcred_1;
926 } else {
927 retry_retcred_2:
928 /* First try Service/Cell@_CLIENT_REALM */
929 if (r = krb5_build_principal(context, &increds.server,
930 (int) strlen(realm_of_user),
931 realm_of_user,
932 ServiceName,
933 CellName,
934 0)) {
935 _reportf(L"krb5_build_principal returns %d", r);
936 goto end_krb5;
939 r = krb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
940 if (r == 0) {
941 /* the user realm is a valid cell realm */
942 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell), realm_of_user);
944 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
945 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
946 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
947 krb5_free_principal(context, increds.server);
948 r = krb5_build_principal(context, &increds.server,
949 (int) strlen(realm_of_cell),
950 realm_of_cell,
951 ServiceName,
952 CellName,
954 if (r == 0)
955 r = krb5_get_credentials(context, 0, k5cc,
956 &increds, &k5creds);
958 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
959 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
960 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
961 strlen(realm_of_cell) == 0) {
962 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
963 afs_realm_of_cell(&ak_cellconfig, TRUE));
965 krb5_free_principal(context, increds.server);
966 r = krb5_build_principal(context, &increds.server,
967 (int) strlen(realm_of_cell),
968 realm_of_cell,
969 ServiceName,
970 CellName,
972 if (r == 0)
973 r = krb5_get_credentials(context, 0, k5cc,
974 &increds, &k5creds);
976 if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
977 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
978 r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
979 /* Next try Service@REALM */
980 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
981 afs_realm_of_cell(&ak_cellconfig, FALSE));
983 krb5_free_principal(context, increds.server);
984 r = krb5_build_principal(context, &increds.server,
985 (int) strlen(realm_of_cell),
986 realm_of_cell,
987 ServiceName,
989 if (r == 0)
990 r = krb5_get_credentials(context, 0, k5cc,
991 &increds, &k5creds);
993 if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
994 r == KRB5_ERR_HOST_REALM_UNKNOWN ||
995 r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
996 strlen(realm_of_cell) == 0) {
997 /* Next try Service@REALM */
998 StringCbCopyA(realm_of_cell, sizeof(realm_of_cell),
999 afs_realm_of_cell(&ak_cellconfig, TRUE));
1001 krb5_free_principal(context, increds.server);
1002 r = krb5_build_principal(context, &increds.server,
1003 (int) strlen(realm_of_cell),
1004 realm_of_cell,
1005 ServiceName,
1007 if (r == 0)
1008 r = krb5_get_credentials(context, 0, k5cc,
1009 &increds, &k5creds);
1012 if (r == 0 && strlen(realm_of_cell) == 0)
1013 copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
1015 /* Check to make sure we received a valid ticket; if not
1016 * remove it and try again. Perhaps there are two service
1017 * tickets for the same service in the ccache.
1019 if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
1020 krb5_free_principal(context, increds.server);
1021 krb5_cc_remove_cred(context, k5cc, 0, k5creds);
1022 krb5_free_creds(context, k5creds);
1023 k5creds = NULL;
1024 goto retry_retcred_2;
1028 krb5_free_principal(context, increds.server);
1029 krb5_free_principal(context, client_principal);
1030 client_principal = 0;
1031 #ifdef KRB5_TC_NOTICKET
1032 flags = KRB5_TC_OPENCLOSE | KRB5_TC_NOTICKET;
1033 krb5_cc_set_flags(context, k5cc, flags);
1034 #endif
1036 (void) krb5_cc_close(context, k5cc);
1037 k5cc = 0;
1039 if (r) {
1040 _reportf(L"Code %d while getting credentials", r);
1041 k5creds = NULL;
1042 goto end_krb5;
1045 #ifdef USE_KRB4
1046 if ( k5creds->ticket.length > MAXKTCTICKETLEN ||
1047 method == AFS_TOKEN_KRB524) {
1048 goto try_krb524d;
1050 #endif
1052 /* This code inserts the entire K5 ticket into the token */
1054 _reportf(L"Trying K5 SetToken");
1056 memset(&aserver, '\0', sizeof(aserver));
1057 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1058 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1060 memset(&atoken, '\0', sizeof(atoken));
1061 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
1062 atoken.startTime = k5creds->times.starttime;
1063 atoken.endTime = k5creds->times.endtime;
1064 if (tkt_DeriveDesKey(k5creds->session.keytype,
1065 k5creds->session.keyvalue.data,
1066 k5creds->session.keyvalue.length,
1067 &atoken.sessionKey))
1068 goto cleanup;
1069 atoken.ticketLen = k5creds->ticket.length;
1070 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
1072 if (tok_expiration)
1073 *tok_expiration = k5creds->times.endtime;
1075 retry_gettoken5:
1076 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
1077 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
1078 if ( rc == KTC_NOCM && retry < 20 ) {
1079 Sleep(500);
1080 retry++;
1081 goto retry_gettoken5;
1083 #ifdef USE_KRB4
1084 goto try_krb524d;
1085 #else
1086 goto end_krb5;
1087 #endif
1090 if (atoken.kvno == btoken.kvno &&
1091 atoken.ticketLen == btoken.ticketLen &&
1092 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1093 sizeof(atoken.sessionKey)) &&
1094 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1096 /* success */
1097 if (k5creds && context)
1098 krb5_free_creds(context, k5creds);
1100 if (context)
1101 krb5_free_context(context);
1103 _reportf(L"Same token already exists");
1105 rc = 0;
1106 goto cleanup;
1109 // * Reset the "aclient" structure before we call ktc_SetToken.
1110 // * This structure was first set by the ktc_GetToken call when
1111 // * we were comparing whether identical tokens already existed.
1113 StringCchCopyA(aclient.name, MAXKTCNAMELEN,
1114 krb5_principal_get_comp_string(context, k5creds->client, 0));
1116 if ( krb5_principal_get_num_comp(context, k5creds->client) > 1 ) {
1117 StringCbCatA(aclient.name, sizeof(aclient.name), ".");
1118 StringCbCatA(aclient.name, sizeof(aclient.name),
1119 krb5_principal_get_comp_string(context, k5creds->client, 1));
1122 aclient.instance[0] = '\0';
1124 StringCbCopyA(aclient.cell, sizeof(aclient.cell), realm_of_cell);
1126 StringCbCatA(aclient.name, sizeof(aclient.name), "@");
1127 StringCbCatA(aclient.name, sizeof(aclient.name),
1128 krb5_principal_get_realm(context, k5creds->client));
1130 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1131 &aclient, &aserver, &atoken);
1133 rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
1134 if (!rc) {
1135 /* success */
1137 if (k5creds && context)
1138 krb5_free_creds(context, k5creds);
1140 if (context)
1141 krb5_free_context(context);
1143 goto cleanup;
1146 _reportf(L"SetToken returns code %d", rc);
1148 #ifdef USE_KRB4
1149 try_krb524d:
1151 _reportf(L"Trying Krb524");
1153 if (krb524_convert_creds_kdc &&
1154 (method == AFS_TOKEN_AUTO || method == AFS_TOKEN_KRB524)) {
1155 /* This requires krb524d to be running with the KDC */
1156 r = krb524_convert_creds_kdc(context, k5creds, &creds);
1157 if (r) {
1158 _reportf(L"Code %d while converting credentials", r);
1159 goto end_krb5;
1161 rc = KSUCCESS;
1162 got524cred = 1;
1163 bGotCreds = TRUE;
1165 #endif
1167 end_krb5:
1168 if (client_principal)
1169 krb5_free_principal(context, client_principal);
1171 if (k5creds && context)
1172 krb5_free_creds(context, k5creds);
1174 if (context)
1175 krb5_free_context(context);
1178 #ifdef USE_KRB4
1179 /* Kerberos 4 */
1180 try_krb4:
1182 if (supports_krb4) {
1183 kcdb_identity_get_config(identity, 0, &confighandle);
1184 khc_read_int32(confighandle, L"Krb4Cred\\Krb4NewCreds", &supports_krb4);
1185 khc_close_space(confighandle);
1188 if (!supports_krb4)
1189 _reportf(L"Kerberos 4 not configured");
1191 if (!bGotCreds && supports_krb4 &&
1192 strlen(RealmName) < REALM_SZ &&
1193 (method == AFS_TOKEN_AUTO ||
1194 method == AFS_TOKEN_KRB4)) {
1196 KTEXT_ST ticket;
1198 _reportf(L"Trying Kerberos 4");
1200 if (!realm_of_user[0] ) {
1201 if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user))
1202 != KSUCCESS) {
1203 /* can't determine realm of user */
1204 _reportf(L"krb_get_tf_realm returns %d", rc);
1205 goto end_krb4;
1209 _reportf(L"Trying to find %S.%S@%S", ServiceName, CellName, RealmName);
1210 rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
1211 if (rc == NO_TKT_FIL) {
1212 // if the problem is that we have no krb4 tickets
1213 // do not attempt to continue
1214 _reportf(L"krb_get_cred returns %d (no ticket file)", rc);
1215 goto end_krb4;
1218 if (rc != KSUCCESS) {
1219 _reportf(L"Trying to find %S@%S", ServiceName, RealmName);
1220 rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
1223 if (rc != KSUCCESS) {
1224 _reportf(L"Trying to obtain new ticket");
1225 if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1226 CellName, RealmName, 0))
1227 == KSUCCESS) {
1228 if ((rc = (*pkrb_get_cred)(ServiceName, CellName,
1229 RealmName, &creds)) != KSUCCESS) {
1230 goto end_krb4;
1231 } else {
1232 _reportf(L"Got %S.%S@%S", ServiceName, CellName, RealmName);
1234 } else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName,
1235 "", RealmName, 0))
1236 == KSUCCESS) {
1237 if ((rc = (*pkrb_get_cred)(ServiceName, "",
1238 RealmName, &creds)) != KSUCCESS) {
1239 goto end_krb4;
1240 } else {
1241 _reportf(L"Got %S@%S", ServiceName, RealmName);
1243 } else {
1244 goto end_krb4;
1248 bGotCreds = TRUE;
1250 end_krb4:
1254 if (bGotCreds) {
1256 memset(&aserver, '\0', sizeof(aserver));
1257 StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1258 StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1260 memset(&atoken, '\0', sizeof(atoken));
1261 atoken.kvno = (short)creds.kvno;
1262 atoken.startTime = creds.issue_date;
1263 atoken.endTime = (*pkrb_life_to_time)(creds.issue_date,creds.lifetime);
1264 memcpy(&atoken.sessionKey, creds.session, 8);
1265 atoken.ticketLen = creds.ticket_st.length;
1266 memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
1268 if (tok_expiration)
1269 *tok_expiration = atoken.endTime;
1271 if (!(rc = ktc_GetToken(&aserver, &btoken,
1272 sizeof(btoken), &aclient)) &&
1273 atoken.kvno == btoken.kvno &&
1274 atoken.ticketLen == btoken.ticketLen &&
1275 !memcmp(&atoken.sessionKey, &btoken.sessionKey,
1276 sizeof(atoken.sessionKey)) &&
1277 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1279 /* success! */
1280 rc = 0;
1281 goto cleanup;
1284 // Reset the "aclient" structure before we call ktc_SetToken.
1285 // This structure was first set by the ktc_GetToken call when
1286 // we were comparing whether identical tokens already existed.
1288 StringCchCopyA(aclient.name, MAXKTCNAMELEN, creds.pname);
1289 if (creds.pinst[0]) {
1290 StringCchCatA(aclient.name, MAXKTCNAMELEN, ".");
1291 StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.pinst);
1294 StringCbCopyA(aclient.instance, sizeof(aclient.instance), "");
1296 StringCchCatA(aclient.name, MAXKTCNAMELEN, "@");
1297 StringCchCatA(aclient.name, MAXKTCNAMELEN, got524cred ? realm_of_user : creds.realm);
1299 StringCbCopyA(aclient.cell, sizeof(aclient.cell), CellName);
1301 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
1302 &aclient, &aserver, &atoken);
1304 if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
1305 afs_report_error(rc, "ktc_SetToken()");
1306 goto cleanup;
1309 #endif
1311 if (!bGotCreds &&
1312 (method == AFS_TOKEN_AUTO ||
1313 method >= AFS_TOKEN_USER)) {
1314 /* we couldn't get a token using Krb5, Krb524 or Krb4,
1315 either because we couldn't get the necessary
1316 credentials or because the method was set to not use
1317 those. Now we dispatch to any extensions to see if
1318 they have better luck. */
1320 rc = !afs_ext_klog(method,
1321 identity,
1322 ServiceName,
1323 CellName,
1324 RealmName,
1325 &ak_cellconfig,
1326 LifeTime);
1327 } else if (!bGotCreds) {
1328 /* if the return code was not set, we should set it now.
1329 Otherwise we let the code go through. */
1330 if (!rc) {
1331 /* No tokens were obtained. We should report something */
1332 _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
1333 _cptr(CellName));
1334 _resolve();
1336 rc = KHM_ERROR_GENERAL;
1340 cleanup:
1341 if (ak_cellconfig.linkedCell)
1342 free(ak_cellconfig.linkedCell);
1344 return rc;
1347 /**************************************/
1348 /* afs_realm_of_cell(): */
1349 /**************************************/
1350 static char *
1351 afs_realm_of_cell(afs_conf_cell *cellconfig, BOOL referral_fallback)
1353 char krbhst[MAX_HSTNM]="";
1354 static char krbrlm[MAXKTCREALMLEN+1]="";
1355 krb5_context ctx = 0;
1356 char ** realmlist=NULL;
1357 krb5_error_code r = 0;
1359 if (!cellconfig)
1360 return 0;
1362 if (referral_fallback) {
1363 char * p;
1364 p = strchr(cellconfig->hostName[0], '.');
1365 if (p++)
1366 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1367 else
1368 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1369 #if _MSC_VER >= 1400
1370 _strupr_s(krbrlm, sizeof(krbrlm));
1371 #else
1372 _strupr(krbrlm);
1373 #endif
1374 } else {
1375 r = krb5_init_context(&ctx);
1376 if ( !r )
1377 r = krb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
1378 if ( !r && realmlist && realmlist[0] ) {
1379 StringCbCopyA(krbrlm, sizeof(krbrlm), realmlist[0]);
1380 krb5_free_host_realm(ctx, realmlist);
1382 if (ctx)
1383 krb5_free_context(ctx);
1385 #ifdef USE_KRB4
1386 if (r) {
1387 if (pkrb_get_krbhst && pkrb_realmofhost) {
1388 StringCbCopyA(krbrlm, sizeof(krbrlm),
1389 (char *)(*pkrb_realmofhost)(cellconfig->hostName[0]));
1390 if ((*pkrb_get_krbhst)(krbhst, krbrlm, 1) != KSUCCESS)
1391 krbrlm[0] = '\0';
1394 if ( !krbrlm[0] ) {
1395 char * p;
1396 p = strchr(cellconfig->hostName[0], '.');
1397 if (p++)
1398 StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1399 else
1400 StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1401 #if _MSC_VER >= 1400
1402 _strupr_s(krbrlm, sizeof(krbrlm));
1403 #else
1404 _strupr(krbrlm);
1405 #endif
1408 #endif
1410 return(krbrlm);
1413 /**************************************/
1414 /* afs_get_cellconfig(): */
1415 /**************************************/
1416 static int
1417 afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
1419 int rc;
1420 int ttl = 0;
1421 char linkedCell[MAXCELLCHARS]="";
1423 local_cell[0] = (char)0;
1424 memset(cellconfig, 0, sizeof(*cellconfig));
1426 cellconfig->cbsize = sizeof(*cellconfig);
1428 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
1429 if (rc = cm_GetRootCellName(local_cell)) {
1430 return(rc);
1433 if (strlen(cell) == 0)
1434 StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
1436 StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
1438 rc = cm_SearchCellRegistry(1, cell, NULL, linkedCell,
1439 afs_get_cellconfig_callback, (void*) cellconfig);
1440 if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
1441 rc = cm_SearchCellFileEx(cell, NULL, linkedCell, afs_get_cellconfig_callback,
1442 (void*)cellconfig);
1443 if(rc)
1444 rc = cm_SearchCellByDNS(cell, NULL, &ttl,
1445 afs_get_cellconfig_callback,
1446 (void*) cellconfig);
1448 if (linkedCell[0])
1449 cellconfig->linkedCell = strdup(linkedCell);
1451 return rc;
1454 /**************************************/
1455 /* afs_get_cellconfig_callback(): */
1456 /**************************************/
1457 static long
1458 afs_get_cellconfig_callback(void *cellconfig,
1459 struct sockaddr_in *addrp,
1460 char *namep,
1461 unsigned short ipRank)
1463 afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
1465 cc->hostAddr[cc->numServers] = *addrp;
1466 StringCbCopyA(cc->hostName[cc->numServers],
1467 sizeof(cc->hostName[0]), namep);
1468 cc->numServers++;
1469 return(0);
1473 /**************************************/
1474 /* afs_report_error(): */
1475 /**************************************/
1476 void
1477 afs_report_error(LONG rc, LPCSTR FailedFunctionName)
1479 char message[256];
1480 const char *errText;
1482 // Using AFS defines as error messages for now, until Transarc
1483 // gets back to me with "string" translations of each of these
1484 // const. defines.
1485 if (rc == KTC_ERROR)
1486 errText = "KTC_ERROR";
1487 else if (rc == KTC_TOOBIG)
1488 errText = "KTC_TOOBIG";
1489 else if (rc == KTC_INVAL)
1490 errText = "KTC_INVAL";
1491 else if (rc == KTC_NOENT)
1492 errText = "KTC_NOENT";
1493 else if (rc == KTC_PIOCTLFAIL)
1494 errText = "KTC_PIOCTLFAIL";
1495 else if (rc == KTC_NOPIOCTL)
1496 errText = "KTC_NOPIOCTL";
1497 else if (rc == KTC_NOCELL)
1498 errText = "KTC_NOCELL";
1499 else if (rc == KTC_NOCM)
1500 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
1501 else
1502 errText = "Unknown error!";
1504 StringCbPrintfA(message, sizeof(message),
1505 "%s\n(%s failed)", errText, FailedFunctionName);
1506 _report_cs1(KHERR_ERROR, L"%1!S!", _cptr(message));
1507 _resolve();
1508 return;
1511 DWORD
1512 GetServiceStatus(LPSTR lpszMachineName,
1513 LPSTR lpszServiceName,
1514 DWORD *lpdwCurrentState,
1515 DWORD *lpdwWaitHint)
1517 DWORD hr = NOERROR;
1518 SC_HANDLE schSCManager = NULL;
1519 SC_HANDLE schService = NULL;
1520 DWORD fdwDesiredAccess = 0;
1521 SERVICE_STATUS ssServiceStatus = {0};
1522 BOOL fRet = FALSE;
1524 *lpdwCurrentState = 0;
1526 fdwDesiredAccess = GENERIC_READ;
1528 schSCManager = OpenSCManagerA(lpszMachineName,
1529 NULL,
1530 fdwDesiredAccess);
1532 if(schSCManager == NULL) {
1533 hr = GetLastError();
1534 goto cleanup;
1537 schService = OpenServiceA(schSCManager,
1538 lpszServiceName,
1539 fdwDesiredAccess);
1541 if(schService == NULL) {
1542 hr = GetLastError();
1543 goto cleanup;
1546 fRet = QueryServiceStatus(schService,
1547 &ssServiceStatus);
1549 if(fRet == FALSE) {
1550 hr = GetLastError();
1551 goto cleanup;
1554 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
1555 if (lpdwWaitHint)
1556 *lpdwWaitHint = ssServiceStatus.dwWaitHint;
1557 cleanup:
1559 CloseServiceHandle(schService);
1560 CloseServiceHandle(schSCManager);
1562 return(hr);
1565 DWORD ServiceControl(LPSTR lpszMachineName,
1566 LPSTR lpszServiceName,
1567 DWORD dwNewState) {
1569 DWORD hr = NOERROR;
1570 SC_HANDLE schSCManager = NULL;
1571 SC_HANDLE schService = NULL;
1572 DWORD fdwDesiredAccess = 0;
1573 SERVICE_STATUS ssServiceStatus = {0};
1574 BOOL fRet = FALSE;
1575 DWORD dwCurrentState = 0;
1577 dwCurrentState = 0;
1579 fdwDesiredAccess = GENERIC_READ;
1581 schSCManager = OpenSCManagerA(lpszMachineName, NULL,
1582 fdwDesiredAccess);
1584 if(schSCManager == NULL) {
1585 hr = GetLastError();
1586 goto cleanup;
1589 fdwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
1591 schService = OpenServiceA(schSCManager, lpszServiceName,
1592 fdwDesiredAccess);
1594 if(schService == NULL) {
1595 hr = GetLastError();
1596 goto cleanup;
1599 fRet = QueryServiceStatus(schService, &ssServiceStatus);
1601 if(fRet == FALSE) {
1602 hr = GetLastError();
1603 goto cleanup;
1606 dwCurrentState = ssServiceStatus.dwCurrentState;
1608 if (dwCurrentState == SERVICE_STOPPED &&
1609 dwNewState == SERVICE_RUNNING) {
1611 fRet = StartService(schService, 0, NULL);
1613 if (fRet == FALSE) {
1614 hr = GetLastError();
1615 goto cleanup;
1619 if (dwCurrentState == SERVICE_RUNNING &&
1620 dwNewState == SERVICE_STOPPED) {
1621 fRet = ControlService(schService, SERVICE_CONTROL_STOP,
1622 &ssServiceStatus);
1624 if (fRet == FALSE) {
1625 hr = GetLastError();
1626 goto cleanup;
1630 cleanup:
1632 CloseServiceHandle(schService);
1633 CloseServiceHandle(schSCManager);
1635 return(hr);
1638 khm_boolean
1639 afs_check_for_cell_realm_match(khm_handle identity, char * cell) {
1640 char local_cell[MAXCELLCHARS];
1641 wchar_t wrealm[MAXCELLCHARS];
1642 wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
1643 wchar_t * atsign;
1644 khm_size cb;
1645 char * realm;
1646 afs_conf_cell cellconfig;
1647 int rc;
1649 ZeroMemory(local_cell, sizeof(local_cell));
1650 ZeroMemory(&cellconfig, sizeof(cellconfig));
1652 rc = afs_get_cellconfig(cell, &cellconfig, local_cell);
1653 if (rc)
1654 return FALSE;
1656 realm = afs_realm_of_cell(&cellconfig, FALSE);
1657 if (cellconfig.linkedCell)
1658 free(cellconfig.linkedCell);
1659 if (!realm[0]) /* referral; assume it matches */
1660 return TRUE;
1662 AnsiStrToUnicode(wrealm, sizeof(wrealm), realm);
1664 cb = sizeof(idname);
1665 idname[0] = L'\0';
1666 kcdb_identity_get_name(identity, idname, &cb);
1668 atsign = wcschr(idname, L'@');
1669 if (atsign && atsign[1] && !_wcsicmp(atsign + 1, wrealm)) {
1670 return TRUE;
1671 } else {
1672 return FALSE;