windows-nim-afscred-double-free-20071127
[openafs.git] / src / WINNT / netidmgr_plugin / afsfuncs.c
1 /*
2  * Copyright (c) 2005,2006,2007 Secure Endpoints Inc.
3  *
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:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
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.
23  */
24
25 /* $Id$ */
26
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)
31
32 #include<afscred.h>
33 #include<dynimport.h>
34 #include<krb5common.h>
35
36 #pragma warning (pop)
37
38 BOOL
39 afs_is_running(void) {
40     DWORD CurrentState;
41
42     if (!AfsAvailable)
43         return FALSE;
44
45     if (GetServiceStatus(NULL, TRANSARCAFSDAEMON, 
46                          &CurrentState, NULL) != NOERROR)
47         return FALSE;
48     if (CurrentState != SERVICE_RUNNING)
49         return FALSE;
50
51     return TRUE;
52 }
53
54 int
55 afs_unlog(void)
56 {
57     long        rc;
58
59     if (!afs_is_running())
60         return 0;
61
62     rc = ktc_ForgetAllTokens();
63
64     return rc;
65 }
66
67 int
68 afs_unlog_cred(khm_handle cred)
69 {
70     long rc;
71     struct ktc_principal princ;
72     khm_size cbbuf;
73     wchar_t name[KCDB_MAXCCH_NAME];
74
75     if (!afs_is_running())
76         return 0;
77
78     cbbuf = sizeof(princ);
79     if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_server_princ, 
80                                      NULL, &princ, &cbbuf)))
81         return 1;
82
83     afs_princ_to_string(&princ, name, sizeof(name));
84
85     _report_cs1(KHERR_INFO, L"Destroying token %1!s!",
86                 _cstr(name));
87     _resolve();
88
89     rc = ktc_ForgetToken(&princ);
90
91     return rc;
92 }
93
94 /* convert a ktc_principal to a wchar_t string form that looks like
95     name.instance@cell return 0 if it worked. non-zero otherwise
96 */
97 int 
98 afs_princ_to_string(struct ktc_principal * p, 
99                     wchar_t * buf, 
100                     size_t cbbuf)
101 {
102     wchar_t wbuf[256];
103     int rv = 0;
104     int l;
105
106     l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->name);
107     wbuf[l] = L'\0';
108
109     rv = FAILED(StringCbCopy(buf, cbbuf, wbuf));
110     if(p->instance[0]) {
111         StringCbCat(buf, cbbuf, L".");
112         if((l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->instance)) > 0) {
113             wbuf[l] = L'\0';
114             rv = rv || FAILED(StringCbCat(buf, cbbuf, wbuf));
115         }
116         else
117             rv = 1;
118     }
119     if(p->cell[0]) {
120         rv = rv || FAILED(StringCbCat(buf, cbbuf, L"@"));
121         if((l = AnsiStrToUnicode(wbuf, sizeof(wbuf), p->cell)) > 0) {
122             wbuf[l] = L'\0';
123             rv = rv || FAILED(StringCbCat(buf, cbbuf, wbuf));
124         }
125         else
126             rv = 1;
127     }
128
129     return rv;
130 }
131
132 int 
133 afs_list_tokens(void)
134 {
135     int r;
136
137     kcdb_credset_flush(afs_credset);
138     r = afs_list_tokens_internal();
139     kcdb_credset_collect(NULL, afs_credset, NULL, afs_credtype_id, NULL);
140
141     return r;
142 }
143
144 /* is the credential provided an AFS token and is it from the
145    specified cell? */
146 static khm_int32 KHMAPI 
147 afs_filter_by_cell(khm_handle cred, khm_int32 flags, void * rock)
148 {
149     wchar_t wcell[MAXCELLCHARS];
150     wchar_t * tcell;
151     khm_size cbsize;
152     khm_int32 type;
153
154     tcell = (wchar_t *) rock;
155
156     if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
157         type != afs_credtype_id)
158         return FALSE;
159
160     cbsize = sizeof(wcell);
161     if(KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell, 
162                                      NULL, wcell, &cbsize)))
163         return FALSE;
164
165     if(wcscmp(wcell, tcell))
166         return FALSE;
167
168     return TRUE;
169 }
170
171 struct token_filter_data {
172     wchar_t * cell;
173 };
174
175 khm_int32 KHMAPI
176 afs_filter_for_token(khm_handle cred, khm_int32 flags, void * rock) {
177     struct token_filter_data * pdata;
178     wchar_t ccell[MAXCELLCHARS];
179     khm_size cb;
180     khm_int32 ctype;
181
182     pdata = (struct token_filter_data *) rock;
183
184     if (KHM_FAILED(kcdb_cred_get_type(cred, &ctype)) ||
185         ctype != afs_credtype_id)
186
187         return 0;
188
189     cb = sizeof(ccell);
190
191     if (KHM_FAILED(kcdb_cred_get_attr(cred, afs_attr_cell,
192                                       NULL,
193                                       ccell,
194                                       &cb)) ||
195         _wcsicmp(ccell, pdata->cell))
196
197         return 0;
198
199     return 1;
200 }
201
202 khm_handle
203 afs_find_token(khm_handle credset, wchar_t * cell) {
204     struct token_filter_data fdata;
205     khm_handle cred = NULL;
206
207     fdata.cell = cell;
208
209     if (KHM_FAILED(kcdb_credset_find_filtered(credset,
210                                               -1,
211                                               afs_filter_for_token,
212                                               &fdata,
213                                               &cred,
214                                               NULL)))
215         return NULL;
216     else
217         return cred;
218 }
219
220 static khm_int32 KHMAPI 
221 afs_filter_krb5_tkt(khm_handle cred, khm_int32 flags, void * rock) 
222 {
223     wchar_t cname[KCDB_CRED_MAXCCH_NAME];
224     khm_int32 type;
225     wchar_t * tcell;
226     wchar_t * t, *tkt_cell;
227     khm_size cbsize;
228
229     tcell = (wchar_t *) rock;
230
231     if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
232        type != krb5_credtype_id)
233         return FALSE;
234
235     cbsize = sizeof(cname);
236     if (KHM_FAILED(kcdb_cred_get_name(cred, cname, &cbsize)))
237         return FALSE;
238
239     if (!wcsncmp(cname, L"afs/", 4)) {
240
241         tkt_cell = cname + 4;
242
243         t = wcschr(tkt_cell, L'@');
244         if (t == NULL)
245             return FALSE;
246         *t = L'\0';
247
248     } else if (!wcsncmp(cname, L"afs@", 4)) {
249
250         tkt_cell = cname + 4;
251
252     } else {
253         return FALSE;
254     }
255
256     if (_wcsicmp(tcell, tkt_cell))
257         return FALSE;
258
259     return TRUE;
260 }
261
262 static khm_int32 KHMAPI 
263 afs_filter_krb4_tkt(khm_handle cred, khm_int32 flags, void * rock) 
264 {
265     wchar_t cname[KCDB_CRED_MAXCCH_NAME];
266     khm_int32 type;
267     wchar_t * tcell;
268     wchar_t * t, *tkt_cell;
269     khm_size cbsize;
270
271     tcell = (wchar_t *) rock;
272
273     if(KHM_FAILED(kcdb_cred_get_type(cred, &type)) ||
274        type != krb4_credtype_id)
275         return FALSE;
276
277     cbsize = sizeof(cname);
278     if (KHM_FAILED(kcdb_cred_get_name(cred, cname, &cbsize)))
279         return FALSE;
280
281     if (!wcsncmp(cname, L"afs.", 4)) {
282
283         tkt_cell = cname + 4;
284
285         t = wcschr(tkt_cell, L'@');
286         if (t == NULL)
287             return FALSE;
288         *t = L'\0';
289
290     } else if (!wcsncmp(cname, L"afs@", 4)) {
291
292         tkt_cell = cname + 4;
293
294     } else {
295         return FALSE;
296     }
297
298     if (_wcsicmp(tcell, tkt_cell))
299         return FALSE;
300
301     return TRUE;
302 }
303
304 /* collects all AFS tokens to the root credential set using the
305    generic afs_credset credential set
306    */
307 int
308 afs_list_tokens_internal(void)
309 {
310     struct ktc_principal    aserver;
311     struct ktc_principal    aclient;
312     struct ktc_token        atoken;
313     int                     cellNum;
314     int                     BreakAtEnd;
315     wchar_t                 idname[256];
316     wchar_t                 crname[256];
317     wchar_t                 location[256];
318     wchar_t                 *cell;
319
320     DWORD                   rc;
321
322     khm_handle              ident = NULL;
323     khm_handle              cred = NULL;
324     afs_tk_method           method;
325
326     FILETIME                ft;
327
328     if (!afs_is_running())
329         return 0;
330
331     kcdb_credset_flush(afs_credset);
332
333     LoadString(hResModule, IDS_DEF_LOCATION, location, ARRAYLENGTH(location));
334
335     BreakAtEnd = 0;
336     cellNum = 0;
337     while (1) 
338     {
339         memset(&aserver, 0, sizeof(aserver));
340         if (rc = ktc_ListTokens(cellNum, &cellNum, &aserver))
341         {
342             if (rc != KTC_NOENT)
343                 return(0);
344
345             if (BreakAtEnd == 1)
346                 break;
347         }
348         BreakAtEnd = 1;
349         memset(&atoken, '\0', sizeof(atoken));
350         if (rc = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient))
351         {
352             if (rc == KTC_ERROR)
353                 return(0);
354
355             continue;
356         }
357
358 #if 0
359         /* failed attempt at trying to figure out the principal name from
360            the token.  The ticket that is attached to the token is not
361            in a form that is useful at this point */
362         idname[0] = L'\0';
363         if(atoken.kvno == RXKAD_TKT_TYPE_KERBEROS_V5) {
364             krb5_context ctx = 0;
365             krb5_ccache cc = 0;
366             krb5_creds * k5c;
367             krb5_error_code code;
368             char * princ;
369
370             code = khm_krb5_initialize(&ctx, &cc);
371             if(code)
372                 goto _no_krb5;
373
374             k5c = (krb5_creds *) atoken.ticket;
375
376             code = pkrb5_unparse_name(ctx, k5c->client, &princ);
377             if(code)
378                 goto _no_krb5;
379
380             MultiByteToWideChar(CP_ACP, 0, princ, strlen(princ), idname, sizeof(idname)/sizeof(idname[0]));
381
382             pkrb5_free_unparsed_name(ctx, princ);
383 _no_krb5:
384             ;
385         }
386 #endif
387
388         method = AFS_TOKEN_AUTO;
389
390         afs_princ_to_string(&aclient, idname, sizeof(idname));
391
392         /* We need to figure out a good client name which we can use
393            to create an identity which looks familiar to the user.  No
394            good way of doing this, so we use a heuristic.
395
396            Note that, we use another heuristic to find out which
397            identity to associate the token with.
398    
399            ASSUMPTION:
400
401            The assumption here is that the principal for the token is
402            computed as follows:
403            
404            if realm != cell : principal looks like user@realm@cell
405            if realm == cell : principal looks like user@realm
406         
407            HEURISTIC:
408         
409            We strip the part of the string that follows the second '@'
410            sign to obtain the 'user@realm' part, which we use as the
411            credential name.  If there is no second '@', we use the
412            whole principal name. */
413         {
414             wchar_t * ats;
415
416             ats = wcschr(idname, L'@');
417             if(ats && (ats = wcschr(ats + 1, L'@')))
418                 *ats = L'\0';
419         }
420
421         afs_princ_to_string(&aserver, crname, sizeof(crname));
422
423         /* Ok, now we need to figure out which identity to associate
424            this token with.  This is a little bit tricky, and there is
425            currently no good way of determining the original identity
426            used to obtain the token if it was done outside of
427            NetIDMgr.  So we use a heuristic here.
428
429            REQUIREMENT:
430
431            Elsewhere, (actually in afsnewcreds.c) just after obtaining
432            AFS tokens through NetIDMgr, we enumerate the AFS tokens
433            and assign the root identity (used to obtain new creds)
434            with the AFS tokens.  This would still be there in the root
435            credential set when we list tokens later on.
436
437            HEURISTIC:
438
439            If there exists an AFS token in the root credential set for
440            the same cell, we associate this token with the same
441            identity as that credential.
442         */
443         cell = wcschr(crname, L'@');
444         if(cell) {
445             cell++;
446             if(!*cell)
447                 cell = NULL;
448         }
449
450         ident = NULL;
451         if(cell) {
452             khm_handle c;
453
454             if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1, 
455                                                         afs_filter_by_cell, 
456                                                         (void *) cell, 
457                                                         &c, NULL))) {
458                 khm_size cb;
459
460                 kcdb_cred_get_identity(c, &ident);
461                 cb = sizeof(method);
462                 kcdb_cred_get_attr(c, afs_attr_method, NULL,
463                                    &method, &cb);
464                 kcdb_cred_release(c);
465             }
466         }
467
468         /* If that failed, we have try another trick.  If there is a
469            Krb5 ticket of the form afs/<cell>@<realm> or afs@<CELL>
470            where <cell> matches our cell, then we pick the identity
471            off of that.
472
473            ASSUMPTION:
474
475            If Krb5 was used to obtain the token, then there is a Krb5
476            ticket of the form afs/<cell>@<REALM> or afs@<CELL> still
477            in the cache.  This is also true for Krb524 token
478            acquisition.
479
480            HEURISTIC:
481
482            If such a Krb5 ticket is found, use the identity of that
483            credential as the identity of the AFS token.
484
485         */
486         if (ident == NULL && cell != NULL) {
487             khm_handle c;
488
489             if(KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1, 
490                                                         afs_filter_krb5_tkt,
491                                                         (void *) cell, 
492                                                         &c, NULL))) {
493                 kcdb_cred_get_identity(c, &ident);
494                 /* this could be Krb5 or Krb524, so we leave method at
495                    AFS_TOKEN_AUTO. */
496                 method = AFS_TOKEN_AUTO;
497                 kcdb_cred_release(c);
498             }
499         }
500
501         /* If that didn't work either, we look for a Krb4 ticket of
502            the form afs.<cell>@<REALM> or afs@<CELL> which matches the
503            cell. 
504
505            ASSUMPTION:
506
507            If Krb4 was used to obtain an AFS token, then there should
508            be a Krb4 ticket of the form afs.<cell>@<REALM> or
509            afs@<CELL> in the cache.
510
511            HEURISTIC:
512
513            If such a ticket is found, then use the identity of that
514            credential as the identity of the AFS token.
515         */
516         if (ident == NULL && cell != NULL) {
517             khm_handle c;
518
519             if (krb4_credtype_id < 0) {
520                 kcdb_credtype_get_id(KRB4_CREDTYPE_NAME,
521                                      &krb4_credtype_id);
522             }
523
524             if (krb4_credtype_id >= 0 &&
525                 KHM_SUCCEEDED(kcdb_credset_find_filtered(NULL, -1,
526                                                          afs_filter_krb4_tkt,
527                                                          (void *) cell,
528                                                          &c, NULL))) {
529
530                 kcdb_cred_get_identity(c, &ident);
531                 kcdb_cred_release(c);
532                 method = AFS_TOKEN_KRB4;
533
534             }
535         }
536
537         /* Finally, we allow any extension plugins to give this a shot */
538         if (ident == NULL && cell != NULL) {
539             afs_ext_resolve_token(cell,
540                                   &atoken,
541                                   &aserver,
542                                   &aclient,
543                                   &ident,
544                                   &method);
545         }
546
547         /* One more thing to try.  If we have a cell->identity
548            mapping, then we try that. */
549         if (ident == NULL && cell != NULL) {
550             khm_handle h_cellmap;
551             wchar_t tidname[KCDB_IDENT_MAXCCH_NAME];
552             khm_size cb;
553
554             cb = sizeof(tidname);
555
556             if (KHM_SUCCEEDED(khc_open_space(csp_afscred,
557                                              L"Cells", 0, 
558                                              &h_cellmap))) {
559                 if (KHM_SUCCEEDED(khc_read_string(h_cellmap,
560                                                   cell,
561                                                   tidname,
562                                                   &cb))) {
563                     kcdb_identity_create(tidname,
564                                          KCDB_IDENT_FLAG_CREATE,
565                                          &ident);
566                 }
567                 khc_close_space(h_cellmap);
568             }
569         }
570
571         /* all else failed */
572         if(ident == NULL) {
573             if(KHM_FAILED(kcdb_identity_create(idname, 
574                                                KCDB_IDENT_FLAG_CREATE, 
575                                                &ident)))
576                 goto _exit;
577         }
578
579         if(KHM_FAILED(kcdb_cred_create(crname, ident, afs_credtype_id, &cred)))
580             goto _exit;
581
582         kcdb_cred_set_attr(cred, afs_attr_method, &method, sizeof(method));
583
584         TimetToFileTime(atoken.endTime, &ft);
585         kcdb_cred_set_attr(cred, KCDB_ATTR_EXPIRE, &ft, sizeof(ft));
586         if (atoken.startTime != 0) {
587             TimetToFileTime(atoken.startTime, &ft);
588             kcdb_cred_set_attr(cred, KCDB_ATTR_ISSUE, &ft, sizeof(ft));
589         }
590         kcdb_cred_set_attr(cred, afs_attr_client_princ, 
591                            &aclient, sizeof(aclient));
592         kcdb_cred_set_attr(cred, afs_attr_server_princ, 
593                            &aserver, sizeof(aserver));
594
595         if(cell) {
596             kcdb_cred_set_attr(cred, afs_attr_cell, cell, (khm_size)KCDB_CBSIZE_AUTO);
597         }
598
599         kcdb_cred_set_attr(cred, KCDB_ATTR_LOCATION, 
600                            location, (khm_size)KCDB_CBSIZE_AUTO);
601
602         kcdb_credset_add_cred(afs_credset, cred, -1);
603
604         /* both these calls are NULL pointer safe */
605         kcdb_cred_release(cred);
606         cred = NULL;
607         kcdb_identity_release(ident);
608         ident = NULL;
609     }
610
611 _exit:
612     if(ident)
613         kcdb_identity_release(ident);
614     if(cred)
615         kcdb_cred_release(cred);
616
617     return(0);
618 }
619
620
621 #define ALLOW_REGISTER 1
622 static int
623 ViceIDToUsername(char *username, 
624                  char *realm_of_user, 
625                  char *realm_of_cell,
626                  char * cell_to_use,
627                  struct ktc_principal *aclient, 
628                  struct ktc_principal *aserver, 
629                  struct ktc_token *atoken)
630 {
631     static char lastcell[MAXCELLCHARS+1] = { 0 };
632     static char confname[512] = { 0 };
633     char username_copy[BUFSIZ];
634     long viceId = ANONYMOUSID;          /* AFS uid of user */
635     int  status = 0;
636 #ifdef ALLOW_REGISTER
637     afs_int32 id;
638 #endif /* ALLOW_REGISTER */
639
640     if (confname[0] == '\0') {
641         StringCbCopyA(confname, sizeof(confname), AFSDIR_CLIENT_ETC_DIRPATH);
642     }
643
644     StringCbCopyA(lastcell, sizeof(lastcell), aserver->cell);
645
646     if (!pr_Initialize (0, confname, aserver->cell)) {
647         char sname[PR_MAXNAMELEN];
648         StringCbCopyA(sname, sizeof(sname), username);
649         status = pr_SNameToId (sname, &viceId);
650         pr_End();
651     }
652
653 #ifdef AFS_ID_TO_NAME
654     /*
655      * This is a crock, but it is Transarc's crock, so
656      * we have to play along in order to get the
657      * functionality.  The way the afs id is stored is
658      * as a string in the username field of the token.
659      * Contrary to what you may think by looking at
660      * the code for tokens, this hack (AFS ID %d) will
661      * not work if you change %d to something else.
662      */
663 #endif /* AFS_ID_TO_NAME */
664     /*
665      * This code is taken from cklog -- it lets people
666      * automatically register with the ptserver in foreign cells
667      */
668
669     /* copy the username because pr_CreateUser will lowercase it */
670     StringCbCopyA(username_copy, BUFSIZ, username);
671
672 #ifdef ALLOW_REGISTER
673     if (status == 0) {
674         if (viceId != ANONYMOUSID) {
675 #else /* ALLOW_REGISTER */
676             if ((status == 0) && (viceId != ANONYMOUSID))
677 #endif /* ALLOW_REGISTER */
678             {
679 #ifdef AFS_ID_TO_NAME
680                 StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
681 #endif /* AFS_ID_TO_NAME */
682             }
683 #ifdef ALLOW_REGISTER
684         } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
685             id = 0;
686             StringCbCopyA(aclient->name, sizeof(aclient->name), username);
687             StringCbCopyA(aclient->instance, sizeof(aclient->instance), "");
688             StringCbCopyA(aclient->cell, sizeof(aclient->cell), realm_of_user);
689             if (status = ktc_SetToken(aserver, atoken, aclient, 0))
690                 return status;
691             if (status = pr_Initialize(1L, confname, aserver->cell))
692                 return status;
693             status = pr_CreateUser(username, &id);
694             pr_End();
695             StringCbCopyA(username, BUFSIZ, username_copy);
696 #ifdef AFS_ID_TO_NAME
697             StringCchPrintfA(username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
698 #endif /* AFS_ID_TO_NAME */
699         }
700     }
701 #endif /* ALLOW_REGISTER */
702     return status;
703 }
704
705
706 int
707 afs_klog(khm_handle identity,
708          char *service,
709          char *cell,
710          char *realm,
711          int LifeTime,
712          afs_tk_method method,
713          time_t * tok_expiration) {
714
715     long        rc;
716     CREDENTIALS creds;
717     struct ktc_principal        aserver;
718     struct ktc_principal        aclient;
719     char        realm_of_user[REALM_SZ]; /* Kerberos realm of user */
720     char        realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
721     char        local_cell[MAXCELLCHARS+1];
722     char        Dmycell[MAXCELLCHARS+1];
723     struct ktc_token    atoken;
724     struct ktc_token    btoken;
725     afs_conf_cell       ak_cellconfig; /* General information about the cell */
726     char        RealmName[128];
727     char        CellName[128];
728     char        ServiceName[128];
729     khm_handle  confighandle = NULL;
730     khm_int32   supports_krb4 = 1;
731     khm_int32   got524cred = 0;
732
733     /* signalling */
734     BOOL        bGotCreds = FALSE; /* got creds? */
735
736     if (tok_expiration)
737         *tok_expiration = (time_t) 0;
738
739     if (!afs_is_running()) {
740         _report_sr0(KHERR_WARNING, IDS_ERR_NOSERVICE);
741         return(0);
742     }
743
744     if ( !realm )   realm = "";
745     if ( !cell )    cell = "";
746     if ( !service ) service = "";
747
748     memset(RealmName, '\0', sizeof(RealmName));
749     memset(CellName, '\0', sizeof(CellName));
750     memset(ServiceName, '\0', sizeof(ServiceName));
751     memset(realm_of_user, '\0', sizeof(realm_of_user));
752     memset(realm_of_cell, '\0', sizeof(realm_of_cell));
753     memset(Dmycell, '\0', sizeof(Dmycell));
754
755     // NULL or empty cell returns information on local cell
756     if (cell && cell[0])
757         StringCbCopyA(Dmycell, sizeof(Dmycell), cell);
758
759     rc = afs_get_cellconfig(Dmycell, &ak_cellconfig, local_cell);
760     if (rc) {
761         _reportf(L"afs_get_cellconfig returns %ld", rc);
762
763         _report_sr2(KHERR_ERROR, IDS_ERR_CELLCONFIG, _cstr(Dmycell), _int32(rc));
764         _suggest_sr(IDS_ERR_CELLCONFIG_S, KHERR_SUGGEST_NONE);
765         _resolve();
766         return(rc);
767     }
768
769     StringCbCopyA(realm_of_cell, sizeof(realm_of_cell), 
770                   afs_realm_of_cell(&ak_cellconfig, FALSE));
771
772     if (strlen(service) == 0)
773         StringCbCopyA(ServiceName, sizeof(ServiceName), "afs");
774     else
775         StringCbCopyA(ServiceName, sizeof(ServiceName), service);
776
777     if (strlen(cell) == 0)
778         StringCbCopyA(CellName, sizeof(CellName), local_cell);
779     else
780         StringCbCopyA(CellName, sizeof(CellName), cell);
781
782     if (strlen(realm) == 0)
783         StringCbCopyA(RealmName, sizeof(RealmName), realm_of_cell);
784     else
785         StringCbCopyA(RealmName, sizeof(RealmName), realm);
786
787     memset(&creds, '\0', sizeof(creds));
788
789     /*** Kerberos 5 and 524 ***/
790
791     if (method == AFS_TOKEN_AUTO ||
792         method == AFS_TOKEN_KRB5 ||
793         method == AFS_TOKEN_KRB524) {
794
795         krb5_context   context = 0;
796         krb5_ccache    k5cc = 0;
797         krb5_creds     increds;
798         krb5_creds *   k5creds = 0;
799         krb5_error_code r;
800         krb5_principal client_principal = 0;
801         krb5_flags     flags = 0;
802
803         int         retry = 0;
804         int         len;
805         char        *p;
806
807         _reportf(L"Trying Kerberos 5");
808
809         if (!(r = khm_krb5_initialize(identity, &context, &k5cc))) {
810             int i;
811
812             memset((char *)&increds, 0, sizeof(increds));
813
814             pkrb5_cc_get_principal(context, k5cc, &client_principal);
815             i = krb5_princ_realm(context, client_principal)->length;
816             if (i > REALM_SZ-1) 
817                 i = REALM_SZ-1;
818             StringCchCopyNA(realm_of_user, ARRAYLENGTH(realm_of_user),
819                             krb5_princ_realm(context, client_principal)->data,
820                             i);
821         } else {
822             _reportf(L"khm_krb5_initialize returns code %d", r);
823             goto try_krb4;
824         }
825
826         /* First try Service/Cell@REALM */
827         if (r = pkrb5_build_principal(context, &increds.server,
828                                          (int) strlen(RealmName),
829                                          RealmName,
830                                          ServiceName,
831                                          CellName,
832                                          0)) {
833             _reportf(L"krb5_build_principal returns %d", r);
834             goto end_krb5;
835         }
836
837         increds.client = client_principal;
838         increds.times.endtime = 0;
839         /* Ask for DES since that is what V4 understands */
840         increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
841
842 #ifdef KRB5_TC_NOTICKET
843         flags = KRB5_TC_OPENCLOSE;
844         r = pkrb5_cc_set_flags(context, k5cc, flags);
845 #endif
846       retry_retcred:
847         r = pkrb5_get_credentials(context, 0, k5cc, &increds, &k5creds);
848         if ((r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
849               r == KRB5KRB_ERR_GENERIC /* Heimdal */) &&
850              !RealmName[0]) {
851             StringCbCopyA(RealmName, sizeof(RealmName), 
852                           afs_realm_of_cell(&ak_cellconfig, TRUE));
853
854             pkrb5_free_principal(context, increds.server);
855             r = pkrb5_build_principal(context, &increds.server,
856                                          (int) strlen(RealmName),
857                                          RealmName,
858                                          ServiceName,
859                                          CellName,
860                                          0);
861             if (r == 0)
862                 r = pkrb5_get_credentials(context, 0, k5cc, 
863                                           &increds, &k5creds);
864         }
865         if (r == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
866             r == KRB5KRB_ERR_GENERIC /* Heimdal */) {
867             /* Next try Service@REALM */
868             pkrb5_free_principal(context, increds.server);
869             r = pkrb5_build_principal(context, &increds.server,
870                                          (int) strlen(RealmName),
871                                          RealmName,
872                                          ServiceName,
873                                          0);
874             if (r == 0)
875                 r = pkrb5_get_credentials(context, 0, k5cc, 
876                                           &increds, &k5creds);
877         }
878
879         /* Check to make sure we received a valid ticket; if not remove it
880         * and try again.  Perhaps there are two service tickets for the
881         * same service in the ccache.
882         */
883         if (r == 0 && k5creds && k5creds->times.endtime < time(NULL)) {
884             pkrb5_cc_remove_cred(context, k5cc, 0, k5creds);
885             pkrb5_free_creds(context, k5creds);
886             k5creds = NULL;
887             goto retry_retcred;
888         }
889
890         pkrb5_free_principal(context, increds.server);
891         pkrb5_free_principal(context, client_principal);
892         client_principal = 0;
893 #ifdef KRB5_TC_NOTICKET
894         flags = KRB5_TC_OPENCLOSE | KRB5_TC_NOTICKET;
895         pkrb5_cc_set_flags(context, k5cc, flags);
896 #endif
897
898         (void) pkrb5_cc_close(context, k5cc);
899         k5cc = 0;
900
901         if (r) {
902             _reportf(L"Code %d while getting credentials", r);
903             k5creds = NULL;
904             goto end_krb5;
905         }
906
907         if ( k5creds->ticket.length > MAXKTCTICKETLEN ||
908              method == AFS_TOKEN_KRB524) {
909             goto try_krb524d;
910         }
911
912         /* This code inserts the entire K5 ticket into the token */
913
914         _reportf(L"Trying K5 SetToken");
915
916         memset(&aserver, '\0', sizeof(aserver));
917         StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
918         StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
919
920         memset(&atoken, '\0', sizeof(atoken));
921         atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
922         atoken.startTime = k5creds->times.starttime;
923         atoken.endTime = k5creds->times.endtime;
924         memcpy(&atoken.sessionKey, 
925                k5creds->keyblock.contents, 
926                k5creds->keyblock.length);
927         atoken.ticketLen = k5creds->ticket.length;
928         memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
929
930         if (tok_expiration)
931             *tok_expiration = k5creds->times.endtime;
932
933     retry_gettoken5:
934         rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
935         if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
936             if ( rc == KTC_NOCM && retry < 20 ) {
937                 Sleep(500);
938                 retry++;
939                 goto retry_gettoken5;
940             }
941             goto try_krb524d;
942         }
943
944         if (atoken.kvno == btoken.kvno &&
945             atoken.ticketLen == btoken.ticketLen &&
946             !memcmp(&atoken.sessionKey, &btoken.sessionKey, 
947                     sizeof(atoken.sessionKey)) &&
948             !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
949
950             /* success */
951             if (k5creds && context)
952                 pkrb5_free_creds(context, k5creds);
953
954             if (context)
955                 pkrb5_free_context(context);
956
957             _reportf(L"Same token already exists");
958             
959             return 0;
960         }
961
962         // * Reset the "aclient" structure before we call ktc_SetToken.
963         // * This structure was first set by the ktc_GetToken call when
964         // * we were comparing whether identical tokens already existed.
965
966         len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1);
967         StringCchCopyNA(aclient.name, MAXKTCNAMELEN,
968                         k5creds->client->data[0].data, len);
969
970         if ( k5creds->client->length > 1 ) {
971             StringCbCatA(aclient.name, sizeof(aclient.name), ".");
972             p = aclient.name + strlen(aclient.name);
973             len = (int) min(k5creds->client->data[1].length,
974                             MAXKTCNAMELEN - strlen(aclient.name) - 1);
975             StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
976                             k5creds->client->data[1].data, len);
977         }
978
979         aclient.instance[0] = '\0';
980
981         StringCbCopyA(aclient.cell, sizeof(aclient.cell), realm_of_cell);
982
983         StringCbCatA(aclient.name, sizeof(aclient.name), "@");
984         p = aclient.name + strlen(aclient.name);
985         len = (int) min(k5creds->client->realm.length,
986                          MAXKTCNAMELEN - strlen(aclient.name) - 1);
987         StringCchCopyNA(p, MAXKTCNAMELEN - strlen(aclient.name),
988                         k5creds->client->realm.data, len);
989
990         ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, 
991                          &aclient, &aserver, &atoken);
992
993         rc = ktc_SetToken(&aserver, &atoken, &aclient, 0);
994         if (!rc) {
995             /* success */
996
997             if (k5creds && context)
998                 pkrb5_free_creds(context, k5creds);
999
1000             if (context)
1001                 pkrb5_free_context(context);
1002             
1003             return 0;
1004         }
1005
1006         _reportf(L"SetToken returns code %d", rc);
1007
1008     try_krb524d:
1009
1010         _reportf(L"Trying Krb524");
1011
1012         if (method == AFS_TOKEN_AUTO ||
1013             method == AFS_TOKEN_KRB524) {
1014             /* This requires krb524d to be running with the KDC */
1015             r = pkrb524_convert_creds_kdc(context, k5creds, &creds);
1016             if (r) {
1017                 _reportf(L"Code %d while converting credentials", r);
1018                 goto end_krb5;
1019             }
1020             rc = KSUCCESS;
1021             got524cred = 1;
1022             bGotCreds = TRUE;
1023         }
1024
1025     end_krb5:
1026         if (client_principal)
1027             pkrb5_free_principal(context, client_principal);
1028
1029         if (k5creds && context)
1030             pkrb5_free_creds(context, k5creds);
1031
1032         if (context)
1033             pkrb5_free_context(context);
1034     }
1035
1036     /* Kerberos 4 */
1037  try_krb4:
1038
1039     kcdb_identity_get_config(identity, 0, &confighandle);
1040     khc_read_int32(confighandle, L"Krb4Cred\\Krb4NewCreds", &supports_krb4);
1041     khc_close_space(confighandle);
1042
1043     if (!supports_krb4) {
1044         _reportf(L"Kerberos 4 not configured");
1045     }
1046
1047     if (!bGotCreds && supports_krb4 && 
1048         (method == AFS_TOKEN_AUTO ||
1049          method == AFS_TOKEN_KRB4)) {
1050
1051         KTEXT_ST        ticket;
1052
1053         _reportf(L"Trying Kerberos 4");
1054
1055         if (!realm_of_user[0] ) {
1056             if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) 
1057                 != KSUCCESS) {
1058                 /* can't determine realm of user */
1059                 _reportf(L"krb_get_tf_realm returns %d", rc);
1060                 goto end_krb4;
1061             }
1062         }
1063
1064         _reportf(L"Trying to find %S.%S@%S", ServiceName, CellName, RealmName);
1065         rc = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds);
1066         if (rc == NO_TKT_FIL) {
1067             // if the problem is that we have no krb4 tickets
1068             // do not attempt to continue
1069             _reportf(L"krb_get_cred returns %d (no ticket file)", rc);
1070             goto end_krb4;
1071         }
1072
1073         if (rc != KSUCCESS) {
1074             _reportf(L"Trying to find %S@%S", ServiceName, RealmName);
1075             rc = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds);
1076         }
1077
1078         if (rc != KSUCCESS) {
1079             _reportf(L"Trying to obtain new ticket");
1080             if ((rc = (*pkrb_mk_req)(&ticket, ServiceName, 
1081                                      CellName, RealmName, 0))
1082                 == KSUCCESS) {
1083                 if ((rc = (*pkrb_get_cred)(ServiceName, CellName, 
1084                                            RealmName, &creds)) != KSUCCESS) {
1085                     goto end_krb4;
1086                 } else {
1087                     _reportf(L"Got %S.%S@%S", ServiceName, CellName, RealmName);
1088                 }
1089             } else if ((rc = (*pkrb_mk_req)(&ticket, ServiceName, 
1090                                             "", RealmName, 0))
1091                        == KSUCCESS) {
1092                 if ((rc = (*pkrb_get_cred)(ServiceName, "", 
1093                                            RealmName, &creds)) != KSUCCESS) {
1094                     goto end_krb4;
1095                 } else {
1096                     _reportf(L"Got %S@%S", ServiceName, RealmName);
1097                 }
1098             } else {
1099                 goto end_krb4;
1100             }
1101         }
1102
1103         bGotCreds = TRUE;
1104
1105     end_krb4:
1106         ;
1107     }
1108
1109     if (bGotCreds) {
1110
1111         memset(&aserver, '\0', sizeof(aserver));
1112         StringCchCopyA(aserver.name, MAXKTCNAMELEN, ServiceName);
1113         StringCchCopyA(aserver.cell, MAXKTCREALMLEN, CellName);
1114
1115         memset(&atoken, '\0', sizeof(atoken));
1116         atoken.kvno = (short)creds.kvno;
1117         atoken.startTime = creds.issue_date;
1118         atoken.endTime = (*pkrb_life_to_time)(creds.issue_date,creds.lifetime);
1119         memcpy(&atoken.sessionKey, creds.session, 8);
1120         atoken.ticketLen = creds.ticket_st.length;
1121         memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen);
1122
1123         if (tok_expiration)
1124             *tok_expiration = atoken.endTime;
1125
1126         if (!(rc = ktc_GetToken(&aserver, &btoken, 
1127                                 sizeof(btoken), &aclient)) &&
1128             atoken.kvno == btoken.kvno &&
1129             atoken.ticketLen == btoken.ticketLen &&
1130             !memcmp(&atoken.sessionKey, &btoken.sessionKey, 
1131                     sizeof(atoken.sessionKey)) &&
1132             !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) {
1133
1134             /* success! */
1135             return(0);
1136         }
1137
1138         // Reset the "aclient" structure before we call ktc_SetToken.
1139         // This structure was first set by the ktc_GetToken call when
1140         // we were comparing whether identical tokens already existed.
1141
1142         StringCchCopyA(aclient.name, MAXKTCNAMELEN, creds.pname);
1143         if (creds.pinst[0]) {
1144             StringCchCatA(aclient.name, MAXKTCNAMELEN, ".");
1145             StringCchCatA(aclient.name, MAXKTCNAMELEN, creds.pinst);
1146         }
1147
1148         StringCbCopyA(aclient.instance, sizeof(aclient.instance), "");
1149
1150         StringCchCatA(aclient.name, MAXKTCNAMELEN, "@");
1151                 StringCchCatA(aclient.name, MAXKTCNAMELEN, got524cred ? realm_of_user : creds.realm);
1152
1153         StringCbCopyA(aclient.cell, sizeof(aclient.cell), CellName);
1154
1155         ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName, 
1156                          &aclient, &aserver, &atoken);
1157
1158         if (rc = ktc_SetToken(&aserver, &atoken, &aclient, 0)) {
1159             afs_report_error(rc, "ktc_SetToken()");
1160             return(rc);
1161         }
1162     } else if (method == AFS_TOKEN_AUTO ||
1163                method >= AFS_TOKEN_USER) {
1164         /* we couldn't get a token using Krb5, Krb524 or Krb4, either
1165            because we couldn't get the necessary credentials or
1166            because the method was set to not use those.  Now we
1167            dispatch to any extensions to see if they have better
1168            luck. */
1169
1170         rc = !afs_ext_klog(method,
1171                            identity,
1172                            ServiceName,
1173                            CellName,
1174                            RealmName,
1175                            &ak_cellconfig,
1176                            LifeTime);
1177     } else {
1178         /* if the return code was not set, we should set it now.
1179            Otherwise we let the code go through. */
1180         if (!rc) {
1181             /* No tokens were obtained.  We should report something */
1182             _report_sr1(KHERR_ERROR, IDS_ERR_GENERAL,
1183                         _cptr(CellName));
1184             _resolve();
1185
1186             rc = KHM_ERROR_GENERAL;
1187         }
1188     }
1189
1190     return rc;
1191 }
1192
1193 /**************************************/
1194 /* afs_realm_of_cell():               */
1195 /**************************************/
1196 static char *
1197 afs_realm_of_cell(afs_conf_cell *cellconfig, BOOL referral_fallback)
1198 {
1199     char krbhst[MAX_HSTNM]="";
1200     static char krbrlm[REALM_SZ+1]="";
1201     krb5_context  ctx = 0;
1202     char ** realmlist=NULL;
1203     krb5_error_code r = 0;
1204
1205     if (!cellconfig)
1206         return 0;
1207
1208     if (referral_fallback) {
1209         char * p;
1210         p = strchr(cellconfig->hostName[0], '.');
1211         if (p++)
1212             StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1213         else
1214             StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1215 #if _MSC_VER >= 1400
1216         _strupr_s(krbrlm, sizeof(krbrlm));
1217 #else
1218         _strupr(krbrlm);
1219 #endif
1220     } else {
1221         if ( pkrb5_init_context ) {
1222             r = pkrb5_init_context(&ctx); 
1223             if ( !r )
1224                 r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist);
1225             if ( !r && realmlist && realmlist[0] ) {
1226                 StringCbCopyA(krbrlm, sizeof(krbrlm), realmlist[0]);
1227                 pkrb5_free_host_realm(ctx, realmlist);
1228             }
1229             if (ctx)
1230                 pkrb5_free_context(ctx);
1231         }
1232
1233         if (r) {
1234             if (pkrb_get_krbhst && pkrb_realmofhost) {
1235                 StringCbCopyA(krbrlm, sizeof(krbrlm), 
1236                                (char *)(*pkrb_realmofhost)(cellconfig->hostName[0]));
1237                 if ((*pkrb_get_krbhst)(krbhst, krbrlm, 1) != KSUCCESS)
1238                     krbrlm[0] = '\0';
1239             }
1240
1241             if ( !krbrlm[0] ) {
1242                 char * p;
1243                 p = strchr(cellconfig->hostName[0], '.');
1244                 if (p++)
1245                     StringCbCopyA(krbrlm, sizeof(krbrlm), p);
1246                 else
1247                     StringCbCopyA(krbrlm, sizeof(krbrlm), cellconfig->name);
1248 #if _MSC_VER >= 1400
1249                 _strupr_s(krbrlm, sizeof(krbrlm));
1250 #else
1251                 _strupr(krbrlm);
1252 #endif
1253             }
1254         }
1255     }
1256     return(krbrlm);
1257 }
1258
1259 /**************************************/
1260 /* afs_get_cellconfig():                  */
1261 /**************************************/
1262 static int 
1263 afs_get_cellconfig(char *cell, afs_conf_cell *cellconfig, char *local_cell)
1264 {
1265     int rc;
1266     int ttl;
1267
1268     local_cell[0] = (char)0;
1269     memset(cellconfig, 0, sizeof(*cellconfig));
1270
1271     cellconfig->cbsize = sizeof(*cellconfig);
1272
1273     /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
1274     if (rc = cm_GetRootCellName(local_cell)) {
1275         return(rc);
1276     }
1277
1278     if (strlen(cell) == 0)
1279         StringCbCopyA(cell, (MAXCELLCHARS+1) * sizeof(char), local_cell);
1280
1281     /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */
1282     StringCbCopyA(cellconfig->name, (MAXCELLCHARS+1) * sizeof(char), cell);
1283
1284     rc = cm_SearchCellFile(cell, NULL, afs_get_cellconfig_callback, 
1285                            (void*)cellconfig);
1286     if(rc)
1287         rc = cm_SearchCellByDNS(cell, NULL, &ttl, 
1288                                 afs_get_cellconfig_callback, 
1289                                 (void*) cellconfig);
1290
1291     return rc;
1292 }
1293
1294 /**************************************/
1295 /* afs_get_cellconfig_callback():          */
1296 /**************************************/
1297 static long 
1298 afs_get_cellconfig_callback(void *cellconfig, 
1299                             struct sockaddr_in *addrp, 
1300                             char *namep)
1301 {
1302     afs_conf_cell *cc = (afs_conf_cell *)cellconfig;
1303
1304     cc->hostAddr[cc->numServers] = *addrp;
1305     StringCbCopyA(cc->hostName[cc->numServers], 
1306                   sizeof(cc->hostName[0]), namep);
1307     cc->numServers++;
1308     return(0);
1309 }
1310
1311
1312 /**************************************/
1313 /* afs_report_error():           */
1314 /**************************************/
1315 void
1316 afs_report_error(LONG rc, LPCSTR FailedFunctionName)
1317 {
1318     char message[256];
1319     const char *errText; 
1320
1321     // Using AFS defines as error messages for now, until Transarc 
1322     // gets back to me with "string" translations of each of these 
1323     // const. defines. 
1324     if (rc == KTC_ERROR)
1325         errText = "KTC_ERROR";
1326     else if (rc == KTC_TOOBIG)
1327         errText = "KTC_TOOBIG";
1328     else if (rc == KTC_INVAL)
1329         errText = "KTC_INVAL";
1330     else if (rc == KTC_NOENT)
1331         errText = "KTC_NOENT";
1332     else if (rc == KTC_PIOCTLFAIL)
1333         errText = "KTC_PIOCTLFAIL";
1334     else if (rc == KTC_NOPIOCTL)
1335         errText = "KTC_NOPIOCTL";
1336     else if (rc == KTC_NOCELL)
1337         errText = "KTC_NOCELL";
1338     else if (rc == KTC_NOCM)
1339         errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
1340     else
1341         errText = "Unknown error!";
1342
1343     StringCbPrintfA(message, sizeof(message), 
1344                     "%s\n(%s failed)", errText, FailedFunctionName);
1345     _report_cs1(KHERR_ERROR, L"%1!S!", _cptr(message));
1346     _resolve();
1347     return;
1348 }
1349
1350 DWORD 
1351 GetServiceStatus(LPSTR lpszMachineName, 
1352                  LPSTR lpszServiceName, 
1353                  DWORD *lpdwCurrentState,
1354                  DWORD *lpdwWaitHint) 
1355
1356     DWORD           hr               = NOERROR; 
1357     SC_HANDLE       schSCManager     = NULL; 
1358     SC_HANDLE       schService       = NULL; 
1359     DWORD           fdwDesiredAccess = 0; 
1360     SERVICE_STATUS  ssServiceStatus  = {0}; 
1361     BOOL            fRet             = FALSE; 
1362
1363     *lpdwCurrentState = 0; 
1364  
1365     fdwDesiredAccess = GENERIC_READ; 
1366  
1367     schSCManager = OpenSCManagerA(lpszMachineName,  
1368                                   NULL,
1369                                   fdwDesiredAccess); 
1370  
1371     if(schSCManager == NULL) { 
1372         hr = GetLastError();
1373         goto cleanup; 
1374     } 
1375  
1376     schService = OpenServiceA(schSCManager,
1377                               lpszServiceName,
1378                               fdwDesiredAccess);
1379  
1380     if(schService == NULL) { 
1381         hr = GetLastError();
1382         goto cleanup; 
1383     } 
1384  
1385     fRet = QueryServiceStatus(schService,
1386                               &ssServiceStatus); 
1387  
1388     if(fRet == FALSE) { 
1389         hr = GetLastError(); 
1390         goto cleanup; 
1391     } 
1392  
1393     *lpdwCurrentState = ssServiceStatus.dwCurrentState; 
1394     if (lpdwWaitHint)
1395         *lpdwWaitHint = ssServiceStatus.dwWaitHint;
1396 cleanup: 
1397  
1398     CloseServiceHandle(schService); 
1399     CloseServiceHandle(schSCManager); 
1400  
1401     return(hr); 
1402
1403
1404 DWORD ServiceControl(LPSTR lpszMachineName, 
1405                      LPSTR lpszServiceName,
1406                      DWORD dwNewState) {
1407
1408     DWORD           hr               = NOERROR; 
1409     SC_HANDLE       schSCManager     = NULL; 
1410     SC_HANDLE       schService       = NULL; 
1411     DWORD           fdwDesiredAccess = 0; 
1412     SERVICE_STATUS  ssServiceStatus  = {0}; 
1413     BOOL            fRet             = FALSE; 
1414     DWORD           dwCurrentState   = 0;
1415
1416     dwCurrentState = 0; 
1417  
1418     fdwDesiredAccess = GENERIC_READ;
1419  
1420     schSCManager = OpenSCManagerA(lpszMachineName, NULL, 
1421                                   fdwDesiredAccess); 
1422  
1423     if(schSCManager == NULL) {
1424         hr = GetLastError();
1425         goto cleanup; 
1426     }
1427
1428     fdwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
1429
1430     schService = OpenServiceA(schSCManager, lpszServiceName,
1431                               fdwDesiredAccess);
1432  
1433     if(schService == NULL) {
1434         hr = GetLastError();
1435         goto cleanup; 
1436     } 
1437  
1438     fRet = QueryServiceStatus(schService, &ssServiceStatus);
1439  
1440     if(fRet == FALSE) {
1441         hr = GetLastError(); 
1442         goto cleanup; 
1443     } 
1444  
1445     dwCurrentState = ssServiceStatus.dwCurrentState; 
1446
1447     if (dwCurrentState == SERVICE_STOPPED &&
1448         dwNewState == SERVICE_RUNNING) {
1449
1450         fRet = StartService(schService, 0, NULL);
1451
1452         if (fRet == FALSE) {
1453             hr = GetLastError();
1454             goto cleanup;
1455         }
1456     }
1457
1458     if (dwCurrentState == SERVICE_RUNNING &&
1459         dwNewState == SERVICE_STOPPED) {
1460         fRet = ControlService(schService, SERVICE_CONTROL_STOP, 
1461                               &ssServiceStatus);
1462
1463         if (fRet == FALSE) {
1464             hr = GetLastError();
1465             goto cleanup;
1466         }
1467     }
1468  
1469 cleanup: 
1470  
1471     CloseServiceHandle(schService); 
1472     CloseServiceHandle(schSCManager); 
1473  
1474     return(hr); 
1475 }
1476
1477 khm_boolean
1478 afs_check_for_cell_realm_match(khm_handle identity, char * cell) {
1479     char local_cell[MAXCELLCHARS];
1480     wchar_t wrealm[MAXCELLCHARS];
1481     wchar_t idname[KCDB_IDENT_MAXCCH_NAME];
1482     wchar_t * atsign;
1483     khm_size cb;
1484     char * realm;
1485     afs_conf_cell cellconfig;
1486     int rc;
1487
1488     ZeroMemory(local_cell, sizeof(local_cell));
1489
1490     rc = afs_get_cellconfig(cell, &cellconfig, local_cell);
1491     if (rc)
1492         return FALSE;
1493
1494     realm = afs_realm_of_cell(&cellconfig, FALSE);
1495     if (realm == NULL)
1496         return FALSE;
1497
1498     AnsiStrToUnicode(wrealm, sizeof(wrealm), realm);
1499
1500     cb = sizeof(idname);
1501     idname[0] = L'\0';
1502     kcdb_identity_get_name(identity, idname, &cb);
1503
1504     atsign = wcschr(idname, L'@');
1505     if (atsign && atsign[1] && !_wcsicmp(atsign + 1, wrealm)) {
1506         return TRUE;
1507     } else {
1508         return FALSE;
1509     }
1510 }