2a7ee9e9987facf6c0e75bcf02f3bc5b6efcd4ff
[openafs.git] / src / WINNT / afsd / afslogon.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include "afslogon.h"
11
12 #include <io.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <fcntl.h>
16
17 #include <winsock2.h>
18
19 #include <afs/param.h>
20 #include <afs/stds.h>
21 #include <afs/pioctl_nt.h>
22 #include <afs/kautils.h>
23
24 #include "afsd.h"
25 #include "cm_config.h"
26 #include "krb.h"
27 #include "afskfw.h"
28
29 DWORD LogonOption,TraceOption;
30
31 HANDLE hDLL;
32
33 WSADATA WSAjunk;
34
35 void DebugEvent0(char *a) 
36 {
37         HANDLE h; char *ptbuf[1];
38         if (!ISLOGONTRACE(TraceOption))
39                 return;
40         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
41         ptbuf[0] = a;
42         ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
43         DeregisterEventSource(h);
44 }
45
46 #define MAXBUF_ 131
47 void DebugEvent(char *a,char *b,...) 
48 {
49         HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
50         va_list marker;
51
52         if (!ISLOGONTRACE(TraceOption))
53                 return;
54
55         /*if(!a) */
56                 a = AFS_DAEMON_EVENT_NAME;
57         h = RegisterEventSource(NULL, a);
58         va_start(marker,b);
59         StringCbVPrintf(buf, MAXBUF_+1,b,marker);
60     buf[MAXBUF_] = '\0';
61         ptbuf[0] = buf;
62         ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);\
63         DeregisterEventSource(h);
64         va_end(marker);
65 }
66
67 CHAR *GenRandomName(CHAR *pbuf)
68 {
69         int i;
70         srand( (unsigned)time( NULL ) );
71         for (i=0;i<MAXRANDOMNAMELEN-1;i++)
72                 pbuf[i]='a'+(rand() % 26);
73         pbuf[MAXRANDOMNAMELEN-1]=0;
74         return pbuf;
75 }
76
77 BOOLEAN AFSWillAutoStart(void)
78 {
79         SC_HANDLE scm;
80         SC_HANDLE svc;
81         BOOLEAN flag;
82         BOOLEAN result = FALSE;
83         LPQUERY_SERVICE_CONFIG pConfig = NULL;
84         DWORD BufSize;
85         LONG status;
86
87         /* Open services manager */
88         scm = OpenSCManager(NULL, NULL, GENERIC_READ);
89         if (!scm) return FALSE;
90
91         /* Open AFSD service */
92         svc = OpenService(scm, "TransarcAFSDaemon", SERVICE_QUERY_CONFIG);
93         if (!svc)
94                 goto close_scm;
95
96         /* Query AFSD service config, first just to get buffer size */
97         /* Expected to fail, so don't test return value */
98         (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
99         status = GetLastError();
100         if (status != ERROR_INSUFFICIENT_BUFFER)
101                 goto close_svc;
102
103         /* Allocate buffer */
104         pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
105         if (!pConfig)
106                 goto close_svc;
107
108         /* Query AFSD service config, this time for real */
109         flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
110         if (!flag)
111                 goto free_pConfig;
112
113         /* Is it autostart? */
114         if (pConfig->dwStartType < SERVICE_DEMAND_START)
115                 result = TRUE;
116
117 free_pConfig:
118         GlobalFree(pConfig);
119 close_svc:
120         CloseServiceHandle(svc);
121 close_scm:
122         CloseServiceHandle(scm);
123
124         return result;
125 }
126
127 DWORD MapAuthError(DWORD code)
128 {
129         switch (code) {
130                 /* Unfortunately, returning WN_NO_NETWORK results in the MPR abandoning
131                  * logon scripts for all credential managers, although they will still
132                  * receive logon notifications.  Since we don't want this, we return
133                  * WN_SUCCESS.  This is highly undesirable, but we also don't want to
134                  * break other network providers.
135                  */
136 /*      case KTC_NOCM:
137         case KTC_NOCMRPC:
138                 return WN_NO_NETWORK; */
139         default: return WN_SUCCESS;
140         }
141 }
142
143 BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
144 {
145         hDLL = dll;
146         switch (reason) {
147                 case DLL_PROCESS_ATTACH:
148                         /* Initialize AFS libraries */
149                         rx_Init(0);
150             initAFSDirPath();
151                         ka_Init(0);
152                         break;
153
154                 /* Everything else succeeds but does nothing. */
155                 case DLL_PROCESS_DETACH:
156                 case DLL_THREAD_ATTACH:
157                 case DLL_THREAD_DETACH:
158                 default:
159                         break;
160         }
161
162         return TRUE;
163 }
164
165 DWORD APIENTRY NPGetCaps(DWORD index)
166 {
167         switch (index) {
168                 case WNNC_NET_TYPE:
169                         /* Don't have our own type; use somebody else's. */
170                         return WNNC_NET_SUN_PC_NFS;
171
172                 case WNNC_START:
173                         /* Say we are already started, even though we might wait after we receive NPLogonNotify */
174                         return 1;
175
176                 default:
177                         return 0;
178         }
179 }
180
181 BOOL IsServiceRunning (void)
182 {
183     SERVICE_STATUS Status;
184     SC_HANDLE hManager;
185     memset (&Status, 0x00, sizeof(Status));
186     Status.dwCurrentState = SERVICE_STOPPED;
187
188     if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
189     {
190         SC_HANDLE hService;
191         if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
192         {
193             QueryServiceStatus (hService, &Status);
194             CloseServiceHandle (hService);
195         }
196
197         CloseServiceHandle (hManager);
198     }
199     DebugEvent("AFS AfsLogon - Test Service Running","Return Code[%x] ?Running[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_RUNNING));
200     return (Status.dwCurrentState == SERVICE_RUNNING);
201 }   
202
203 /* LOOKUPKEYCHAIN: macro to look up the value in the list of keys in order until it's found
204    v:variable to receive value (reference type)
205    t:type
206    d:default, in case the value isn't on any of the keys
207    n:name of value */
208 #define LOOKUPKEYCHAIN(v,t,d,n) \
209         do { \
210                 rv = ~ERROR_SUCCESS; \
211                 dwType = t; \
212                 if(hkDom) { \
213                         dwSize = sizeof(v); \
214                         rv = RegQueryValueEx(hkDom, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
215                         if(rv == ERROR_SUCCESS) DebugEvent(NULL, #v " found in hkDom with type [%d]", dwType); \
216                 } \
217                 if(hkDoms && (rv != ERROR_SUCCESS || dwType != t)) { \
218                         dwSize = sizeof(v); \
219                         rv = RegQueryValueEx(hkDoms, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
220                         if(rv == ERROR_SUCCESS) DebugEvent(NULL, #v " found in hkDoms with type [%d]", dwType); \
221                 } \
222                 if(hkNp && (rv != ERROR_SUCCESS || dwType != t)) { \
223                         dwSize = sizeof(v); \
224                         rv = RegQueryValueEx(hkNp, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
225                         if(rv == ERROR_SUCCESS) DebugEvent(NULL, #v " found in hkNp with type [%d]", dwType); \
226                 } \
227                 if(rv != ERROR_SUCCESS || dwType != t) { \
228                         v = d; \
229                         DebugEvent(NULL, #v " being set to default"); \
230                 } \
231         } while(0)
232
233 /* Get domain specific configuration info.  We are returning void because if anything goes wrong
234    we just return defaults.
235  */
236 void GetDomainLogonOptions( PLUID lpLogonId, char * username, char * domain, LogonOptions_t *opt ) {
237         HKEY hkParm = NULL; /* Service parameter */
238         HKEY hkNp = NULL;   /* network provider key */
239         HKEY hkDoms = NULL; /* domains key */
240         HKEY hkDom = NULL;  /* DOMAINS/domain key */
241         HKEY hkTemp = NULL;
242         LONG rv;
243         DWORD dwSize;
244         DWORD dwType;
245         DWORD dwDummy;
246         char computerName[MAX_COMPUTERNAME_LENGTH + 1];
247         char *effDomain;
248
249         DebugEvent(NULL,"In GetDomainLogonOptions for user [%s] in domain [%s]", username, domain);
250         /* If the domain is the same as the Netbios computer name, we use the LOCALHOST domain name*/
251         opt->flags = LOGON_FLAG_REMOTE;
252         if(domain) {
253                 dwSize = MAX_COMPUTERNAME_LENGTH;
254                 if(GetComputerName(computerName, &dwSize)) {
255                         if(!stricmp(computerName, domain)) {
256                                 effDomain = "LOCALHOST";
257                                 opt->flags = LOGON_FLAG_LOCAL;
258                         }
259                         else
260                                 effDomain = domain;
261                 }
262         } else
263                 effDomain = NULL;
264
265         rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY, 0, KEY_READ, &hkParm );
266         if(rv != ERROR_SUCCESS) {
267                 hkParm = NULL;
268                 DebugEvent(NULL, "GetDomainLogonOption: Can't open parms key [%d]", rv);
269         }
270
271         rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CLIENT_PROVIDER_KEY, 0, KEY_READ, &hkNp );
272         if(rv != ERROR_SUCCESS) {
273                 hkNp = NULL;
274                 DebugEvent(NULL, "GetDomainLogonOptions: Can't open NP key [%d]", rv);
275         }
276
277         if(hkNp) {
278                 rv = RegOpenKeyEx( hkNp, REG_CLIENT_DOMAINS_SUBKEY, 0, KEY_READ, &hkDoms );
279                 if( rv != ERROR_SUCCESS ) {
280                         hkDoms = NULL;
281                         DebugEvent(NULL, "GetDomainLogonOptions: Can't open Domains key [%d]", rv);
282                 }
283         }
284
285         if(hkDoms && effDomain) {
286                 rv = RegOpenKeyEx( hkDoms, effDomain, 0, KEY_READ, &hkDom );
287                 if( rv != ERROR_SUCCESS ) {
288                         hkDom = NULL;
289                         DebugEvent( NULL, "GetDomainLogonOptions: Can't open domain key for [%s] [%d]", effDomain, rv);
290                         /* If none of the domains match, we shouldn't use the domain key either */
291                         RegCloseKey(hkDoms);
292                         hkDoms = NULL;
293                 }
294         } else
295                 DebugEvent( NULL, "Not opening domain key for [%s]", effDomain);
296
297         /* Each individual can either be specified on the domain key, the domains key or in the
298            net provider key.  They fail over in that order.  If none is found, we just use the 
299            defaults. */
300
301         /* LogonOption */
302         LOOKUPKEYCHAIN(opt->LogonOption, REG_DWORD, DEFAULT_LOGON_OPTION, REG_CLIENT_LOGON_OPTION_PARM);
303
304         /* FailLoginsSilently */
305         dwSize = sizeof(dwDummy);
306         rv = RegQueryValueEx(hkParm, REG_CLIENT_FAIL_SILENTLY_PARM, 0, &dwType, (LPBYTE) &dwDummy, &dwSize);
307         if(rv != ERROR_SUCCESS)
308                 LOOKUPKEYCHAIN(dwDummy, REG_DWORD, DEFAULT_FAIL_SILENTLY, REG_CLIENT_FAIL_SILENTLY_PARM);
309     opt->failSilently = !!dwDummy;
310
311         /* Retry interval */
312         LOOKUPKEYCHAIN(opt->retryInterval, REG_DWORD, DEFAULT_RETRY_INTERVAL, REG_CLIENT_RETRY_INTERVAL_PARM);
313
314         /* Sleep interval */
315         LOOKUPKEYCHAIN(opt->sleepInterval, REG_DWORD, DEFAULT_SLEEP_INTERVAL, REG_CLIENT_SLEEP_INTERVAL_PARM);
316
317         opt->logonScript = NULL;
318         opt->smbName = NULL;
319
320         if(!ISLOGONINTEGRATED(opt->LogonOption)) {
321                 goto cleanup; /* no need to lookup the logon script */
322         }
323
324         /* come up with SMB username */
325         if(ISHIGHSECURITY(opt->LogonOption)) {
326         opt->smbName = malloc( MAXRANDOMNAMELEN );
327                 GenRandomName(opt->smbName);
328         } else {
329                 /* username and domain for logon session is not necessarily the same as
330                    username and domain passed into network provider. */
331                 PSECURITY_LOGON_SESSION_DATA plsd;
332                 char lsaUsername[MAX_USERNAME_LENGTH];
333                 char lsaDomain[MAX_DOMAIN_LENGTH];
334                 size_t len, tlen;
335
336         LsaGetLogonSessionData(lpLogonId, &plsd);
337         
338                 UnicodeStringToANSI(plsd->UserName, lsaUsername, MAX_USERNAME_LENGTH);
339                 UnicodeStringToANSI(plsd->LogonDomain, lsaDomain, MAX_DOMAIN_LENGTH);
340
341                 DebugEvent(NULL,"PLSD username[%s] domain[%s]",lsaUsername,lsaDomain);
342
343                 if(SUCCEEDED(StringCbLength(lsaUsername, MAX_USERNAME_LENGTH, &tlen)))
344                         len = tlen;
345                 else
346                         goto bad_strings;
347
348                 if(SUCCEEDED(StringCbLength(lsaDomain, MAX_DOMAIN_LENGTH, &tlen)))
349                         len += tlen;
350                 else
351                         goto bad_strings;
352
353                 len += 2;
354
355                 opt->smbName = malloc(len);
356
357                 StringCbCopy(opt->smbName, len, lsaDomain);
358                 StringCbCat(opt->smbName, len, "\\");
359                 StringCbCat(opt->smbName, len, lsaUsername);
360
361                 strlwr(opt->smbName);
362
363 bad_strings:
364                 LsaFreeReturnBuffer(plsd);
365         }
366
367         DebugEvent(NULL,"Looking up logon script");
368         /* Logon script */
369         /* First find out where the key is */
370         hkTemp = NULL;
371         rv = ~ERROR_SUCCESS;
372         dwType = 0;
373         if(hkDom)
374             rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
375         if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
376                 hkTemp = hkDom;
377                 DebugEvent(NULL,"Located logon script in hkDom");
378         }
379         else if(hkDoms)
380             rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
381         if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
382                 hkTemp = hkDoms;
383                 DebugEvent(NULL,"Located logon script in hkDoms");
384         }
385         /* Note that the LogonScript in the NP key is only used if we are doing high security. */
386         else if(hkNp && ISHIGHSECURITY(opt->LogonOption))
387             rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
388         if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
389                 hkTemp = hkNp;
390                 DebugEvent(NULL,"Located logon script in hkNp");
391         }
392
393         if(hkTemp) {
394                 WCHAR *regscript        = NULL;
395                 WCHAR *regexscript      = NULL;
396                 WCHAR *regexuscript     = NULL;
397                 WCHAR *wuname           = NULL;
398                 HRESULT hr;
399
400                 size_t len;
401                 
402                 StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
403                 len ++;
404
405                 wuname = malloc(len * sizeof(WCHAR));
406                 MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,len*sizeof(WCHAR));
407
408                 DebugEvent(NULL,"Username is set for [%S]", wuname);
409
410                 /* dwSize still has the size of the required buffer in bytes. */
411         regscript = malloc(dwSize);
412                 rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
413                 if(rv != ERROR_SUCCESS) {/* what the ..? */
414                         DebugEvent(NULL,"Can't look up logon script [%d]",rv);
415                         goto doneLogonScript;
416                 }
417                 
418                 DebugEvent(NULL,"Found logon script [%S]", regscript);
419
420                 if(dwType == REG_EXPAND_SZ) {
421                         DWORD dwReq;
422
423                         dwSize += MAX_PATH * sizeof(WCHAR);  /* make room for environment expansion. */
424                         regexscript = malloc(dwSize);
425                         dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
426                         free(regscript);
427                         regscript = regexscript;
428                         regexscript = NULL;
429                         if(dwReq > (dwSize / sizeof(WCHAR))) {
430                                 DebugEvent(NULL,"Overflow while expanding environment strings.");
431                                 goto doneLogonScript;
432                         }
433                 }
434
435                 DebugEvent(NULL,"After expanding env strings [%S]", regscript);
436
437                 if(wcsstr(regscript, L"%s")) {
438                 dwSize += len * sizeof(WCHAR); /* make room for username expansion */
439                         regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
440                         hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
441                 } else {
442                         regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
443                         hr = StringCbCopyW(regexuscript, dwSize, regscript);
444                 }
445
446                 DebugEvent(NULL,"After expanding username [%S]", regexuscript);
447
448                 if(hr == S_OK)
449                         opt->logonScript = regexuscript;
450                 else
451                         LocalFree(regexuscript);
452
453 doneLogonScript:
454                 if(wuname) free(wuname);
455                 if(regscript) free(regscript);
456                 if(regexscript) free(regexscript);
457         }
458
459 cleanup:
460         if(hkNp) RegCloseKey(hkNp);
461         if(hkDom) RegCloseKey(hkDom);
462         if(hkDoms) RegCloseKey(hkDoms);
463         if(hkParm) RegCloseKey(hkParm);
464 }
465
466 #undef LOOKUPKEYCHAIN
467
468 /* Try to find out which cell the given path is in.  We must retain
469    the contents of *cell in case of failure. *cell is assumed to be
470    at least cellLen chars */
471 DWORD GetFileCellName(char * path, char * cell, size_t cellLen) {
472         struct ViceIoctl blob;
473         char tcell[MAX_PATH];
474         DWORD code;
475
476         blob.in_size = 0;
477         blob.out_size = MAX_PATH;
478         blob.out = tcell;
479
480         code = pioctl(path, VIOC_FILE_CELL_NAME, &blob, 1);
481
482         if(!code) {
483                 strncpy(cell, tcell, cellLen);
484                 cell[cellLen - 1] = '\0';
485         }
486         return code;
487 }
488
489
490 static BOOL
491 WINAPI
492 UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
493 {
494     CPINFO CodePageInfo;
495
496     GetCPInfo(CP_ACP, &CodePageInfo);
497
498     if (CodePageInfo.MaxCharSize > 1)
499         // Only supporting non-Unicode strings
500         return FALSE;
501     
502     if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0')
503     {
504         // Looks like unicode, better translate it
505         // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
506         WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
507                             lpszOutputString, nOutStringLen-1, NULL, NULL);
508         lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
509         return TRUE;
510     }
511         else
512                 lpszOutputString[0] = '\0';
513     return FALSE;
514 }  // UnicodeStringToANSI
515
516 DWORD APIENTRY NPLogonNotify(
517         PLUID lpLogonId,
518         LPCWSTR lpAuthentInfoType,
519         LPVOID lpAuthentInfo,
520         LPCWSTR lpPreviousAuthentInfoType,
521         LPVOID lpPreviousAuthentInfo,
522         LPWSTR lpStationName,
523         LPVOID StationHandle,
524         LPWSTR *lpLogonScript)
525 {
526         char uname[MAX_USERNAME_LENGTH]="";
527         char password[MAX_PASSWORD_LENGTH]="";
528         char logonDomain[MAX_DOMAIN_LENGTH]="";
529         char cell[256]="<non-integrated logon>";
530         char homePath[MAX_PATH]="";
531
532         MSV1_0_INTERACTIVE_LOGON *IL;
533
534         DWORD code;
535
536         int pw_exp;
537         char *reason;
538         char *ctemp;
539
540         BOOLEAN interactive;
541         BOOLEAN flag;
542         DWORD LSPtype, LSPsize;
543         HKEY NPKey;
544
545         HWND hwndOwner = (HWND)StationHandle;
546
547         BOOLEAN afsWillAutoStart;
548
549     BOOLEAN uppercased_name = TRUE;
550
551         LogonOptions_t opt; /* domain specific logon options */
552         int retryInterval;
553         int sleepInterval;
554
555     /* Initialize Logon Script to none */
556         *lpLogonScript=NULL;
557     
558         /* TODO: We should check the value of lpAuthentInfoType before assuming that it is
559                  MSV1_0_INTERACTIVE_LOGON though for our purposes KERB_INTERACTIVE_LOGON is
560                          co-incidentally equivalent. */
561         IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
562
563         /* Are we interactive? */
564         interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
565
566         /* Convert from Unicode to ANSI */
567
568         /*TODO: Use SecureZeroMemory to erase passwords */
569         UnicodeStringToANSI(IL->UserName, uname, 256);
570         UnicodeStringToANSI(IL->Password, password, 256);
571         UnicodeStringToANSI(IL->LogonDomainName, logonDomain, 256);
572
573         /* Make sure AD-DOMANS sent from login that is sent to us is striped */
574     ctemp = strchr(uname, '@');
575     if (ctemp) *ctemp = 0;
576
577     /* is the name all uppercase? */
578     for ( ctemp = uname; *ctemp ; ctemp++) {
579         if ( islower(*ctemp) ) {
580             uppercased_name = FALSE;
581             break;
582         }
583     }
584
585         (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY,
586                         0, KEY_QUERY_VALUE, &NPKey);
587         LSPsize=sizeof(TraceOption);
588         RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
589                      &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
590
591         RegCloseKey (NPKey);
592
593         /*
594          * Get Logon options
595          */
596
597         GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
598         retryInterval = opt.retryInterval;
599         sleepInterval = opt.sleepInterval;
600         *lpLogonScript = opt.logonScript;
601
602         DebugEvent(NULL,"Got logon script: %S",opt.logonScript);
603
604         afsWillAutoStart = AFSWillAutoStart();
605
606         DebugEvent("AFS AfsLogon - NPLogonNotify","LogonOption[%x], Service AutoStart[%d]",
607                 opt.LogonOption,afsWillAutoStart);
608     
609     /* Check for zero length password if integrated logon*/
610         if ( ISLOGONINTEGRATED(opt.LogonOption) )  {
611         if ( password[0] == 0 ) {
612             code = GT_PW_NULL;
613             reason = "zero length password is illegal";
614             code=0;
615         }
616
617         /* Get cell name if doing integrated logon.  
618                    We might overwrite this if we are logging into an AD realm and we find out that
619                    the user's home dir is in some other cell. */
620                 code = cm_GetRootCellName(cell);
621                 if (code < 0) { 
622                         code = KTC_NOCELL;
623                         reason = "unknown cell";
624                         code=0;
625                 }
626
627                 /* We get the user's home directory path, if applicable, though we can't lookup the
628                    cell right away because the client service may not have started yet. This call
629                    also sets the AD_REALM flag in opt.flags if applicable. */
630                 if(ISREMOTE(opt.flags))
631                         GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
632     }
633
634     /* loop until AFS is started. */
635     while (TRUE) {
636                 if(ISADREALM(opt.flags)) {
637                         code = GetFileCellName(homePath,cell,256);
638                         if(!code) {
639                                 DebugEvent(NULL,"profile path [%s] is in cell [%s]",homePath,cell);
640                         }
641                         /* Don't bail out if GetFileCellName failed.
642                          * The home dir may not be in AFS after all. 
643                          */
644                 } else
645                 code=0;
646                 
647         /* if Integrated Logon  */
648         if (ISLOGONINTEGRATED(opt.LogonOption))
649                 {                       
650                         if ( KFW_is_available() ) {
651                 code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
652                                 DebugEvent(NULL,"KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",uname,opt.smbName,cell,code);
653                         }
654                         else {
655                 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
656                                                 uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
657                                                 &reason);
658                                 DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2","Code[%x]",
659                                                         code);
660                         }
661             if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && uppercased_name ) {
662                 for ( ctemp = uname; *ctemp ; ctemp++) {
663                     *ctemp = tolower(*ctemp);
664                 }
665                 uppercased_name = FALSE;
666                 continue;
667             }
668                 }
669                 else {  
670             /*JUST check to see if its running*/
671                     if (IsServiceRunning())
672                 break;
673                     code = KTC_NOCM;
674                     if (!afsWillAutoStart)
675                 break;
676                 }
677
678                 /* is service started yet?*/
679         DebugEvent("AFS AfsLogon - ka_UserAuthenticateGeneral2","Code[%x] uname[%s] Cell[%s]",
680                    code,uname,cell);
681
682                 /* If we've failed because the client isn't running yet and the
683          * client is set to autostart (and therefore it makes sense for
684          * us to wait for it to start) then sleep a while and try again. 
685          * If the error was something else, then give up. */
686                 if (code != KTC_NOCM && code != KTC_NOCMRPC || !afsWillAutoStart)
687                         break;
688                 
689         /* If the retry interval has expired and we still aren't
690          * logged in, then just give up if we are not in interactive
691          * mode or the failSilently flag is set, otherwise let the
692          * user know we failed and give them a chance to try again. */
693         if (retryInterval <= 0) {
694             reason = "AFS not running";
695             if (!interactive || opt.failSilently)
696                 break;
697                         flag = MessageBox(hwndOwner,
698                                "AFS is still starting.  Retry?",
699                                "AFS Logon",
700                                MB_ICONQUESTION | MB_RETRYCANCEL);
701                         if (flag == IDCANCEL)
702                 break;
703
704             /* Wait just a little while and try again */
705             retryInterval = sleepInterval = DEFAULT_SLEEP_INTERVAL;
706         }
707
708         if (retryInterval < sleepInterval)
709                         sleepInterval = retryInterval;
710
711                 Sleep(sleepInterval * 1000);
712
713         retryInterval -= sleepInterval;
714     }
715
716     /* remove any kerberos 5 tickets currently held by the SYSTEM account */
717     if ( KFW_is_available() )
718         KFW_AFS_destroy_tickets_for_cell(cell);
719
720         if (code) {
721         char msg[128];
722
723                 StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
724
725                 if (interactive && !opt.failSilently)
726                         MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
727                 else {
728             HANDLE h;
729             char *ptbuf[1];
730
731             h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
732             ptbuf[0] = msg;
733             ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
734                          1, 0, ptbuf, NULL);
735             DeregisterEventSource(h);
736         }
737             code = MapAuthError(code);
738                 SetLastError(code);
739
740                 if (ISLOGONINTEGRATED(LogonOption) && (code!=0))
741                 {
742                         if (*lpLogonScript)
743                                 LocalFree(*lpLogonScript);
744                         *lpLogonScript = NULL;
745                         if (!afsWillAutoStart)  // its not running, so if not autostart or integrated logon then just skip
746                                 code = 0;
747
748                 }
749         }
750
751         if(opt.smbName) free(opt.smbName);
752
753         DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
754         return code;
755 }
756
757 DWORD APIENTRY NPPasswordChangeNotify(
758         LPCWSTR lpAuthentInfoType,
759         LPVOID lpAuthentInfo,
760         LPCWSTR lpPreviousAuthentInfoType,
761         LPVOID lpPreviousAuthentInfo,
762         LPWSTR lpStationName,
763         LPVOID StationHandle,
764         DWORD dwChangeInfo)
765 {
766         DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
767         return 0;
768 }
769
770 #include <Winwlx.h>
771
772 VOID AFS_Logoff_Event( 
773     PWLX_NOTIFICATION_INFO pInfo )
774 {
775     DWORD code;
776     if (code = ktc_ForgetAllTokens())
777         DebugEvent(NULL,"AFS AfsLogon - AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
778     else
779         DebugEvent0("AFS AfsLogon - AFS_Logoff_Event - ForgetAllTokens succeeded");
780 }   
781
782
783
784