c966486d7d0f4f73dd23eef3a1f357a4614b92f8
[openafs.git] / src / WINNT / afsd / afsd_init.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 <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <roken.h>
14
15 #include <afs/stds.h>
16 #include <afs/afs_args.h>
17
18 #include <windows.h>
19 #include <string.h>
20 #include <nb30.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <locale.h>
24 #include <mbctype.h>
25 #include <winsock2.h>
26 #include <ErrorRep.h>
27
28 #include <osi.h>
29 #include "afsd.h"
30 #ifdef USE_BPLUS
31 #include "cm_btree.h"
32 #endif
33 #include <rx\rx.h>
34 #include <rx\rx_null.h>
35 #include <rx\rxstat.h>
36 #include <WINNT/syscfg.h>
37 #include <WINNT/afsreg.h>
38 #include <afs\afscbint.h>
39
40 #include "smb.h"
41 #include "cm_rpc.h"
42 #include "lanahelper.h"
43 #include <strsafe.h>
44 #include "cm_memmap.h"
45 #include "msrpc.h"
46 #ifdef DEBUG
47 #include <crtdbg.h>
48 #endif
49
50 extern afs_uint32 cryptall;
51 extern afs_uint32 cm_anonvldb;
52 extern int cm_enableServerLocks;
53 extern int cm_followBackupPath;
54 extern int cm_deleteReadOnly;
55 #ifdef USE_BPLUS
56 extern afs_int32 cm_BPlusTrees;
57 #endif
58 extern afs_int32 cm_OfflineROIsValid;
59 extern afs_int32 cm_giveUpAllCBs;
60 extern const clientchar_t **smb_ExecutableExtensions;
61
62 osi_log_t *afsd_logp;
63
64 cm_config_data_t        cm_data;
65
66 fschar_t cm_rootVolumeName[VL_MAXNAMELEN];
67 DWORD cm_rootVolumeNameLen;
68
69 fschar_t cm_mountRoot[1024];
70 DWORD cm_mountRootLen;
71
72 clientchar_t cm_mountRootC[1024];
73 DWORD cm_mountRootCLen;
74
75 int cm_readonlyVolumeVersioning = 0;
76 int cm_logChunkSize;
77 int cm_chunkSize;
78 int cm_virtualCache = 0;
79 afs_int32 cm_verifyData = 0;
80 int cm_shortNames = 1;
81 int cm_directIO = 1;
82
83 int smb_UseV3 = 1;
84 afs_uint32 smb_Enabled = 1;
85
86 int LANadapter;
87
88 int numBkgD;
89 int numSvThreads;
90 long rx_mtu = -1;
91 int traceOnPanic = 0;
92
93 int logReady = 0;
94
95 char cm_HostName[200];
96 long cm_HostAddr;
97 unsigned short cm_callbackport = CM_DEFAULT_CALLBACKPORT;
98
99 char cm_NetbiosName[MAX_NB_NAME_LENGTH] = "NOT.YET.SET";
100 clientchar_t cm_NetbiosNameC[MAX_NB_NAME_LENGTH] = _C("NOT.YET.SET");
101
102 char cm_CachePath[MAX_PATH];
103 DWORD cm_ValidateCache = 1;
104
105 BOOL reportSessionStartups = FALSE;
106
107 cm_initparams_v1 cm_initParams;
108
109 unsigned int  cm_sysNameCount = 0;
110 clientchar_t *cm_sysNameList[MAXNUMSYSNAMES];
111 unsigned int  cm_sysName64Count = 0;
112 clientchar_t *cm_sysName64List[MAXNUMSYSNAMES];
113
114 DWORD TraceOption = 0;
115
116 /*
117  * AFSD Initialization Log
118  *
119  * This is distinct from the regular debug logging facility.
120  * Log items go directly to a file, not to an array in memory, so that even
121  * if AFSD crashes, the log can be inspected.
122  */
123
124 HANDLE afsi_file;
125
126 int cm_dnsEnabled = 1;
127
128
129 static int afsi_log_useTimestamp = 1;
130
131 void
132 afsi_log(char *pattern, ...)
133 {
134     char s[256], t[100], d[100], u[512];
135     DWORD zilch;
136     va_list ap;
137     va_start(ap, pattern);
138
139     StringCbVPrintfA(s, sizeof(s), pattern, ap);
140     if ( afsi_log_useTimestamp ) {
141         GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, t, sizeof(t));
142         GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, d, sizeof(d));
143         StringCbPrintfA(u, sizeof(u), "%s %s: %s\r\n", d, t, s);
144         if (afsi_file != INVALID_HANDLE_VALUE)
145             WriteFile(afsi_file, u, (DWORD)strlen(u), &zilch, NULL);
146 #ifdef NOTSERVICE
147         printf("%s", u);
148 #endif
149     } else {
150         if (afsi_file != INVALID_HANDLE_VALUE)
151             WriteFile(afsi_file, s, (DWORD)strlen(s), &zilch, NULL);
152     }
153 }
154
155 void
156 afsi_start()
157 {
158     char wd[MAX_PATH+1];
159     char t[100], u[100], *p, *path;
160     int zilch;
161     DWORD code;
162     DWORD dwLow, dwHigh;
163     HKEY parmKey;
164     DWORD dummyLen;
165     DWORD maxLogSize = 100 * 1024;
166
167     afsi_file = INVALID_HANDLE_VALUE;
168     code = GetTempPath(sizeof(wd)-15, wd);
169     if ( code == 0 || code > (sizeof(wd)-15) )
170         return;         /* unable to create a log */
171
172     StringCbCatA(wd, sizeof(wd), "\\afsd_init.log");
173     GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, t, sizeof(t));
174     afsi_file = CreateFile(wd, GENERIC_WRITE, FILE_SHARE_READ, NULL,
175                            OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
176
177     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
178                          0, KEY_QUERY_VALUE, &parmKey);
179     if (code == ERROR_SUCCESS) {
180         dummyLen = sizeof(maxLogSize);
181         code = RegQueryValueEx(parmKey, "MaxLogSize", NULL, NULL,
182                                 (BYTE *) &maxLogSize, &dummyLen);
183         RegCloseKey (parmKey);
184     }
185
186     if (maxLogSize) {
187         dwLow = GetFileSize( afsi_file, &dwHigh );
188         if ( dwHigh > 0 || dwLow >= maxLogSize ) {
189             CloseHandle(afsi_file);
190             afsi_file = CreateFile( wd, GENERIC_WRITE, FILE_SHARE_READ, NULL,
191                                     CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
192         }
193     }
194
195     SetFilePointer(afsi_file, 0, NULL, FILE_END);
196     GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, u, sizeof(u));
197     StringCbCatA(t, sizeof(t), ": Create log file\r\n");
198     StringCbCatA(u, sizeof(u), ": Created log file\r\n");
199     WriteFile(afsi_file, t, (DWORD)strlen(t), &zilch, NULL);
200     WriteFile(afsi_file, u, (DWORD)strlen(u), &zilch, NULL);
201     p = "PATH=";
202     code = GetEnvironmentVariable("PATH", NULL, 0);
203     path = malloc(code);
204     code = GetEnvironmentVariable("PATH", path, code);
205     WriteFile(afsi_file, p, (DWORD)strlen(p), &zilch, NULL);
206     WriteFile(afsi_file, path, (DWORD)strlen(path), &zilch, NULL);
207     WriteFile(afsi_file, "\r\n", (DWORD)1, &zilch, NULL);
208     free(path);
209
210     /* Initialize C RTL Code Page conversion functions */
211     /* All of the path info obtained from the SMB client is in the OEM code page */
212     afsi_log("OEM Code Page = %d", GetOEMCP());
213     afsi_log("locale =  %s", setlocale(LC_ALL,NULL));
214 #ifdef COMMENT
215     /* Two things to look into.  First, should mbstowcs() be performing
216      * character set translations from OEM to Unicode in smb3.c;
217      * Second, do we need to set this translation in each function
218      * due to multi-threading.
219      */
220     afsi_log("locale -> %s", setlocale(LC_ALL, ".OCP"));
221     afsi_log("_setmbcp = %d -> %d", _setmbcp(_MB_CP_OEM), _getmbcp());
222 #endif /* COMMENT */
223 }
224
225 /*
226  * Standard AFSD trace
227  */
228
229 void afsd_ForceTrace(BOOL flush)
230 {
231     HANDLE handle;
232     int len;
233     char buf[256];
234
235     if (!logReady)
236         return;
237
238     len = GetTempPath(sizeof(buf)-10, buf);
239     StringCbCopyA(&buf[len], sizeof(buf)-len, "/afsd.log");
240     handle = CreateFile(buf, GENERIC_WRITE, FILE_SHARE_READ,
241                          NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
242     if (handle == INVALID_HANDLE_VALUE) {
243         logReady = 0;
244         osi_panic("Cannot create log file", __FILE__, __LINE__);
245     }
246     osi_LogPrint(afsd_logp, handle);
247     if (flush)
248         FlushFileBuffers(handle);
249     CloseHandle(handle);
250 }
251
252 static void afsd_InitServerPreferences(void)
253 {
254     HKEY hkPrefs = 0;
255     DWORD dwType, dwSize;
256     DWORD dwPrefs = 0;
257     DWORD dwIndex;
258     TCHAR szHost[256];
259     DWORD dwHostSize = 256;
260     DWORD dwRank;
261     struct sockaddr_in  saddr;
262     cm_server_t       *tsp;
263
264     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
265                       AFSREG_CLT_OPENAFS_SUBKEY "\\Server Preferences\\VLDB",
266                       0,
267                       KEY_READ|KEY_QUERY_VALUE,
268                       &hkPrefs) == ERROR_SUCCESS) {
269
270         RegQueryInfoKey( hkPrefs,
271                          NULL,  /* lpClass */
272                          NULL,  /* lpcClass */
273                          NULL,  /* lpReserved */
274                          NULL,  /* lpcSubKeys */
275                          NULL,  /* lpcMaxSubKeyLen */
276                          NULL,  /* lpcMaxClassLen */
277                          &dwPrefs, /* lpcValues */
278                          NULL,  /* lpcMaxValueNameLen */
279                          NULL,  /* lpcMaxValueLen */
280                          NULL,  /* lpcbSecurityDescriptor */
281                          NULL   /* lpftLastWriteTime */
282                          );
283
284         for ( dwIndex = 0 ; dwIndex < dwPrefs; dwIndex++ ) {
285
286             dwSize = sizeof(DWORD);
287             dwHostSize = 256;
288
289             if (RegEnumValue( hkPrefs, dwIndex, szHost, &dwHostSize, NULL,
290                               &dwType, (LPBYTE)&dwRank, &dwSize))
291             {
292                 afsi_log("RegEnumValue(hkPrefs) failed");
293                 continue;
294             }
295
296             afsi_log("VLDB Server Preference: %s = %d",szHost, dwRank);
297
298             if (isdigit(szHost[0]))
299             {
300                 if ((saddr.sin_addr.S_un.S_addr = inet_addr (szHost)) == INADDR_NONE)
301                     continue;
302             } else {
303                 HOSTENT *pEntry;
304                 if ((pEntry = gethostbyname (szHost)) == NULL)
305                     continue;
306
307                 saddr.sin_addr.S_un.S_addr = *(unsigned long *)pEntry->h_addr;
308             }
309             saddr.sin_port = htons(7003);
310             saddr.sin_family = AF_INET;
311             dwRank += (rand() & 0x000f);
312
313             tsp = cm_FindServer(&saddr, CM_SERVER_VLDB, FALSE);
314             if ( tsp )          /* an existing server - ref count increased */
315             {
316                 lock_ObtainMutex(&tsp->mx);
317                 tsp->adminRank = (USHORT)dwRank;
318                 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PREF_SET);
319                 cm_RankServer(tsp);
320                 lock_ReleaseMutex(&tsp->mx);
321
322                 /* set preferences for an existing vlserver */
323                 cm_ChangeRankCellVLServer(tsp);
324                 cm_PutServer(tsp);  /* decrease refcount */
325             }
326             else        /* add a new server without a cell */
327             {
328                 tsp = cm_NewServer(&saddr, CM_SERVER_VLDB, NULL, NULL, CM_FLAG_NOPROBE); /* refcount = 1 */
329                 lock_ObtainMutex(&tsp->mx);
330                 tsp->adminRank = (USHORT)dwRank;
331                 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PREF_SET);
332                 cm_RankServer(tsp);
333                 lock_ReleaseMutex(&tsp->mx);
334             }
335         }
336
337         RegCloseKey(hkPrefs);
338     }
339
340     if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
341                       AFSREG_CLT_OPENAFS_SUBKEY "\\Server Preferences\\File",
342                       0,
343                       KEY_READ|KEY_QUERY_VALUE,
344                       &hkPrefs) == ERROR_SUCCESS) {
345
346         RegQueryInfoKey( hkPrefs,
347                          NULL,  /* lpClass */
348                          NULL,  /* lpcClass */
349                          NULL,  /* lpReserved */
350                          NULL,  /* lpcSubKeys */
351                          NULL,  /* lpcMaxSubKeyLen */
352                          NULL,  /* lpcMaxClassLen */
353                          &dwPrefs, /* lpcValues */
354                          NULL,  /* lpcMaxValueNameLen */
355                          NULL,  /* lpcMaxValueLen */
356                          NULL,  /* lpcbSecurityDescriptor */
357                          NULL   /* lpftLastWriteTime */
358                          );
359
360         for ( dwIndex = 0 ; dwIndex < dwPrefs; dwIndex++ ) {
361
362             dwSize = sizeof(DWORD);
363             dwHostSize = 256;
364
365             if (RegEnumValue( hkPrefs, dwIndex, szHost, &dwHostSize, NULL,
366                               &dwType, (LPBYTE)&dwRank, &dwSize))
367             {
368                 afsi_log("RegEnumValue(hkPrefs) failed");
369                 continue;
370             }
371
372             afsi_log("File Server Preference: %s = %d",szHost, dwRank);
373
374             if (isdigit(szHost[0]))
375             {
376                 if ((saddr.sin_addr.S_un.S_addr = inet_addr (szHost)) == INADDR_NONE)
377                     continue;
378             } else {
379                 HOSTENT *pEntry;
380                 if ((pEntry = gethostbyname (szHost)) == NULL)
381                     continue;
382
383                 saddr.sin_addr.S_un.S_addr = *(unsigned long *)pEntry->h_addr;
384             }
385             saddr.sin_port = htons(7000);
386             saddr.sin_family = AF_INET;
387             dwRank += (rand() & 0x000f);
388
389             tsp = cm_FindServer(&saddr, CM_SERVER_FILE, FALSE);
390             if ( tsp )          /* an existing server - ref count increased */
391             {
392                 lock_ObtainMutex(&tsp->mx);
393                 tsp->adminRank = (USHORT)dwRank;
394                 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PREF_SET);
395                 cm_RankServer(tsp);
396                 lock_ReleaseMutex(&tsp->mx);
397
398                 /* find volumes which might have RO copy
399                 /* on server and change the ordering of
400                  * their RO list
401                  */
402                 cm_ChangeRankVolume(tsp);
403                 cm_PutServer(tsp);  /* decrease refcount */
404             }
405             else        /* add a new server without a cell */
406             {
407                 tsp = cm_NewServer(&saddr, CM_SERVER_FILE, NULL, NULL, CM_FLAG_NOPROBE); /* refcount = 1 */
408                 lock_ObtainMutex(&tsp->mx);
409                 tsp->adminRank = (USHORT)dwRank;
410                 _InterlockedOr(&tsp->flags, CM_SERVERFLAG_PREF_SET);
411                 cm_RankServer(tsp);
412                 lock_ReleaseMutex(&tsp->mx);
413             }
414         }
415
416         RegCloseKey(hkPrefs);
417     }
418 }
419
420
421 #ifndef _WIN64
422 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
423
424 static BOOL
425 is_wow64(void)
426 {
427     static BOOL bChecked = FALSE;
428     static BOOL bIsWow64 = FALSE;
429
430     if (!bChecked)
431     {
432         HANDLE h1 = NULL;
433         LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
434
435         h1 = GetModuleHandle("kernel32.dll");
436         fnIsWow64Process =
437             (LPFN_ISWOW64PROCESS)GetProcAddress(h1, "IsWow64Process");
438
439         /* If we don't find the fnIsWow64Process function then we
440          * are not running in a broken Wow64
441          */
442         if (fnIsWow64Process)
443             fnIsWow64Process(GetCurrentProcess(), &bIsWow64);
444
445         bChecked = TRUE;
446     }
447
448     return bIsWow64;
449 }
450 #endif /* _WIN64 */
451
452 /*
453  * AFSD Initialization
454  */
455
456 static int
457 afsd_InitRoot(char **reasonP)
458 {
459     long code;
460     cm_req_t req;
461
462     cm_InitReq(&req);
463
464     if (cm_freelanceEnabled) {
465         cm_FakeRootFid(&cm_data.rootFid);
466     } else {
467         int attempts = 10;
468
469         osi_Log0(afsd_logp, "Loading Root Volume from cell");
470         do {
471             code = cm_FindVolumeByName(cm_data.rootCellp, cm_rootVolumeName, cm_rootUserp,
472                                        &req, CM_GETVOL_FLAG_CREATE, &cm_data.rootVolumep);
473             afsi_log("cm_FindVolumeByName code %x root vol %x", code,
474                       (code ? (cm_volume_t *)-1 : cm_data.rootVolumep));
475         } while (code && --attempts);
476         if (code != 0) {
477             *reasonP = "can't find root volume in root cell";
478             return -1;
479         }
480
481         /* compute the root fid */
482         cm_SetFid(&cm_data.rootFid, cm_data.rootCellp->cellID, cm_GetROVolumeID(cm_data.rootVolumep), 1, 1);
483     }
484
485     code = cm_GetSCache(&cm_data.rootFid, NULL, &cm_data.rootSCachep, cm_rootUserp, &req);
486     afsi_log("cm_GetSCache code %x scache %x", code,
487              (code ? (cm_scache_t *)-1 : cm_data.rootSCachep));
488     if (code != 0) {
489         *reasonP = "unknown error";
490         return -1;
491     }
492
493     return 0;
494 }
495
496 int
497 afsd_InitCM(char **reasonP)
498 {
499     osi_uid_t debugID;
500     afs_uint64 cacheBlocks;
501     DWORD cacheSize;
502     DWORD blockSize;
503     long logChunkSize;
504     DWORD stats;
505     DWORD volumes;
506     DWORD cells;
507     DWORD dwValue;
508     DWORD rx_enable_peer_stats;
509     DWORD rx_enable_process_stats;
510     DWORD rx_udpbufsize = -1;
511     DWORD lockOrderValidation;
512     long traceBufSize;
513     long maxcpus;
514     long ltt, ltto;
515     long rx_nojumbo;
516     int  rx_max_rwin_size;
517     int  rx_max_swin_size;
518     int  rx_min_peer_timeout;
519     DWORD virtualCache = 0;
520     fschar_t rootCellName[256];
521     struct rx_service *serverp;
522     static struct rx_securityClass *nullServerSecurityClassp;
523     struct hostent *thp;
524     char *msgBuf;
525     char buf[1024];
526     HKEY parmKey;
527     DWORD dummyLen;
528     DWORD regType;
529     long code;
530     /*int freelanceEnabled;*/
531     WSADATA WSAjunk;
532     int i;
533     int cm_noIPAddr;         /* number of client network interfaces */
534     int cm_IPAddr[CM_MAXINTERFACE_ADDR];    /* client's IP address in host order */
535     int cm_SubnetMask[CM_MAXINTERFACE_ADDR];/* client's subnet mask in host order*/
536     int cm_NetMtu[CM_MAXINTERFACE_ADDR];    /* client's MTU sizes */
537     int cm_NetFlags[CM_MAXINTERFACE_ADDR];  /* network flags */
538     DWORD dwPriority;
539     OSVERSIONINFO osVersion;
540
541     /* Get the version of Windows */
542     memset(&osVersion, 0x00, sizeof(osVersion));
543     osVersion.dwOSVersionInfoSize = sizeof(osVersion);
544     GetVersionEx(&osVersion);
545
546     WSAStartup(0x0101, &WSAjunk);
547
548     init_et_to_sys_error();
549
550     cm_utilsInit();
551
552     /* setup osidebug server at RPC slot 1000 */
553     osi_LongToUID(1000, &debugID);
554     code = osi_InitDebug(&debugID);
555     afsi_log("osi_InitDebug code %d", code);
556
557 #ifndef _WIN64
558     if (is_wow64())
559     {
560         *reasonP = "32-bit OpenAFS Service is incompatible with the WOW64 environment";
561         return -1;
562     }
563 #endif
564
565     //  osi_LockTypeSetDefault("stat"); /* comment this out for speed */
566     if (code != 0) {
567         if (code == RPC_S_NO_PROTSEQS)
568             *reasonP = "No RPC Protocol Sequences registered.  Check HKLM\\SOFTWARE\\Microsoft\\RPC\\ClientProtocols";
569         else
570             *reasonP = "unknown error";
571         return -1;
572     }
573
574     /* who are we ? */
575     gethostname(cm_HostName, sizeof(cm_HostName));
576     afsi_log("gethostname %s", cm_HostName);
577     thp = gethostbyname(cm_HostName);
578     memcpy(&cm_HostAddr, thp->h_addr_list[0], 4);
579
580     /* seed random number generator */
581     srand(ntohl(cm_HostAddr));
582
583     /* Look up configuration parameters in Registry */
584     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
585                         0, KEY_QUERY_VALUE, &parmKey);
586     if (code != ERROR_SUCCESS) {
587         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
588                        | FORMAT_MESSAGE_ALLOCATE_BUFFER,
589                        NULL, code, 0, (LPTSTR)&msgBuf, 0, NULL);
590         StringCbPrintfA(buf, sizeof(buf),
591                          "Failure in configuration while opening Registry: %s",
592                          msgBuf);
593         osi_panic(buf, __FILE__, __LINE__);
594     }
595
596     dummyLen = sizeof(dwPriority);
597     code = RegQueryValueEx(parmKey, "PriorityClass", NULL, NULL,
598                             (BYTE *) &dwPriority, &dummyLen);
599     if (code != ERROR_SUCCESS || dwPriority == 0) {
600         dwPriority = HIGH_PRIORITY_CLASS;
601     }
602     if (dwPriority != GetPriorityClass(GetCurrentProcess()))
603         SetPriorityClass(GetCurrentProcess(), dwPriority);
604     afsi_log("PriorityClass 0x%x", GetPriorityClass(GetCurrentProcess()));
605
606     dummyLen = sizeof(lockOrderValidation);
607     code = RegQueryValueEx(parmKey, "LockOrderValidation", NULL, NULL,
608                             (BYTE *) &lockOrderValidation, &dummyLen);
609     if (code != ERROR_SUCCESS) {
610 #ifdef DEBUG
611         lockOrderValidation = 1;
612 #else
613         lockOrderValidation = 0;
614 #endif
615     }
616     osi_SetLockOrderValidation(lockOrderValidation);
617     afsi_log("Lock Order Validation %s", lockOrderValidation ? "On" : "Off");
618
619     dummyLen = sizeof(maxcpus);
620     code = RegQueryValueEx(parmKey, "MaxCPUs", NULL, NULL,
621                             (BYTE *) &maxcpus, &dummyLen);
622     if (code != ERROR_SUCCESS) {
623         maxcpus = 2;
624     }
625
626     {
627         HANDLE hProcess;
628         DWORD_PTR processAffinityMask, systemAffinityMask;
629
630         hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION,
631                                FALSE, GetCurrentProcessId());
632         if ( hProcess != NULL &&
633              GetProcessAffinityMask(hProcess, &processAffinityMask, &systemAffinityMask) )
634         {
635             int i, n, bits, cpu_count = 0;
636             DWORD_PTR mask, newAffinityMask;
637
638 #if defined(_WIN64)
639             bits = 64;
640 #else
641             bits = 32;
642 #endif
643             for ( i=0, n=0, mask=1, newAffinityMask=0; i<bits; i++ ) {
644                 if ( processAffinityMask & mask ) {
645                     cpu_count++;
646                     if (n<maxcpus) {
647                         newAffinityMask |= mask;
648                         n++;
649                     }
650                 }
651                 mask *= 2;
652             }
653
654             if (maxcpus == 0) {
655                 afsi_log("No CPU Restrictions; %d cpu(s) available", cpu_count);
656             } else {
657                 SetProcessAffinityMask(hProcess, newAffinityMask);
658             }
659             CloseHandle(hProcess);
660             afsi_log("CPU Restrictions set to %d cpu(s); %d cpu(s) available", maxcpus, cpu_count);
661         } else {
662             afsi_log("CPU Restrictions requested %d cpu(s); unable to access process information", maxcpus);
663         }
664     }
665
666     dummyLen = sizeof(TraceOption);
667     code = RegQueryValueEx(parmKey, "TraceOption", NULL, NULL,
668                             (BYTE *) &TraceOption, &dummyLen);
669     afsi_log("Trace Options = %lX", TraceOption);
670
671     dummyLen = sizeof(traceBufSize);
672     code = RegQueryValueEx(parmKey, "TraceBufferSize", NULL, NULL,
673                             (BYTE *) &traceBufSize, &dummyLen);
674     if (code == ERROR_SUCCESS)
675         afsi_log("Trace Buffer size %d", traceBufSize);
676     else {
677         traceBufSize = CM_CONFIGDEFAULT_TRACEBUFSIZE;
678         afsi_log("Default trace buffer size %d", traceBufSize);
679     }
680
681     /* setup and enable debug log */
682     afsd_logp = osi_LogCreate("afsd", traceBufSize);
683     afsi_log("osi_LogCreate log addr %x", PtrToUlong(afsd_logp));
684     if ((TraceOption & 0x8)
685 #ifdef DEBUG
686          || 1
687 #endif
688          ) {
689         osi_LogEnable(afsd_logp);
690     }
691     logReady = 1;
692
693     osi_Log0(afsd_logp, "Log init");
694
695     dummyLen = sizeof(smb_monitorReqs);
696     code = RegQueryValueEx(parmKey, "SMBRequestMonitor", NULL, NULL,
697                            (BYTE *) &smb_monitorReqs, &dummyLen);
698     afsi_log("SMB request monitoring is %s", (smb_monitorReqs != 0)? "enabled": "disabled");
699
700     dummyLen = sizeof(virtualCache);
701     code = RegQueryValueEx(parmKey, "NonPersistentCaching", NULL, NULL,
702                             (LPBYTE)&virtualCache, &dummyLen);
703     if (!code)
704         cm_virtualCache = virtualCache ? 1 : 0;
705     afsi_log("Cache type is %s", (cm_virtualCache?"VIRTUAL":"FILE"));
706
707     if (!cm_virtualCache) {
708         dummyLen = sizeof(cm_ValidateCache);
709         code = RegQueryValueEx(parmKey, "ValidateCache", NULL, NULL,
710                                (LPBYTE)&cm_ValidateCache, &dummyLen);
711         if ( cm_ValidateCache < 0 || cm_ValidateCache > 2 )
712             cm_ValidateCache = 1;
713         switch (cm_ValidateCache) {
714         case 0:
715             afsi_log("Cache Validation disabled");
716             break;
717         case 1:
718             afsi_log("Cache Validation on Startup");
719             break;
720         case 2:
721             afsi_log("Cache Validation on Startup and Shutdown");
722             break;
723         }
724     }
725
726     dummyLen = sizeof(cacheSize);
727     code = RegQueryValueEx(parmKey, "CacheSize", NULL, NULL,
728                             (BYTE *) &cacheSize, &dummyLen);
729     if (code != ERROR_SUCCESS)
730         cacheSize = CM_CONFIGDEFAULT_CACHESIZE;
731
732     if (cm_virtualCache) {
733         MEMORYSTATUSEX memStatus;
734         DWORD maxCacheSize;
735
736         memStatus.dwLength = sizeof(memStatus);
737         if (GlobalMemoryStatusEx(&memStatus)) {
738             /* Set maxCacheSize to 10% of physical memory */
739             maxCacheSize = (DWORD)(memStatus.ullTotalPhys / 1024 / 10);
740         } else {
741             /* Cannot determine physical memory, set limit to 64MB */
742             maxCacheSize = 65536;
743         }
744         if (cacheSize > maxCacheSize) {
745             afsi_log("Requested Cache size %u", cacheSize);
746             cacheSize = maxCacheSize;
747         }
748     }
749     afsi_log("Allocated Cache size %u", cacheSize);
750
751     dummyLen = sizeof(logChunkSize);
752     code = RegQueryValueEx(parmKey, "ChunkSize", NULL, NULL,
753                             (BYTE *) &logChunkSize, &dummyLen);
754     if (code == ERROR_SUCCESS) {
755         if (logChunkSize < 12 || logChunkSize > 30) {
756             afsi_log("Invalid chunk size %d, using default",
757                       logChunkSize);
758             logChunkSize = CM_CONFIGDEFAULT_CHUNKSIZE;
759         }
760     } else {
761         logChunkSize = CM_CONFIGDEFAULT_CHUNKSIZE;
762     }
763     cm_logChunkSize = logChunkSize;
764     cm_chunkSize = 1 << logChunkSize;
765     afsi_log("Chunk size %u (%d)", cm_chunkSize, cm_logChunkSize);
766
767     dummyLen = sizeof(blockSize);
768     code = RegQueryValueEx(parmKey, "blockSize", NULL, NULL,
769                             (BYTE *) &blockSize, &dummyLen);
770     if (code == ERROR_SUCCESS) {
771         if (blockSize < 1 ||
772             (blockSize > 1024 && (blockSize % CM_CONFIGDEFAULT_BLOCKSIZE != 0)))
773         {
774             afsi_log("Invalid block size %u specified, using default", blockSize);
775             blockSize = CM_CONFIGDEFAULT_BLOCKSIZE;
776         } else {
777             /*
778              * if the blockSize is less than 1024 we permit the blockSize to be
779              * specified in multiples of the default blocksize
780              */
781             if (blockSize <= 1024)
782                 blockSize *= CM_CONFIGDEFAULT_BLOCKSIZE;
783         }
784     } else {
785         blockSize = CM_CONFIGDEFAULT_BLOCKSIZE;
786     }
787     if (blockSize > cm_chunkSize) {
788         afsi_log("Block size (%d) cannot be larger than Chunk size (%d).",
789                   blockSize, cm_chunkSize);
790         blockSize = cm_chunkSize;
791     }
792     if (cm_chunkSize % blockSize != 0) {
793         afsi_log("Block size (%d) must be a factor of Chunk size (%d).",
794                   blockSize, cm_chunkSize);
795         blockSize = CM_CONFIGDEFAULT_BLOCKSIZE;
796     }
797     afsi_log("Block size %u", blockSize);
798
799     dummyLen = sizeof(numBkgD);
800     code = RegQueryValueEx(parmKey, "Daemons", NULL, NULL,
801                             (BYTE *) &numBkgD, &dummyLen);
802     if (code == ERROR_SUCCESS) {
803         if (numBkgD > CM_MAX_DAEMONS)
804             numBkgD = CM_MAX_DAEMONS;
805         afsi_log("%d background daemons", numBkgD);
806     } else {
807         numBkgD = CM_CONFIGDEFAULT_DAEMONS;
808         afsi_log("Defaulting to %d background daemons", numBkgD);
809     }
810
811     dummyLen = sizeof(numSvThreads);
812     code = RegQueryValueEx(parmKey, "ServerThreads", NULL, NULL,
813                             (BYTE *) &numSvThreads, &dummyLen);
814     if (code == ERROR_SUCCESS)
815         afsi_log("%d server threads", numSvThreads);
816     else {
817         numSvThreads = CM_CONFIGDEFAULT_SVTHREADS;
818         afsi_log("Defaulting to %d server threads", numSvThreads);
819     }
820
821     dummyLen = sizeof(stats);
822     code = RegQueryValueEx(parmKey, "Stats", NULL, NULL,
823                             (BYTE *) &stats, &dummyLen);
824     if (code == ERROR_SUCCESS)
825         afsi_log("Status cache entries: %d", stats);
826     else {
827         stats = CM_CONFIGDEFAULT_STATS;
828         afsi_log("Default status cache entries: %d", stats);
829     }
830
831     dummyLen = sizeof(volumes);
832     code = RegQueryValueEx(parmKey, "Volumes", NULL, NULL,
833                             (BYTE *) &volumes, &dummyLen);
834     if (code == ERROR_SUCCESS)
835         afsi_log("Volumes cache entries: %d", volumes);
836     else {
837         volumes = CM_CONFIGDEFAULT_STATS / 3;
838         afsi_log("Default volume cache entries: %d", volumes);
839     }
840
841     dummyLen = sizeof(cells);
842     code = RegQueryValueEx(parmKey, "Cells", NULL, NULL,
843                             (BYTE *) &cells, &dummyLen);
844     if (code == ERROR_SUCCESS)
845         afsi_log("Cell cache entries: %d", cells);
846     else {
847         cells = CM_CONFIGDEFAULT_CELLS;
848         afsi_log("Default cell cache entries: %d", cells);
849     }
850
851     dummyLen = sizeof(ltt);
852     code = RegQueryValueEx(parmKey, "LogoffTokenTransfer", NULL, NULL,
853                             (BYTE *) &ltt, &dummyLen);
854     if (code != ERROR_SUCCESS)
855         ltt = 1;
856     smb_LogoffTokenTransfer = ltt;
857     afsi_log("Logoff token transfer %s",  (ltt ? "on" : "off"));
858
859     if (ltt) {
860         dummyLen = sizeof(ltto);
861         code = RegQueryValueEx(parmKey, "LogoffTokenTransferTimeout",
862                                 NULL, NULL, (BYTE *) &ltto, &dummyLen);
863         if (code != ERROR_SUCCESS)
864             ltto = 120;
865     } else {
866         ltto = 0;
867     }
868     smb_LogoffTransferTimeout = ltto;
869     afsi_log("Logoff token transfer timeout %d seconds", ltto);
870
871     dummyLen = sizeof(cm_NetbiosName);
872     code = RegQueryValueEx(parmKey, "NetbiosName", NULL, NULL,
873                             (LPBYTE) cm_NetbiosName, &dummyLen);
874     if (code == ERROR_SUCCESS)
875         afsi_log("NetbiosName %s", cm_NetbiosName);
876     else {
877         cm_FsStrCpy(cm_NetbiosName, lengthof(cm_NetbiosName), "AFS");
878         afsi_log("Default NetbiosName AFS");
879     }
880     cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
881
882     dummyLen = sizeof(cm_rootVolumeName);
883     code = RegQueryValueEx(parmKey, "RootVolume", NULL, NULL,
884                             (LPBYTE) cm_rootVolumeName, &dummyLen);
885     if (code == ERROR_SUCCESS)
886         afsi_log("Root volume %s", cm_rootVolumeName);
887     else {
888         cm_FsStrCpy(cm_rootVolumeName, lengthof(cm_rootVolumeName), "root.afs");
889         afsi_log("Default root volume name root.afs");
890     }
891
892     cm_mountRootCLen = sizeof(cm_mountRootC);
893     code = RegQueryValueExW(parmKey, L"MountRoot", NULL, NULL,
894                             (LPBYTE) cm_mountRootC, &cm_mountRootCLen);
895     if (code == ERROR_SUCCESS) {
896         afsi_log("Mount root %S", cm_mountRootC);
897         cm_mountRootCLen = (DWORD)cm_ClientStrLen(cm_mountRootC);
898     } else {
899         cm_ClientStrCpy(cm_mountRootC, lengthof(cm_mountRootC), _C("/afs"));
900         cm_mountRootCLen = (DWORD)cm_ClientStrLen(cm_mountRootC);
901         /* Don't log */
902     }
903
904     cm_ClientStringToFsString(cm_mountRootC, -1, cm_mountRoot, lengthof(cm_mountRoot));
905     cm_mountRootLen = (DWORD)cm_FsStrLen(cm_mountRoot);
906
907     dummyLen = sizeof(buf);
908     code = RegQueryValueEx(parmKey, "CachePath", NULL, &regType,
909                            buf, &dummyLen);
910     if (code == ERROR_SUCCESS && buf[0]) {
911         if (regType == REG_EXPAND_SZ) {
912             dummyLen = ExpandEnvironmentStrings(buf, cm_CachePath, sizeof(cm_CachePath));
913             if (dummyLen > sizeof(cm_CachePath)) {
914                 afsi_log("Cache path [%s] longer than %d after expanding env strings", buf, sizeof(cm_CachePath));
915                 osi_panic("CachePath too long", __FILE__, __LINE__);
916             }
917         } else {
918             StringCbCopyA(cm_CachePath, sizeof(cm_CachePath), buf);
919         }
920         afsi_log("Cache path %s", cm_CachePath);
921     } else {
922         dummyLen = ExpandEnvironmentStrings("%TEMP%\\AFSCache", cm_CachePath, sizeof(cm_CachePath));
923         if (dummyLen > sizeof(cm_CachePath)) {
924             afsi_log("Cache path [%%TEMP%%\\AFSCache] longer than %d after expanding env strings",
925                      sizeof(cm_CachePath));
926             osi_panic("CachePath too long", __FILE__, __LINE__);
927         }
928         afsi_log("Default cache path %s", cm_CachePath);
929     }
930
931     dummyLen = sizeof(traceOnPanic);
932     code = RegQueryValueEx(parmKey, "TrapOnPanic", NULL, NULL,
933                             (BYTE *) &traceOnPanic, &dummyLen);
934     if (code != ERROR_SUCCESS)
935         traceOnPanic = 1;              /* log */
936     afsi_log("Set to %s on panic", traceOnPanic ? "trap" : "not trap");
937
938     dummyLen = sizeof(reportSessionStartups);
939     code = RegQueryValueEx(parmKey, "ReportSessionStartups", NULL, NULL,
940                             (BYTE *) &reportSessionStartups, &dummyLen);
941     if (code == ERROR_SUCCESS)
942         afsi_log("Session startups %s be recorded in the Event Log",
943                   reportSessionStartups ? "will" : "will not");
944     else {
945         reportSessionStartups = 0;
946         /* Don't log */
947     }
948
949     for ( i=0; i < MAXNUMSYSNAMES; i++ ) {
950         cm_sysNameList[i] = osi_Alloc(MAXSYSNAME * sizeof(clientchar_t));
951         cm_sysNameList[i][0] = '\0';
952         cm_sysName64List[i] = osi_Alloc(MAXSYSNAME * sizeof(clientchar_t));
953         cm_sysName64List[i][0] = '\0';
954     }
955
956     /* Process SysName lists from the registry */
957     {
958         clientchar_t *p, *q;
959         clientchar_t * cbuf = (clientchar_t *) buf;
960
961         dummyLen = sizeof(buf);
962         code = RegQueryValueExW(parmKey, L"SysName", NULL, NULL, (LPBYTE) cbuf, &dummyLen);
963         if (code != ERROR_SUCCESS || !cbuf[0]) {
964 #if defined(_IA64_)
965             cm_ClientStrCpy(cbuf, lengthof(buf), _C("ia64_win64"));
966 #elif defined(_AMD64_)
967             cm_ClientStrCpy(cbuf, lengthof(buf), _C("amd64_win64 x86_win32 i386_w2k"));
968 #else /* assume x86 32-bit */
969             cm_ClientStrCpy(cbuf, lengthof(buf), _C("x86_win32 i386_w2k i386_nt40"));
970 #endif
971         }
972         afsi_log("Sys name list: %S", cbuf);
973
974         /* breakup buf into individual search string entries */
975         for (p = q = cbuf; p < cbuf + dummyLen; p++) {
976             if (*p == '\0' || iswspace(*p)) {
977                 memcpy(cm_sysNameList[cm_sysNameCount],q,(p-q) * sizeof(clientchar_t));
978                 cm_sysNameList[cm_sysNameCount][p-q] = '\0';
979                 cm_sysNameCount++;
980                 do {
981                     if (*p == '\0')
982                         goto done_sysname32;
983                     p++;
984                 } while (*p == '\0' || isspace(*p));
985                 q = p;
986                 p--;
987             }
988         }
989       done_sysname32:
990         ;
991
992 #ifdef _WIN64
993         /*
994          * If there is a 64-bit list, process it.  Otherwise, we will leave
995          * it undefined which implies that the 32-bit list be used for both.
996          * The 64-bit list is only used for the native file system driver.
997          * The SMB redirector interface does not provide any means of indicating
998          * the source of the request.
999          */
1000         dummyLen = sizeof(buf);
1001         code = RegQueryValueExW(parmKey, L"SysName64", NULL, NULL, (LPBYTE) cbuf, &dummyLen);
1002         if (code == ERROR_SUCCESS && cbuf[0]) {
1003             afsi_log("Sys name 64 list: %S", cbuf);
1004
1005             /* breakup buf into individual search string entries */
1006             for (p = q = cbuf; p < cbuf + dummyLen; p++) {
1007                 if (*p == '\0' || iswspace(*p)) {
1008                     memcpy(cm_sysName64List[cm_sysName64Count],q,(p-q) * sizeof(clientchar_t));
1009                     cm_sysName64List[cm_sysName64Count][p-q] = '\0';
1010                     cm_sysName64Count++;
1011                     do {
1012                         if (*p == '\0')
1013                             goto done_sysname64;
1014                         p++;
1015                     } while (*p == '\0' || isspace(*p));
1016                     q = p;
1017                     p--;
1018                 }
1019             }
1020         }
1021       done_sysname64:
1022         ;
1023 #endif
1024     }
1025
1026     dummyLen = sizeof(cryptall);
1027     code = RegQueryValueEx(parmKey, "SecurityLevel", NULL, NULL,
1028                            (BYTE *) &cryptall, &dummyLen);
1029     if (code == ERROR_SUCCESS) {
1030         afsi_log("SecurityLevel is %s", cryptall == 1?"crypt": cryptall == 2?"auth":"clear");
1031     } else {
1032         cryptall = 0;
1033         afsi_log("Default SecurityLevel is clear");
1034     }
1035
1036     if (cryptall == 1)
1037         LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_ON);
1038     else if (cryptall == 2)
1039         LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_AUTH);
1040     else
1041         LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_CRYPT_OFF);
1042
1043     dummyLen = sizeof(cm_verifyData);
1044     code = RegQueryValueEx(parmKey, "VerifyData", NULL, NULL,
1045                            (BYTE *) &cm_verifyData, &dummyLen);
1046     afsi_log("VerifyData is %s", cm_verifyData?"on":"off");
1047
1048     dummyLen = sizeof(cm_anonvldb);
1049     code = RegQueryValueEx(parmKey, "ForceAnonVLDB", NULL, NULL,
1050                             (BYTE *) &cm_anonvldb, &dummyLen);
1051     afsi_log("CM ForceAnonVLDB is %s", cm_anonvldb ? "on" : "off");
1052
1053     dummyLen = sizeof(cm_dnsEnabled);
1054     code = RegQueryValueEx(parmKey, "UseDNS", NULL, NULL,
1055                             (BYTE *) &cm_dnsEnabled, &dummyLen);
1056     if (code == ERROR_SUCCESS) {
1057         afsi_log("DNS %s be used to find AFS cell servers",
1058                   cm_dnsEnabled ? "will" : "will not");
1059     }
1060     else {
1061         cm_dnsEnabled = 1;   /* default on */
1062         afsi_log("Default to use DNS to find AFS cell servers");
1063     }
1064
1065 #ifdef AFS_FREELANCE_CLIENT
1066     dummyLen = sizeof(cm_freelanceEnabled);
1067     code = RegQueryValueEx(parmKey, "FreelanceClient", NULL, NULL,
1068                             (BYTE *) &cm_freelanceEnabled, &dummyLen);
1069     afsi_log("Freelance client feature %s activated",
1070               cm_freelanceEnabled ? "is" : "is not");
1071
1072     dummyLen = sizeof(cm_freelanceImportCellServDB);
1073     code = RegQueryValueEx(parmKey, "FreelanceImportCellServDB", NULL, NULL,
1074                             (BYTE *) &cm_freelanceImportCellServDB, &dummyLen);
1075     afsi_log("Freelance client %s import CellServDB",
1076               cm_freelanceImportCellServDB ? "does" : "does not");
1077
1078     dummyLen = sizeof(cm_freelanceDiscovery);
1079     code = RegQueryValueEx(parmKey, "FreelanceDiscovery", NULL, NULL,
1080                             (BYTE *) &cm_freelanceDiscovery, &dummyLen);
1081     afsi_log("Freelance client discovery is %s",
1082               cm_freelanceDiscovery ? "on" : "off");
1083
1084 #endif /* AFS_FREELANCE_CLIENT */
1085
1086     dummyLen = sizeof(smb_UseUnicode);
1087     code = RegQueryValueEx(parmKey, "NegotiateUnicode", NULL, NULL,
1088                            (BYTE *) &smb_UseUnicode, &dummyLen);
1089     if (code != ERROR_SUCCESS) {
1090         smb_UseUnicode = 1; /* default on */
1091     }
1092     afsi_log("SMB Server Unicode Support is %s",
1093               smb_UseUnicode ? "enabled" : "disabled");
1094
1095     dummyLen = sizeof(smb_hideDotFiles);
1096     code = RegQueryValueEx(parmKey, "HideDotFiles", NULL, NULL,
1097                            (BYTE *) &smb_hideDotFiles, &dummyLen);
1098     if (code != ERROR_SUCCESS) {
1099         smb_hideDotFiles = 1; /* default on */
1100     }
1101     afsi_log("Dot files/dirs will %sbe marked hidden",
1102               smb_hideDotFiles ? "" : "not ");
1103
1104     dummyLen = sizeof(dwValue);
1105     code = RegQueryValueEx(parmKey, "UnixModeFileDefault", NULL, NULL,
1106                            (BYTE *) &dwValue, &dummyLen);
1107     if (code == ERROR_SUCCESS) {
1108         smb_unixModeDefaultFile = (dwValue & 07777);
1109     }
1110     afsi_log("Default unix mode bits for files is 0%04o", smb_unixModeDefaultFile);
1111
1112     dummyLen = sizeof(dwValue);
1113     code = RegQueryValueEx(parmKey, "UnixModeDirDefault", NULL, NULL,
1114                            (BYTE *) &dwValue, &dummyLen);
1115     if (code == ERROR_SUCCESS) {
1116         smb_unixModeDefaultDir = (dwValue & 07777);
1117     }
1118     afsi_log("Default unix mode bits for directories is 0%04o", smb_unixModeDefaultDir);
1119
1120     dummyLen = sizeof(smb_maxMpxRequests);
1121     code = RegQueryValueEx(parmKey, "MaxMpxRequests", NULL, NULL,
1122                            (BYTE *) &smb_maxMpxRequests, &dummyLen);
1123     if (code != ERROR_SUCCESS) {
1124         smb_maxMpxRequests = 50;
1125     }
1126     afsi_log("Maximum number of multiplexed sessions is %d", smb_maxMpxRequests);
1127
1128     dummyLen = sizeof(smb_maxVCPerServer);
1129     code = RegQueryValueEx(parmKey, "MaxVCPerServer", NULL, NULL,
1130                            (BYTE *) &smb_maxVCPerServer, &dummyLen);
1131     if (code != ERROR_SUCCESS) {
1132         smb_maxVCPerServer = 100;
1133     }
1134     afsi_log("Maximum number of VCs per server is %d", smb_maxVCPerServer);
1135
1136     dummyLen = sizeof(smb_authType);
1137     code = RegQueryValueEx(parmKey, "SMBAuthType", NULL, NULL,
1138                             (BYTE *) &smb_authType, &dummyLen);
1139
1140     if (code != ERROR_SUCCESS ||
1141          (smb_authType != SMB_AUTH_EXTENDED && smb_authType != SMB_AUTH_NTLM && smb_authType != SMB_AUTH_NONE)) {
1142         smb_authType = SMB_AUTH_EXTENDED; /* default is to use extended authentication */
1143     }
1144     afsi_log("SMB authentication type is %s", ((smb_authType == SMB_AUTH_NONE)?"NONE":((smb_authType == SMB_AUTH_EXTENDED)?"EXTENDED":"NTLM")));
1145
1146     dummyLen = sizeof(rx_max_rwin_size);
1147     code = RegQueryValueEx(parmKey, "RxMaxRecvWinSize", NULL, NULL,
1148                            (BYTE *) &rx_max_rwin_size, &dummyLen);
1149     if (code == ERROR_SUCCESS)
1150         rx_SetMaxReceiveWindow(rx_max_rwin_size);
1151     afsi_log("Rx Maximum Receive Window Size is %d", rx_GetMaxReceiveWindow());
1152
1153     dummyLen = sizeof(rx_max_swin_size);
1154     code = RegQueryValueEx(parmKey, "RxMaxSendWinSize", NULL, NULL,
1155                            (BYTE *) &rx_max_swin_size, &dummyLen);
1156     if (code == ERROR_SUCCESS)
1157         rx_SetMaxSendWindow(rx_max_swin_size);
1158     afsi_log("Rx Maximum Send Window Size is %d", rx_GetMaxSendWindow());
1159
1160     dummyLen = sizeof(rx_min_peer_timeout);
1161     code = RegQueryValueEx(parmKey, "RxMinPeerTimeout", NULL, NULL,
1162                            (BYTE *) &rx_min_peer_timeout, &dummyLen);
1163     if (code == ERROR_SUCCESS)
1164         rx_SetMinPeerTimeout(rx_min_peer_timeout);
1165     afsi_log("Rx Minimum Peer Timeout is %d ms", rx_GetMinPeerTimeout());
1166
1167     dummyLen = sizeof(rx_pmtu_discovery);
1168     code = RegQueryValueEx(parmKey, "RxPMTUDiscovery", NULL, NULL,
1169                            (BYTE *) &rx_pmtu_discovery, &dummyLen);
1170     afsi_log("Rx PMTU Discovery is %d ms", rx_pmtu_discovery);
1171
1172     dummyLen = sizeof(rx_nojumbo);
1173     code = RegQueryValueEx(parmKey, "RxNoJumbo", NULL, NULL,
1174                            (BYTE *) &rx_nojumbo, &dummyLen);
1175     if (code != ERROR_SUCCESS) {
1176         DWORD jumbo;
1177         dummyLen = sizeof(jumbo);
1178         code = RegQueryValueEx(parmKey, "RxJumbo", NULL, NULL,
1179                                 (BYTE *) &jumbo, &dummyLen);
1180         if (code != ERROR_SUCCESS) {
1181             rx_nojumbo = 1;
1182         } else {
1183             rx_nojumbo = !jumbo;
1184         }
1185     }
1186     if (rx_nojumbo)
1187         afsi_log("RX Jumbograms are disabled");
1188     else
1189         afsi_log("RX Jumbograms are enabled");
1190
1191     dummyLen = sizeof(rx_extraPackets);
1192     code = RegQueryValueEx(parmKey, "RxExtraPackets", NULL, NULL,
1193                            (BYTE *) &rx_extraPackets, &dummyLen);
1194     if (code != ERROR_SUCCESS) {
1195         rx_extraPackets = (numBkgD + numSvThreads + 5) * 64;
1196     }
1197     if (rx_extraPackets)
1198         afsi_log("RX extraPackets is %d", rx_extraPackets);
1199
1200     dummyLen = sizeof(rx_udpbufsize);
1201     code = RegQueryValueEx(parmKey, "RxUdpBufSize", NULL, NULL,
1202                            (BYTE *) &rx_udpbufsize, &dummyLen);
1203     if (code != ERROR_SUCCESS) {
1204         rx_udpbufsize = 256*1024;
1205     }
1206     if (rx_udpbufsize != -1)
1207         afsi_log("RX udpbufsize is %d", rx_udpbufsize);
1208
1209     dummyLen = sizeof(rx_mtu);
1210     code = RegQueryValueEx(parmKey, "RxMaxMTU", NULL, NULL,
1211                            (BYTE *) &rx_mtu, &dummyLen);
1212     if (code != ERROR_SUCCESS || !rx_mtu) {
1213         rx_mtu = -1;
1214     }
1215     if (rx_mtu != -1)
1216         afsi_log("RX maximum MTU is %d", rx_mtu);
1217
1218     dummyLen = sizeof(rx_enable_peer_stats);
1219     code = RegQueryValueEx(parmKey, "RxEnablePeerStats", NULL, NULL,
1220                            (BYTE *) &rx_enable_peer_stats, &dummyLen);
1221     if (code != ERROR_SUCCESS) {
1222         rx_enable_peer_stats = 1;
1223     }
1224     if (rx_enable_peer_stats)
1225         afsi_log("RX Peer Statistics gathering is enabled");
1226     else
1227         afsi_log("RX Peer Statistics gathering is disabled");
1228
1229     dummyLen = sizeof(rx_enable_process_stats);
1230     code = RegQueryValueEx(parmKey, "RxEnableProcessStats", NULL, NULL,
1231                            (BYTE *) &rx_enable_process_stats, &dummyLen);
1232     if (code != ERROR_SUCCESS) {
1233         rx_enable_process_stats = 1;
1234     }
1235     if (rx_enable_process_stats)
1236         afsi_log("RX Process Statistics gathering is enabled");
1237     else
1238         afsi_log("RX Process Statistics gathering is disabled");
1239
1240     dummyLen = sizeof(dwValue);
1241     dwValue = 0;
1242     code = RegQueryValueEx(parmKey, "RxEnableHotThread", NULL, NULL,
1243                             (BYTE *) &dwValue, &dummyLen);
1244      if (code != ERROR_SUCCESS || dwValue != 0) {
1245          rx_EnableHotThread();
1246          afsi_log("RX Hot Thread is enabled");
1247      }
1248      else
1249          afsi_log("RX Hot Thread is disabled");
1250
1251     dummyLen = sizeof(DWORD);
1252     code = RegQueryValueEx(parmKey, "CallBackPort", NULL, NULL,
1253                            (BYTE *) &dwValue, &dummyLen);
1254     if (code == ERROR_SUCCESS) {
1255         cm_callbackport = (unsigned short) dwValue;
1256     }
1257     afsi_log("CM CallBackPort is %u", cm_callbackport);
1258
1259     dummyLen = sizeof(DWORD);
1260     code = RegQueryValueEx(parmKey, "EnableServerLocks", NULL, NULL,
1261                            (BYTE *) &dwValue, &dummyLen);
1262     if (code == ERROR_SUCCESS) {
1263         cm_enableServerLocks = (unsigned short) dwValue;
1264     }
1265     switch (cm_enableServerLocks) {
1266     case 0:
1267         afsi_log("EnableServerLocks: never");
1268         break;
1269     case 2:
1270         afsi_log("EnableServerLocks: always");
1271         break;
1272     case 1:
1273     default:
1274         afsi_log("EnableServerLocks: server requested");
1275         break;
1276     }
1277
1278     dummyLen = sizeof(DWORD);
1279     code = RegQueryValueEx(parmKey, "DeleteReadOnly", NULL, NULL,
1280                            (BYTE *) &dwValue, &dummyLen);
1281     if (code == ERROR_SUCCESS) {
1282         cm_deleteReadOnly = (unsigned short) dwValue;
1283     }
1284     afsi_log("CM DeleteReadOnly is %u", cm_deleteReadOnly);
1285
1286 #ifdef USE_BPLUS
1287     dummyLen = sizeof(DWORD);
1288     code = RegQueryValueEx(parmKey, "BPlusTrees", NULL, NULL,
1289                            (BYTE *) &dwValue, &dummyLen);
1290     if (code == ERROR_SUCCESS) {
1291         cm_BPlusTrees = (unsigned short) dwValue;
1292     }
1293     afsi_log("CM BPlusTrees is %u", cm_BPlusTrees);
1294
1295     if (cm_BPlusTrees && !cm_InitBPlusDir()) {
1296         cm_BPlusTrees = 0;
1297         afsi_log("CM BPlusTree initialization failure; disabled for this session");
1298     }
1299 #else
1300     afsi_log("CM BPlusTrees is not supported");
1301 #endif
1302
1303     if ((RegQueryValueExW( parmKey, L"PrefetchExecutableExtensions", 0,
1304                            &regType, NULL, &dummyLen) == ERROR_SUCCESS) &&
1305          (regType == REG_MULTI_SZ))
1306     {
1307         clientchar_t * pSz;
1308         dummyLen += 3; /* in case the source string is not nul terminated */
1309         pSz = malloc(dummyLen);
1310         if ((RegQueryValueExW( parmKey, L"PrefetchExecutableExtensions", 0, &regType,
1311                                (LPBYTE) pSz, &dummyLen) == ERROR_SUCCESS) &&
1312              (regType == REG_MULTI_SZ))
1313         {
1314             int cnt;
1315             clientchar_t * p;
1316
1317             for (cnt = 0, p = pSz; (p - pSz < dummyLen) && *p; cnt++, p += cm_ClientStrLen(p) + 1);
1318
1319             smb_ExecutableExtensions = malloc(sizeof(clientchar_t *) * (cnt+1));
1320
1321             for (cnt = 0, p = pSz; (p - pSz < dummyLen) && *p; cnt++, p += cm_ClientStrLen(p) + 1) {
1322                 smb_ExecutableExtensions[cnt] = p;
1323                 afsi_log("PrefetchExecutableExtension: \"%S\"", p);
1324             }
1325             smb_ExecutableExtensions[cnt] = NULL;
1326         }
1327
1328         if (!smb_ExecutableExtensions)
1329             free(pSz);
1330     }
1331     if (!smb_ExecutableExtensions)
1332         afsi_log("No PrefetchExecutableExtensions");
1333
1334     dummyLen = sizeof(DWORD);
1335     code = RegQueryValueEx(parmKey, "OfflineReadOnlyIsValid", NULL, NULL,
1336                            (BYTE *) &dwValue, &dummyLen);
1337     if (code == ERROR_SUCCESS) {
1338         cm_OfflineROIsValid = (unsigned short) dwValue;
1339     }
1340     afsi_log("CM OfflineReadOnlyIsValid is %u", cm_OfflineROIsValid);
1341
1342     dummyLen = sizeof(DWORD);
1343     code = RegQueryValueEx(parmKey, "GiveUpAllCallBacks", NULL, NULL,
1344                            (BYTE *) &dwValue, &dummyLen);
1345     if (code == ERROR_SUCCESS) {
1346         cm_giveUpAllCBs = (unsigned short) dwValue;
1347     }
1348     afsi_log("CM GiveUpAllCallBacks is %u", cm_giveUpAllCBs);
1349
1350     dummyLen = sizeof(DWORD);
1351     code = RegQueryValueEx(parmKey, "FollowBackupPath", NULL, NULL,
1352                            (BYTE *) &dwValue, &dummyLen);
1353     if (code == ERROR_SUCCESS) {
1354         cm_followBackupPath = (unsigned short) dwValue;
1355     }
1356     afsi_log("CM FollowBackupPath is %u", cm_followBackupPath);
1357
1358     dummyLen = sizeof(DWORD);
1359     code = RegQueryValueEx(parmKey, "PerFileAccessCheck", NULL, NULL,
1360                            (BYTE *) &dwValue, &dummyLen);
1361     if (code == ERROR_SUCCESS) {
1362         cm_accessPerFileCheck = (int) dwValue;
1363     }
1364     afsi_log("CM PerFileAccessCheck is %d", cm_accessPerFileCheck);
1365
1366     dummyLen = sizeof(DWORD);
1367     code = RegQueryValueEx(parmKey, "ReadOnlyVolumeVersioning", NULL, NULL,
1368                            (BYTE *) &dwValue, &dummyLen);
1369     if (code == ERROR_SUCCESS) {
1370         cm_readonlyVolumeVersioning = (unsigned short) dwValue;
1371     }
1372     afsi_log("CM ReadOnlyVolumeVersioning is %u", cm_readonlyVolumeVersioning);
1373
1374     dummyLen = sizeof(DWORD);
1375     code = RegQueryValueEx(parmKey, "ShortNames", NULL, NULL,
1376                            (BYTE *) &dwValue, &dummyLen);
1377     if (code == ERROR_SUCCESS) {
1378         cm_shortNames = (unsigned short) dwValue;
1379     } else {
1380         /* disable by default on Win7, Win 8, Server 2008 R2 and Server 2012 */
1381         if (osVersion.dwMajorVersion > 6 ||
1382             osVersion.dwMajorVersion == 6 &&
1383             osVersion.dwMinorVersion >= 1)
1384             cm_shortNames = 0;
1385         else
1386             cm_shortNames = 1;
1387     }
1388     afsi_log("CM ShortNames is %u", cm_shortNames);
1389
1390     dummyLen = sizeof(DWORD);
1391     code = RegQueryValueEx(parmKey, "DirectIO", NULL, NULL,
1392                            (BYTE *) &dwValue, &dummyLen);
1393     if (code == ERROR_SUCCESS) {
1394         cm_directIO = (unsigned short) dwValue;
1395     } else {
1396         cm_directIO = 1;
1397     }
1398     afsi_log("CM DirectIO is %u", cm_directIO);
1399
1400     RegCloseKey (parmKey);
1401
1402     cacheBlocks = ((afs_uint64)cacheSize * 1024) / blockSize;
1403
1404     /* get network related info */
1405     cm_noIPAddr = CM_MAXINTERFACE_ADDR;
1406     code = syscfg_GetIFInfo(&cm_noIPAddr,
1407                              cm_IPAddr, cm_SubnetMask,
1408                              cm_NetMtu, cm_NetFlags);
1409
1410     if ( (cm_noIPAddr <= 0) || (code <= 0 ) )
1411         afsi_log("syscfg_GetIFInfo error code %d", code);
1412     else
1413         afsi_log("First Network address %x SubnetMask %x",
1414                   cm_IPAddr[0], cm_SubnetMask[0]);
1415
1416     /*
1417      * Save client configuration for GetCacheConf\eig requests
1418      */
1419     cm_initParams.nChunkFiles = 0;
1420     cm_initParams.nStatCaches = stats;
1421     cm_initParams.nDataCaches = (afs_uint32)(cacheBlocks > 0xFFFFFFFF ? 0xFFFFFFFF : cacheBlocks);
1422     cm_initParams.nVolumeCaches = volumes;
1423     cm_initParams.firstChunkSize = cm_chunkSize;
1424     cm_initParams.otherChunkSize = cm_chunkSize;
1425     cm_initParams.cacheSize = cacheSize;
1426     cm_initParams.setTime = 0;
1427     cm_initParams.memCache = 1;
1428
1429     /* init user daemon, and other packages */
1430     cm_InitUser();
1431
1432     cm_InitConn();
1433
1434     cm_InitServer();
1435
1436     cm_InitIoctl();
1437
1438     smb_InitIoctl();
1439
1440     cm_InitCallback();
1441
1442     cm_InitNormalization();
1443
1444     code = cm_InitMappedMemory(cm_virtualCache, cm_CachePath, stats, volumes, cells, cm_chunkSize, cacheBlocks, blockSize);
1445     afsi_log("cm_InitMappedMemory code %x", code);
1446     if (code != 0) {
1447         *reasonP = "error initializing cache file";
1448         return -1;
1449     }
1450
1451     /* Must be called after cm_InitMappedMemory. */
1452     cm_EAccesInitCache();
1453
1454 #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
1455     if (cm_InitDNS(cm_dnsEnabled) == -1)
1456         cm_dnsEnabled = 0;  /* init failed, so deactivate */
1457     afsi_log("cm_InitDNS %d", cm_dnsEnabled);
1458 #endif
1459
1460     /* Set RX parameters before initializing RX */
1461     if ( rx_nojumbo ) {
1462         rx_SetNoJumbo();
1463         afsi_log("rx_SetNoJumbo successful");
1464     }
1465
1466     if ( rx_mtu != -1 ) {
1467         rx_SetMaxMTU(rx_mtu);
1468         afsi_log("rx_SetMaxMTU %d successful", rx_mtu);
1469     }
1470
1471     if ( rx_udpbufsize != -1 ) {
1472         rx_SetUdpBufSize(rx_udpbufsize);
1473         afsi_log("rx_SetUdpBufSize %d", rx_udpbufsize);
1474     }
1475
1476     rx_SetBusyChannelError(1);  /* Activate busy call channel reporting */
1477
1478     /* initialize RX, and tell it to listen to the callbackport,
1479      * which is used for callback RPC messages.
1480      */
1481     code = rx_Init(htons(cm_callbackport));
1482     if (code != 0) {
1483         afsi_log("rx_Init code %x - retrying with a random port number", code);
1484         code = rx_Init(0);
1485     }
1486     afsi_log("rx_Init code %x", code);
1487     if (code != 0) {
1488         *reasonP = "afsd: failed to init rx client";
1489         return -1;
1490     }
1491
1492     /* create an unauthenticated service #1 for callbacks */
1493     nullServerSecurityClassp = rxnull_NewServerSecurityObject();
1494     serverp = rx_NewService(0, 1, "AFS", &nullServerSecurityClassp, 1,
1495                              RXAFSCB_ExecuteRequest);
1496     afsi_log("rx_NewService addr %x", PtrToUlong(serverp));
1497     if (serverp == NULL) {
1498         *reasonP = "unknown error";
1499         return -1;
1500     }
1501     rx_SetMinProcs(serverp, 2);
1502     rx_SetMaxProcs(serverp, 4);
1503     rx_SetCheckReach(serverp, 1);
1504
1505     nullServerSecurityClassp = rxnull_NewServerSecurityObject();
1506     serverp = rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats",
1507                              &nullServerSecurityClassp, 1, RXSTATS_ExecuteRequest);
1508     afsi_log("rx_NewService addr %x", PtrToUlong(serverp));
1509     if (serverp == NULL) {
1510         *reasonP = "unknown error";
1511         return -1;
1512     }
1513     rx_SetMinProcs(serverp, 2);
1514     rx_SetMaxProcs(serverp, 4);
1515
1516     /* start server threads, *not* donating this one to the pool */
1517     rx_StartServer(0);
1518     afsi_log("rx_StartServer");
1519
1520     if (rx_enable_peer_stats)
1521         rx_enablePeerRPCStats();
1522
1523     if (rx_enable_process_stats)
1524         rx_enableProcessRPCStats();
1525
1526     code = cm_GetRootCellName(rootCellName);
1527     afsi_log("cm_GetRootCellName code %d, cm_freelanceEnabled= %d, rcn= %s",
1528              code, cm_freelanceEnabled, (code ? "<none>" : rootCellName));
1529     if (code != 0 && !cm_freelanceEnabled)
1530     {
1531         *reasonP = "can't find root cell name in " AFS_CELLSERVDB;
1532         return -1;
1533     }
1534     else if (cm_freelanceEnabled)
1535         cm_data.rootCellp = NULL;
1536
1537     if (code == 0 && !cm_freelanceEnabled)
1538     {
1539         cm_data.rootCellp = cm_GetCell(rootCellName, CM_FLAG_CREATE);
1540         afsi_log("cm_GetCell addr %x", PtrToUlong(cm_data.rootCellp));
1541         if (cm_data.rootCellp == NULL)
1542         {
1543             *reasonP = "can't find root cell in " AFS_CELLSERVDB;
1544             return -1;
1545         }
1546     }
1547
1548 #ifdef AFS_FREELANCE_CLIENT
1549     if (cm_freelanceEnabled)
1550         cm_InitFreelance();
1551 #endif
1552
1553     /* Initialize the RPC server for session keys */
1554     RpcInit();
1555
1556     /* Initialize the RPC server for pipe services */
1557     MSRPC_Init();
1558
1559     afsd_InitServerPreferences();
1560
1561     code = afsd_InitRoot(reasonP);
1562
1563     return code;
1564 }
1565
1566 int afsd_ShutdownCM(void)
1567 {
1568     MSRPC_Shutdown();
1569
1570     cm_ReleaseSCache(cm_data.rootSCachep);
1571
1572     cm_utilsCleanup();
1573
1574     cm_shutdown = 1;
1575
1576     return 0;
1577 }
1578
1579 int afsd_InitDaemons(char **reasonP)
1580 {
1581     cm_InitDaemon(numBkgD);
1582     afsi_log("cm_InitDaemon complete");
1583
1584     return 0;
1585 }
1586
1587 int afsd_InitSMB(char **reasonP, void *aMBfunc)
1588 {
1589     HKEY parmKey;
1590     DWORD dummyLen;
1591     DWORD dwValue;
1592     DWORD code;
1593
1594     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
1595                          0, KEY_QUERY_VALUE, &parmKey);
1596     if (code == ERROR_SUCCESS) {
1597         dummyLen = sizeof(DWORD);
1598         code = RegQueryValueEx(parmKey, "StoreAnsiFilenames", NULL, NULL,
1599                                 (BYTE *) &dwValue, &dummyLen);
1600         if (code == ERROR_SUCCESS)
1601             smb_StoreAnsiFilenames = dwValue ? 1 : 0;
1602         afsi_log("StoreAnsiFilenames = %d", smb_StoreAnsiFilenames);
1603
1604         dummyLen = sizeof(DWORD);
1605         code = RegQueryValueEx(parmKey, "EnableSMBAsyncStore", NULL, NULL,
1606                                 (BYTE *) &dwValue, &dummyLen);
1607         if (code == ERROR_SUCCESS)
1608             smb_AsyncStore = dwValue == 2 ? 2 : (dwValue ? 1 : 0);
1609         afsi_log("EnableSMBAsyncStore = %d", smb_AsyncStore);
1610
1611         dummyLen = sizeof(DWORD);
1612         code = RegQueryValueEx(parmKey, "SMBAsyncStoreSize", NULL, NULL,
1613                                 (BYTE *) &dwValue, &dummyLen);
1614         if (code == ERROR_SUCCESS) {
1615             /* Should check for >= blocksize && <= chunksize && round down to multiple of blocksize */
1616             if (dwValue > cm_chunkSize)
1617                 smb_AsyncStoreSize = cm_chunkSize;
1618             else if (dwValue <  cm_data.buf_blockSize)
1619                 smb_AsyncStoreSize = cm_data.buf_blockSize;
1620             else
1621                 smb_AsyncStoreSize = (dwValue & ~(cm_data.buf_blockSize-1));
1622         } else
1623             smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
1624         afsi_log("SMBAsyncStoreSize = %d", smb_AsyncStoreSize);
1625
1626         dummyLen = sizeof(DWORD);
1627         code = RegQueryValueEx(parmKey, "SMBInterfaceEnabled", NULL, NULL,
1628                                 (BYTE *) &dwValue, &dummyLen);
1629         if (code == ERROR_SUCCESS)
1630             smb_Enabled = dwValue ? 1 : 0;
1631         afsi_log("SMBInterfaceEnabled = %d", smb_Enabled);
1632
1633         RegCloseKey (parmKey);
1634     }
1635
1636     if ( smb_Enabled ) {
1637         /* Do this last so that we don't handle requests before init is done.
1638          * Here we initialize the SMB listener.
1639          */
1640         smb_Init(afsd_logp, smb_UseV3, numSvThreads, aMBfunc);
1641         afsi_log("smb_Init complete");
1642     } else {
1643         smb_configureBackConnectionHostNames(FALSE);
1644
1645         if (msftSMBRedirectorSupportsExtendedTimeouts()) {
1646             afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
1647             smb_configureExtendedSMBSessionTimeouts(FALSE);
1648         }
1649         afsi_log("smb_Init skipped");
1650     }
1651
1652     return 0;
1653 }
1654
1655 #ifdef ReadOnly
1656 #undef ReadOnly
1657 #endif
1658
1659 #ifdef File
1660 #undef File
1661 #endif
1662
1663 #pragma pack( push, before_imagehlp, 8 )
1664 #include <imagehlp.h>
1665 #pragma pack( pop, before_imagehlp )
1666
1667 #define MAXNAMELEN 1024
1668
1669 void afsd_printStack(HANDLE hThread, CONTEXT *c)
1670 {
1671     HANDLE hProcess = GetCurrentProcess();
1672     int frameNum;
1673 #if defined(_AMD64_)
1674     DWORD64 offset;
1675 #elif defined(_X86_)
1676     DWORD offset;
1677 #endif
1678     DWORD symOptions;
1679     char functionName[MAXNAMELEN];
1680
1681     IMAGEHLP_MODULE Module;
1682     IMAGEHLP_LINE Line;
1683
1684     STACKFRAME s;
1685     IMAGEHLP_SYMBOL *pSym;
1686
1687     afsi_log_useTimestamp = 0;
1688
1689     pSym = (IMAGEHLP_SYMBOL *) GlobalAlloc(0, sizeof (IMAGEHLP_SYMBOL) + MAXNAMELEN);
1690
1691     memset( &s, '\0', sizeof s );
1692     if (!SymInitialize(hProcess, NULL, 1) )
1693     {
1694         afsi_log("SymInitialize(): GetLastError() = %lu\n", GetLastError() );
1695
1696         SymCleanup( hProcess );
1697         GlobalFree(pSym);
1698
1699         return;
1700     }
1701
1702     symOptions = SymGetOptions();
1703     symOptions |= SYMOPT_LOAD_LINES;
1704     symOptions &= ~SYMOPT_UNDNAME;
1705     SymSetOptions( symOptions );
1706
1707     /*
1708      * init STACKFRAME for first call
1709      * Notes: AddrModeFlat is just an assumption. I hate VDM debugging.
1710      * Notes: will have to be #ifdef-ed for Alphas; MIPSes are dead anyway,
1711      * and good riddance.
1712      */
1713 #if defined (_ALPHA_) || defined (_MIPS_) || defined (_PPC_)
1714 #error The STACKFRAME initialization in afsd_printStack() for this platform
1715 #error must be properly configured
1716 #elif defined(_AMD64_)
1717     s.AddrPC.Offset = c->Rip;
1718     s.AddrPC.Mode = AddrModeFlat;
1719     s.AddrFrame.Offset = c->Rbp;
1720     s.AddrFrame.Mode = AddrModeFlat;
1721 #else
1722     s.AddrPC.Offset = c->Eip;
1723     s.AddrPC.Mode = AddrModeFlat;
1724     s.AddrFrame.Offset = c->Ebp;
1725     s.AddrFrame.Mode = AddrModeFlat;
1726 #endif
1727
1728     memset( pSym, '\0', sizeof (IMAGEHLP_SYMBOL) + MAXNAMELEN );
1729     pSym->SizeOfStruct = sizeof (IMAGEHLP_SYMBOL);
1730     pSym->MaxNameLength = MAXNAMELEN;
1731
1732     memset( &Line, '\0', sizeof Line );
1733     Line.SizeOfStruct = sizeof Line;
1734
1735     memset( &Module, '\0', sizeof Module );
1736     Module.SizeOfStruct = sizeof Module;
1737
1738     offset = 0;
1739
1740     afsi_log("\n--# FV EIP----- RetAddr- FramePtr StackPtr Symbol" );
1741
1742     for ( frameNum = 0; ; ++ frameNum )
1743     {
1744         /*
1745          * get next stack frame (StackWalk(), SymFunctionTableAccess(),
1746          * SymGetModuleBase()). if this returns ERROR_INVALID_ADDRESS (487) or
1747          * ERROR_NOACCESS (998), you can assume that either you are done, or
1748          * that the stack is so hosed that the next deeper frame could not be
1749          * found.
1750          */
1751         if ( ! StackWalk( IMAGE_FILE_MACHINE_I386, hProcess, hThread, &s, c,
1752                           NULL, SymFunctionTableAccess, SymGetModuleBase,
1753                           NULL ) )
1754             break;
1755
1756         /* display its contents */
1757         afsi_log("\n%3d %c%c %08lx %08lx %08lx %08lx ",
1758                  frameNum, s.Far? 'F': '.', s.Virtual? 'V': '.',
1759                  s.AddrPC.Offset, s.AddrReturn.Offset,
1760                  s.AddrFrame.Offset, s.AddrStack.Offset );
1761
1762         if ( s.AddrPC.Offset == 0 )
1763         {
1764             afsi_log("(-nosymbols- PC == 0)" );
1765         }
1766         else
1767         {
1768             /* show procedure info from a valid PC */
1769             if (!SymGetSymFromAddr(hProcess, s.AddrPC.Offset, &offset, pSym))
1770             {
1771                 if ( GetLastError() != ERROR_INVALID_ADDRESS )
1772                 {
1773                     afsi_log("SymGetSymFromAddr(): errno = %lu",
1774                              GetLastError());
1775                 }
1776             }
1777             else
1778             {
1779                 UnDecorateSymbolName(pSym->Name, functionName, MAXNAMELEN,
1780                                      UNDNAME_NAME_ONLY);
1781                 afsi_log("%s", functionName );
1782
1783                 if ( offset != 0 )
1784                 {
1785                     afsi_log(" %+ld bytes", (long) offset);
1786                 }
1787             }
1788
1789             if (!SymGetLineFromAddr(hProcess, s.AddrPC.Offset, &offset, &Line))
1790             {
1791                 if (GetLastError() != ERROR_INVALID_ADDRESS)
1792                 {
1793                     afsi_log("Error: SymGetLineFromAddr(): errno = %lu",
1794                              GetLastError());
1795                 }
1796             }
1797             else
1798             {
1799                 afsi_log("    Line: %s(%lu) %+ld bytes", Line.FileName,
1800                          Line.LineNumber, offset);
1801             }
1802         }
1803
1804         /* no return address means no deeper stackframe */
1805         if (s.AddrReturn.Offset == 0)
1806         {
1807             SetLastError(0);
1808             break;
1809         }
1810     }
1811
1812     if (GetLastError() != 0)
1813     {
1814         afsi_log("\nStackWalk(): errno = %lu\n", GetLastError());
1815     }
1816
1817     SymCleanup(hProcess);
1818     GlobalFree(pSym);
1819 }
1820
1821 #ifdef _DEBUG
1822 static DWORD *afsd_crtDbgBreakCurrent = NULL;
1823 static DWORD afsd_crtDbgBreaks[256];
1824 #endif
1825
1826 static EFaultRepRetVal (WINAPI *pReportFault)(LPEXCEPTION_POINTERS pep, DWORD dwMode) = NULL;
1827 static BOOL (WINAPI *pMiniDumpWriteDump)(HANDLE hProcess,DWORD ProcessId,HANDLE hFile,
1828                                   MINIDUMP_TYPE DumpType,
1829                                   PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
1830                                   PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
1831                                   PMINIDUMP_CALLBACK_INFORMATION CallbackParam) = NULL;
1832
1833
1834 static HANDLE
1835 OpenDumpFile(void)
1836 {
1837     char tmp[256];
1838     char wd[256];
1839     SYSTEMTIME st;
1840     DWORD code;
1841
1842     code = GetEnvironmentVariable("TEMP", tmp, sizeof(tmp));
1843     if ( code == 0 || code > sizeof(tmp) )
1844     {
1845         if (!GetWindowsDirectory(tmp, sizeof(tmp)))
1846             return NULL;
1847     }
1848     GetLocalTime(&st);
1849     StringCbPrintfA(wd, sizeof(wd),
1850                     "%s\\afsd-%04d-%02d-%02d-%02d_%02d_%02d.dmp", tmp,
1851                     st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
1852     return CreateFile( wd, GENERIC_WRITE, FILE_SHARE_READ, NULL,
1853                             CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
1854 }
1855
1856 void
1857 GenerateMiniDump(PEXCEPTION_POINTERS ep)
1858 {
1859     if (IsDebuggerPresent())
1860         return;
1861
1862     if (ep == NULL)
1863     {
1864         // Generate exception to get proper context in dump
1865         __try
1866         {
1867             RaiseException(DBG_CONTINUE, 0, 0, NULL);
1868         }
1869         __except(GenerateMiniDump(GetExceptionInformation()), EXCEPTION_CONTINUE_EXECUTION)
1870         {
1871         }
1872     }
1873     else
1874     {
1875         MINIDUMP_EXCEPTION_INFORMATION eInfo;
1876         HANDLE hFile = NULL;
1877         HMODULE hDbgHelp = NULL;
1878
1879         hDbgHelp = LoadLibrary("Dbghelp.dll");
1880         if ( hDbgHelp == NULL )
1881             return;
1882
1883         (FARPROC) pMiniDumpWriteDump = GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
1884         if ( pMiniDumpWriteDump == NULL ) {
1885             FreeLibrary(hDbgHelp);
1886             return;
1887         }
1888
1889         hFile = OpenDumpFile();
1890
1891         if ( hFile ) {
1892             HKEY parmKey;
1893             DWORD dummyLen;
1894             DWORD dwValue;
1895             DWORD code;
1896             DWORD dwMiniDumpType = MiniDumpWithDataSegs;
1897
1898             code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
1899                                  0, KEY_QUERY_VALUE, &parmKey);
1900             if (code == ERROR_SUCCESS) {
1901                 dummyLen = sizeof(DWORD);
1902                 code = RegQueryValueEx(parmKey, "MiniDumpType", NULL, NULL,
1903                                         (BYTE *) &dwValue, &dummyLen);
1904                 if (code == ERROR_SUCCESS)
1905                     dwMiniDumpType = dwValue;
1906                 RegCloseKey (parmKey);
1907             }
1908
1909             eInfo.ThreadId = GetCurrentThreadId();
1910             eInfo.ExceptionPointers = ep;
1911             eInfo.ClientPointers = FALSE;
1912
1913             pMiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(),
1914                                 hFile, dwMiniDumpType, ep ? &eInfo : NULL,
1915                                 NULL, NULL);
1916
1917             CloseHandle(hFile);
1918         }
1919         FreeLibrary(hDbgHelp);
1920     }
1921 }
1922
1923 LONG __stdcall afsd_ExceptionFilter(EXCEPTION_POINTERS *ep)
1924 {
1925     CONTEXT context;
1926 #ifdef _DEBUG
1927     BOOL allocRequestBrk = FALSE;
1928 #endif
1929     HMODULE hLib = NULL;
1930
1931     afsi_log("UnhandledException : code : 0x%x, address: 0x%x\n",
1932              ep->ExceptionRecord->ExceptionCode,
1933              ep->ExceptionRecord->ExceptionAddress);
1934
1935 #ifdef _DEBUG
1936     if (afsd_crtDbgBreakCurrent &&
1937         *afsd_crtDbgBreakCurrent == _CrtSetBreakAlloc(*afsd_crtDbgBreakCurrent))
1938     {
1939         allocRequestBrk = TRUE;
1940         afsi_log("Breaking on alloc request # %d\n", *afsd_crtDbgBreakCurrent);
1941     }
1942 #endif
1943
1944     /* save context if we want to print the stack information */
1945     context = *ep->ContextRecord;
1946
1947     afsd_printStack(GetCurrentThread(), &context);
1948
1949     GenerateMiniDump(ep);
1950
1951     hLib = LoadLibrary("Faultrep.dll");
1952     if ( hLib ) {
1953         (FARPROC) pReportFault = GetProcAddress(hLib, "ReportFault");
1954         if ( pReportFault )
1955             pReportFault(ep, 0);
1956         FreeLibrary(hLib);
1957     }
1958
1959     if (ep->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT)
1960     {
1961         afsi_log("\nEXCEPTION_BREAKPOINT - continue execution ...\n");
1962
1963 #ifdef _DEBUG
1964         if (allocRequestBrk)
1965         {
1966             afsd_crtDbgBreakCurrent++;
1967             _CrtSetBreakAlloc(*afsd_crtDbgBreakCurrent);
1968         }
1969 #endif
1970 #if defined(_X86)
1971         ep->ContextRecord->Eip++;
1972 #endif
1973 #if defined(_AMD64_)
1974         ep->ContextRecord->Rip++;
1975 #endif
1976         return EXCEPTION_CONTINUE_EXECUTION;
1977     }
1978     else
1979     {
1980         return EXCEPTION_CONTINUE_SEARCH;
1981     }
1982 }
1983
1984 void afsd_SetUnhandledExceptionFilter()
1985 {
1986 #ifndef NOTRACE
1987     SetUnhandledExceptionFilter(afsd_ExceptionFilter);
1988 #endif
1989 }
1990
1991 #ifdef _DEBUG
1992 void afsd_DbgBreakAllocInit()
1993 {
1994     memset(afsd_crtDbgBreaks, -1, sizeof(afsd_crtDbgBreaks));
1995     afsd_crtDbgBreakCurrent = afsd_crtDbgBreaks;
1996 }
1997
1998 void afsd_DbgBreakAdd(DWORD requestNumber)
1999 {
2000     int i;
2001     for (i = 0; i < sizeof(afsd_crtDbgBreaks) - 1; i++)
2002         {
2003         if (afsd_crtDbgBreaks[i] == -1)
2004             {
2005             break;
2006             }
2007         }
2008     afsd_crtDbgBreaks[i] = requestNumber;
2009
2010     _CrtSetBreakAlloc(afsd_crtDbgBreaks[0]);
2011 }
2012 #endif