96bae52f8e9c379fe9aff18871d23b513e8d7d5d
[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         _vsnprintf(buf,MAXBUF_,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                 int len;
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                 DebugEvent(NULL,"PLSD Unicode username[%S] domain[%S]",plsd->UserName.Buffer,plsd->LogonDomain.Buffer);
343                 DebugEvent(NULL,"PLSD lengths username[%d] domain[%d]",plsd->UserName.Length,plsd->LogonDomain.Length);
344
345         len = strlen(lsaUsername) + strlen(lsaDomain) + 2;
346
347                 opt->smbName = malloc(len);
348
349                 strcpy(opt->smbName, lsaDomain);
350                 strcat(opt->smbName, "\\");
351                 strcat(opt->smbName, lsaUsername);
352
353                 strlwr(opt->smbName);
354
355                 LsaFreeReturnBuffer(plsd);
356         }
357
358         DebugEvent(NULL,"Looking up logon script");
359         /* Logon script */
360         /* First find out where the key is */
361         hkTemp = NULL;
362         rv = ~ERROR_SUCCESS;
363         dwType = 0;
364         if(hkDom)
365             rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
366         if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
367                 hkTemp = hkDom;
368                 DebugEvent(NULL,"Located logon script in hkDom");
369         }
370         else if(hkDoms)
371             rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
372         if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
373                 hkTemp = hkDoms;
374                 DebugEvent(NULL,"Located logon script in hkDoms");
375         }
376         /* Note that the LogonScript in the NP key is only used if we are doing high security. */
377         else if(hkNp && ISHIGHSECURITY(opt->LogonOption))
378             rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
379         if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
380                 hkTemp = hkNp;
381                 DebugEvent(NULL,"Located logon script in hkNp");
382         }
383
384         if(hkTemp) {
385                 WCHAR *regscript        = NULL;
386                 WCHAR *regexscript      = NULL;
387                 WCHAR *regexuscript     = NULL;
388                 WCHAR *wuname           = NULL;
389                 HRESULT hr;
390
391                 int len = strlen(opt->smbName) + 1;
392
393                 wuname = malloc(len * sizeof(WCHAR));
394                 MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,len*sizeof(WCHAR));
395
396                 DebugEvent(NULL,"Username is set for [%S]", wuname);
397
398                 /* dwSize still has the size of the required buffer in bytes. */
399         regscript = malloc(dwSize);
400                 rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
401                 if(rv != ERROR_SUCCESS) {/* what the ..? */
402                         DebugEvent(NULL,"Can't look up logon script [%d]",rv);
403                         goto doneLogonScript;
404                 }
405                 
406                 DebugEvent(NULL,"Found logon script [%S]", regscript);
407
408                 if(dwType == REG_EXPAND_SZ) {
409                         dwSize += MAX_PATH * sizeof(WCHAR);  /* make room for environment expansion. */
410                         regexscript = malloc(dwSize);
411                         rv = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
412                         free(regscript);
413                         regscript = regexscript;
414                         regexscript = NULL;
415                         if(rv > (dwSize / sizeof(WCHAR))) {
416                                 DebugEvent(NULL,"Overflow while expanding environment strings.");
417                                 goto doneLogonScript;
418                         }
419                 }
420
421                 DebugEvent(NULL,"After expanding env strings [%S]", regscript);
422
423                 if(wcsstr(regscript, L"%s")) {
424                 dwSize += 256 * sizeof(WCHAR); /* make room for username expansion */
425                         regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
426                         hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
427                 } else {
428                         regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
429                         wcscpy(regexuscript, regscript);
430                         hr = S_OK;
431                 }
432
433                 DebugEvent(NULL,"After expanding username [%S]", regexuscript);
434
435                 if(hr == S_OK)
436                         opt->logonScript = regexuscript;
437                 else
438                         LocalFree(regexuscript);
439
440 doneLogonScript:
441                 if(wuname) free(wuname);
442                 if(regscript) free(regscript);
443                 if(regexscript) free(regexscript);
444         }
445
446 cleanup:
447         if(hkNp) RegCloseKey(hkNp);
448         if(hkDom) RegCloseKey(hkDom);
449         if(hkDoms) RegCloseKey(hkDoms);
450         if(hkParm) RegCloseKey(hkParm);
451 }
452
453 #undef LOOKUPKEYCHAIN
454
455 /* Try to find out which cell the given path is in.  We must retain
456    the contents of *cell in case of failure. *cell is assumed to be
457    at least cellLen chars */
458 DWORD GetFileCellName(char * path, char * cell, size_t cellLen) {
459         struct ViceIoctl blob;
460         char tcell[MAX_PATH];
461         DWORD code;
462
463         blob.in_size = 0;
464         blob.out_size = MAX_PATH;
465         blob.out = tcell;
466
467         code = pioctl(path, VIOC_FILE_CELL_NAME, &blob, 1);
468
469         if(!code) {
470                 strncpy(cell, tcell, cellLen);
471                 cell[cellLen - 1] = '\0';
472         }
473         return code;
474 }
475
476
477 static BOOL
478 WINAPI
479 UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
480 {
481     CPINFO CodePageInfo;
482
483     GetCPInfo(CP_ACP, &CodePageInfo);
484
485     if (CodePageInfo.MaxCharSize > 1)
486         // Only supporting non-Unicode strings
487         return FALSE;
488     
489     if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0')
490     {
491         // Looks like unicode, better translate it
492         // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
493         WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
494                             lpszOutputString, nOutStringLen-1, NULL, NULL);
495         lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
496         return TRUE;
497     }
498         else
499                 lpszOutputString[0] = '\0';
500     return FALSE;
501 }  // UnicodeStringToANSI
502
503 DWORD APIENTRY NPLogonNotify(
504         PLUID lpLogonId,
505         LPCWSTR lpAuthentInfoType,
506         LPVOID lpAuthentInfo,
507         LPCWSTR lpPreviousAuthentInfoType,
508         LPVOID lpPreviousAuthentInfo,
509         LPWSTR lpStationName,
510         LPVOID StationHandle,
511         LPWSTR *lpLogonScript)
512 {
513         char uname[MAX_USERNAME_LENGTH]="";
514         char password[MAX_PASSWORD_LENGTH]="";
515         char logonDomain[MAX_DOMAIN_LENGTH]="";
516         char cell[256]="<non-integrated logon>";
517         char homePath[MAX_PATH]="";
518
519         MSV1_0_INTERACTIVE_LOGON *IL;
520
521         DWORD code;
522         int len;
523
524         int pw_exp;
525         char *reason;
526         char *ctemp;
527
528         BOOLEAN interactive;
529         BOOLEAN flag;
530         DWORD LSPtype, LSPsize;
531         HKEY NPKey;
532
533         HWND hwndOwner = (HWND)StationHandle;
534
535         BOOLEAN afsWillAutoStart;
536
537     BOOLEAN uppercased_name = TRUE;
538
539         LogonOptions_t opt; /* domain specific logon options */
540         int retryInterval;
541         int sleepInterval;
542
543     /* Initialize Logon Script to none */
544         *lpLogonScript=NULL;
545     
546         /* TODO: We should check the value of lpAuthentInfoType before assuming that it is
547                  MSV1_0_INTERACTIVE_LOGON though for our purposes KERB_INTERACTIVE_LOGON is
548                          co-incidentally equivalent. */
549         IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
550
551         /* Are we interactive? */
552         interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
553
554         /* Convert from Unicode to ANSI */
555
556         /*TODO: Use SecureZeroMemory to erase passwords */
557         UnicodeStringToANSI(IL->UserName, uname, 256);
558         UnicodeStringToANSI(IL->Password, password, 256);
559         UnicodeStringToANSI(IL->LogonDomainName, logonDomain, 256);
560
561         /* Make sure AD-DOMANS sent from login that is sent to us is striped */
562     ctemp = strchr(uname, '@');
563     if (ctemp) *ctemp = 0;
564
565     /* is the name all uppercase? */
566     for ( ctemp = uname; *ctemp ; ctemp++) {
567         if ( islower(*ctemp) ) {
568             uppercased_name = FALSE;
569             break;
570         }
571     }
572
573         (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY,
574                         0, KEY_QUERY_VALUE, &NPKey);
575         LSPsize=sizeof(TraceOption);
576         RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
577                      &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
578
579         RegCloseKey (NPKey);
580
581         /*
582          * Get Logon options
583          */
584
585         GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
586         retryInterval = opt.retryInterval;
587         sleepInterval = opt.sleepInterval;
588         *lpLogonScript = opt.logonScript;
589
590         DebugEvent(NULL,"Got logon script: %S",opt.logonScript);
591
592         afsWillAutoStart = AFSWillAutoStart();
593
594         DebugEvent("AFS AfsLogon - NPLogonNotify","LogonOption[%x], Service AutoStart[%d]",
595                 opt.LogonOption,afsWillAutoStart);
596     
597     /* Check for zero length password if integrated logon*/
598         if ( ISLOGONINTEGRATED(opt.LogonOption) )  {
599         if ( password[0] == 0 ) {
600             code = GT_PW_NULL;
601             reason = "zero length password is illegal";
602             code=0;
603         }
604
605         /* Get cell name if doing integrated logon.  
606                    We might overwrite this if we are logging into an AD realm and we find out that
607                    the user's home dir is in some other cell. */
608                 code = cm_GetRootCellName(cell);
609                 if (code < 0) { 
610                         code = KTC_NOCELL;
611                         reason = "unknown cell";
612                         code=0;
613                 }
614
615                 /* We get the user's home directory path, if applicable, though we can't lookup the
616                    cell right away because the client service may not have started yet. This call
617                    also sets the AD_REALM flag in opt.flags if applicable. */
618                 if(ISREMOTE(opt.flags))
619                         GetAdHomePath(homePath,MAX_PATH,lpLogonId,IL,&opt);
620     }
621
622     /* loop until AFS is started. */
623     while (TRUE) {
624                 if(ISADREALM(opt.flags)) {
625                         code = GetFileCellName(homePath,cell,256);
626                         if(!code) {
627                                 DebugEvent(NULL,"profile path [%s] is in cell [%s]",homePath,cell);
628                         }
629                         /* Don't bail out if GetFileCellName failed.
630                          * The home dir may not be in AFS after all. 
631                          */
632                 } else
633                 code=0;
634                 
635         /* if Integrated Logon  */
636         if (ISLOGONINTEGRATED(opt.LogonOption))
637                 {                       
638                         if ( KFW_is_available() ) {
639                 code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
640                                 DebugEvent(NULL,"KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",uname,opt.smbName,cell,code);
641                         }
642                         else {
643                 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
644                                                 uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
645                                                 &reason);
646                                 DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2","Code[%x]",
647                                                         code);
648                         }
649             if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && uppercased_name ) {
650                 for ( ctemp = uname; *ctemp ; ctemp++) {
651                     *ctemp = tolower(*ctemp);
652                 }
653                 uppercased_name = FALSE;
654                 continue;
655             }
656                 }
657                 else {  
658             /*JUST check to see if its running*/
659                     if (IsServiceRunning())
660                 break;
661                     code = KTC_NOCM;
662                     if (!afsWillAutoStart)
663                 break;
664                 }
665
666                 /* is service started yet?*/
667         DebugEvent("AFS AfsLogon - ka_UserAuthenticateGeneral2","Code[%x] uname[%s] Cell[%s]",
668                    code,uname,cell);
669
670                 /* If we've failed because the client isn't running yet and the
671          * client is set to autostart (and therefore it makes sense for
672          * us to wait for it to start) then sleep a while and try again. 
673          * If the error was something else, then give up. */
674                 if (code != KTC_NOCM && code != KTC_NOCMRPC || !afsWillAutoStart)
675                         break;
676                 
677         /* If the retry interval has expired and we still aren't
678          * logged in, then just give up if we are not in interactive
679          * mode or the failSilently flag is set, otherwise let the
680          * user know we failed and give them a chance to try again. */
681         if (retryInterval <= 0) {
682             reason = "AFS not running";
683             if (!interactive || opt.failSilently)
684                 break;
685                         flag = MessageBox(hwndOwner,
686                                "AFS is still starting.  Retry?",
687                                "AFS Logon",
688                                MB_ICONQUESTION | MB_RETRYCANCEL);
689                         if (flag == IDCANCEL)
690                 break;
691
692             /* Wait just a little while and try again */
693             retryInterval = sleepInterval = DEFAULT_SLEEP_INTERVAL;
694         }
695
696         if (retryInterval < sleepInterval)
697                         sleepInterval = retryInterval;
698
699                 Sleep(sleepInterval * 1000);
700
701         retryInterval -= sleepInterval;
702     }
703
704     /* remove any kerberos 5 tickets currently held by the SYSTEM account */
705     if ( KFW_is_available() )
706         KFW_AFS_destroy_tickets_for_cell(cell);
707
708         if (code) {
709         char msg[128];
710         sprintf(msg, "Integrated login failed: %s", reason);
711
712                 if (interactive && !opt.failSilently)
713                         MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
714                 else {
715             HANDLE h;
716             char *ptbuf[1];
717
718             h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
719             ptbuf[0] = msg;
720             ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
721                          1, 0, ptbuf, NULL);
722             DeregisterEventSource(h);
723         }
724             code = MapAuthError(code);
725                 SetLastError(code);
726
727                 if (ISLOGONINTEGRATED(LogonOption) && (code!=0))
728                 {
729                         if (*lpLogonScript)
730                                 LocalFree(*lpLogonScript);
731                         *lpLogonScript = NULL;
732                         if (!afsWillAutoStart)  // its not running, so if not autostart or integrated logon then just skip
733                                 code = 0;
734
735                 }
736         }
737
738         if(opt.smbName) free(opt.smbName);
739
740         DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
741         return code;
742 }
743
744 DWORD APIENTRY NPPasswordChangeNotify(
745         LPCWSTR lpAuthentInfoType,
746         LPVOID lpAuthentInfo,
747         LPCWSTR lpPreviousAuthentInfoType,
748         LPVOID lpPreviousAuthentInfo,
749         LPWSTR lpStationName,
750         LPVOID StationHandle,
751         DWORD dwChangeInfo)
752 {
753         DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
754         return 0;
755 }
756
757 #include <Winwlx.h>
758
759 VOID AFS_Logoff_Event( 
760     PWLX_NOTIFICATION_INFO pInfo )
761 {
762     DWORD code;
763     if (code = ktc_ForgetAllTokens())
764         DebugEvent("AFS AfsLogon - AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
765     else
766         DebugEvent0("AFS AfsLogon - AFS_Logoff_Event - ForgetAllTokens succeeded");
767 }   
768
769
770
771