2 * Copyright 2000, International Business Machines Corporation and others.
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
11 #include <afs/param.h>
15 #include "afs_config.h"
19 #include "../afsd/fs_utils.h"
21 #define __CM_CONFIG_INTERFACES_ONLY__
22 #include "../afsd/cm_config.h"
24 #define __CM_IOCTL_INTERFACES_ONLY__
25 #include "../afsd/cm_ioctl.h"
30 #define cREALLOC_PREFS 32
32 #define cSERVERPREFS_CHUNK 256
34 #define PIOCTL_MAXSIZE 2048
38 * REGISTRY ___________________________________________________________________
42 static TCHAR cszLANMANDEVICE[] = TEXT("\\Device\\LanmanRedirector\\");
43 const TCHAR AFSConfigKeyName[] = TEXT("SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters");
47 * ROUTINES ___________________________________________________________________
51 static DWORD log2 (DWORD dwValue)
53 for (DWORD dwLog = 0; (DWORD)(1<<dwLog) < dwValue; ++dwLog)
58 DWORD Config_GetServiceState (void)
62 TCHAR szGateway[ cchRESOURCE ] = TEXT("");
63 Config_GetGatewayName (szGateway);
64 return (szGateway[0]) ? SERVICE_RUNNING : SERVICE_STOPPED;
67 SERVICE_STATUS Status;
68 memset (&Status, 0x00, sizeof(Status));
71 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
74 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
76 QueryServiceStatus (hService, &Status);
77 CloseServiceHandle (hService);
80 CloseServiceHandle (hManager);
83 return Status.dwCurrentState;
88 * Configuration Routine ______________________________________________________
92 void Config_GetGatewayFlag (BOOL *pfFlag)
94 if (!Config_ReadNum (TEXT("IsGateway"), (DWORD*)pfFlag))
99 BOOL Config_SetGatewayFlag (BOOL fFlag, ULONG *pStatus)
101 Config_WriteNum (TEXT("IsGateway"), fFlag);
102 g.fNeedRestart = TRUE;
107 void Config_GetGatewayName (LPTSTR pszName)
109 if (!Config_ReadString (TEXT("Gateway"), pszName, MAX_PATH))
110 GetString (pszName, IDS_GATEWAY_UNKNOWN);
112 GetString (pszName, IDS_GATEWAY_UNKNOWN);
116 BOOL Config_SetGatewayName (LPCTSTR pszName, ULONG *pStatus)
118 TCHAR szBogus[ cchRESOURCE ];
119 GetString (szBogus, IDS_GATEWAY_UNKNOWN);
120 if (!lstrcmpi (szBogus, pszName))
122 Config_WriteString (TEXT("Gateway"), TEXT(""));
126 Config_WriteString (TEXT("Gateway"), pszName);
133 void Config_FixGatewayDrives (void)
135 // Zip through the user's network drives and reconnect
136 // them as necessary.
138 for (TCHAR chDrive = chDRIVE_A; chDrive <= chDRIVE_Z; ++chDrive)
140 TCHAR szSubmount[ MAX_PATH ];
141 if (!GetDriveSubmount (chDrive, szSubmount))
144 // We've got a mapping into AFS! Remove it, rather forcefully.
146 TCHAR szDrive[] = "@:";
147 szDrive[0] = chDrive;
148 WNetCancelConnection (szDrive, TRUE);
151 // Now recreate our drive mappings, based on the user's already-
152 // specified preferences.
155 QueryDriveMapList (&List);
157 for (size_t ii = 0; ii < 26; ++ii)
159 if (!List.aDriveMap[ii].szMapping[0])
161 ActivateDriveMap (List.aDriveMap[ii].chDrive, List.aDriveMap[ii].szMapping, List.aDriveMap[ii].szSubmount, List.aDriveMap[ii].fPersistent);
166 void Config_GetCellName (LPTSTR pszName)
168 if (!Config_ReadString (TEXT("Cell"), pszName, MAX_PATH))
169 GetString (pszName, IDS_CELL_UNKNOWN);
171 GetString (pszName, IDS_CELL_UNKNOWN);
175 BOOL Config_ContactGateway (LPTSTR pszGateway, LPTSTR pszCell)
179 BYTE OutData[ PIOCTL_MAXSIZE ];
180 memset (OutData, 0x00, sizeof(OutData));
182 struct ViceIoctl IOInfo;
185 IOInfo.out = (char *)OutData;
186 IOInfo.out_size = PIOCTL_MAXSIZE;
188 TCHAR szOldGateway[ MAX_PATH ];
189 Config_GetGatewayName (szOldGateway);
190 Config_SetGatewayName (pszGateway);
193 if ((status = pioctl (0, VIOC_GET_WS_CELL, &IOInfo, 1)) == 0)
197 lstrcpy (pszCell, (LPCTSTR)OutData);
202 Config_SetGatewayName (szOldGateway);
208 BOOL Config_SetCellName (LPCTSTR pszName, ULONG *pStatus)
210 TCHAR szBogus[ cchRESOURCE ];
211 GetString (szBogus, IDS_CELL_UNKNOWN);
212 if (lstrcmpi (szBogus, pszName))
214 Config_WriteString (TEXT("Cell"), pszName);
215 g.fNeedRestart = TRUE;
221 /* These two functions are not needed as of the 1.2.2a updates.
222 The old implementation used to 'bind' afslogon.dll to the credentials manager
223 when the Integrated Logon was selected.
225 With version 1.2.2a afslogon.dll is always 'bound' to the credentials manager; therefore,
226 the binding operation is done during installation. Note: the Integrated Logon is
227 selected by an entry in the registry (LogonOptions).
229 void Config_GetAuthentFlag (BOOL *pfFlag)
234 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Control\\NetworkProvider\\Order"), 0, KEY_QUERY_VALUE, &hk) == ERROR_SUCCESS)
238 TCHAR szProviders[ MAX_PATH ] = TEXT("");
239 DWORD dwSize = sizeof(szProviders);
241 if (RegQueryValueEx (hk, TEXT("ProviderOrder"), NULL, NULL, (PBYTE)szProviders, &dwSize) == ERROR_SUCCESS)
243 for (LPTSTR pch = szProviders; *pch; )
245 if (!lstrncmpi (pch, TEXT("TransarcAFSDaemon"), lstrlen(TEXT("TransarcAFSDaemon"))))
248 for ( ; *pch && (*pch != TEXT(',')); ++pch)
250 for ( ; *pch == TEXT(','); ++pch)
257 else // (!g.fIsWinNT)
259 TCHAR szLHS[ MAX_PATH ] = TEXT("");
260 DWORD dwSize = sizeof(szLHS);
262 if (RegQueryValueEx (hk, TEXT("TransarcAFSDaemon"), NULL, NULL, (PBYTE)szLHS, &dwSize) == ERROR_SUCCESS)
269 BOOL Config_SetAuthentFlag (BOOL fFlag, ULONG *pStatus)
276 if ((status = RegCreateKeyEx (HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Control\\NetworkProvider\\Order"), 0, TEXT("container"), 0, KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, &hk, &dwDisp)) == ERROR_SUCCESS)
280 TCHAR szOldProviders[ MAX_PATH ] = TEXT("");
281 TCHAR szNewProviders[ MAX_PATH ] = TEXT("");
282 DWORD dwSize = sizeof(szOldProviders);
283 RegQueryValueEx (hk, TEXT("ProviderOrder"), NULL, NULL, (PBYTE)szOldProviders, &dwSize);
285 for (LPTSTR pch = szOldProviders; *pch; )
288 if (!lstrncmpi (pch, TEXT("TransarcAFSDaemon"), lstrlen(TEXT("TransarcAFSDaemon"))))
296 LPTSTR pchOut = &szNewProviders[ lstrlen(szNewProviders) ];
297 if (szNewProviders[0])
298 *pchOut++ = TEXT(',');
299 for ( ; *pch && (*pch != TEXT(',')); )
301 *pchOut = TEXT('\0');
304 for ( ; *pch && (*pch != TEXT(',')); ++pch)
306 for ( ; *pch == TEXT(','); ++pch)
312 if (szNewProviders[0])
313 lstrcat (szNewProviders, TEXT(","));
314 lstrcat (szNewProviders, TEXT("TransarcAFSDaemon"));
317 if ((status = RegSetValueEx (hk, TEXT("ProviderOrder"), NULL, REG_SZ, (PBYTE)szNewProviders, sizeof(TCHAR)*(1+lstrlen(szNewProviders)))) == ERROR_SUCCESS)
320 else // (!g.fIsWinNT)
322 TCHAR szLHS[ cchRESOURCE ] = TEXT("TransarcAFSDaemon");
323 TCHAR szRHS[ cchRESOURCE ] = TEXT("");
327 if ((status = RegSetValueEx (hk, szLHS, NULL, REG_SZ, (PBYTE)szRHS, sizeof(TCHAR)*(lstrlen(szRHS)+1))) == 0)
332 RegDeleteValue (hk, szLHS);
343 Message (MB_ICONHAND, GetErrorTitle(), IDS_FAILCONFIG_AUTHENT, TEXT("%ld"), status);
348 void Config_GetTrayIconFlag (BOOL *pfFlag)
350 if (!Config_ReadNum (TEXT("ShowTrayIcon"), (DWORD*)pfFlag))
355 BOOL Config_SetTrayIconFlag (BOOL fFlag, ULONG *pStatus)
357 Config_WriteNum (TEXT("ShowTrayIcon"), fFlag);
359 for (HWND hSearch = GetWindow (GetDesktopWindow(), GW_CHILD);
360 hSearch && IsWindow(hSearch);
361 hSearch = GetWindow (hSearch, GW_HWNDNEXT))
363 TCHAR szClassName[ cchRESOURCE ];
364 if (GetClassName (hSearch, szClassName, cchRESOURCE))
366 if (!lstrcmpi (szClassName, TEXT("AfsCreds")))
371 if (hSearch && IsWindow(hSearch))
373 UINT msgCheckTerminate = RegisterWindowMessage (TEXT("AfsCredsCheckTerminate"));
374 PostMessage (hSearch, msgCheckTerminate, 0, 0);
376 else if (fFlag && !(hSearch && IsWindow(hSearch)))
378 WinExec (TEXT("AfsCreds.exe /quiet"), SW_SHOW);
385 PSERVERPREFS Config_GetServerPrefs (BOOL fVLServers)
387 PSERVERPREFS pPrefs = New (SERVERPREFS);
388 memset (pPrefs, 0x00, sizeof(SERVERPREFS));
389 pPrefs->fVLServers = fVLServers;
391 if (Config_GetServiceState() == SERVICE_RUNNING)
393 // We retrieve server prefs in batches--start that loop now.
396 for (int iOffset = 0; ; )
398 cm_SPrefRequest_t InData;
399 memset (&InData, 0x00, sizeof(InData));
400 InData.offset = iOffset;
401 InData.flags = (pPrefs->fVLServers) ? CM_SPREF_VLONLY : 0;
402 InData.num_servers = cSERVERPREFS_CHUNK;
404 BYTE OutDataStorage[ sizeof(cm_SPrefInfo_t) + cSERVERPREFS_CHUNK * sizeof(cm_SPref_t) ];
405 memset (OutDataStorage, 0x00, sizeof(OutDataStorage));
406 cm_SPrefInfo_t *pOutData = (cm_SPrefInfo_t *)OutDataStorage;
408 struct ViceIoctl IOInfo;
409 IOInfo.in_size = sizeof(InData);
410 IOInfo.in = (char *)&InData;
411 IOInfo.out = (char *)pOutData;
412 IOInfo.out_size = sizeof(cm_SPrefInfo_t) + cSERVERPREFS_CHUNK * sizeof(cm_SPref_t);
414 if (pioctl (0, VIOC_GETSPREFS, &IOInfo, 1) != 0)
417 if (!REALLOC (pPrefs->aPrefs, pPrefs->cPrefs, iOut + pOutData->num_servers, cREALLOC_PREFS))
420 for (size_t ii = 0; ii < pOutData->num_servers; ++ii)
422 pPrefs->aPrefs[ iOut ].ipServer = pOutData->servers[ ii ].host.s_addr;
423 pPrefs->aPrefs[ iOut ].iRank = pOutData->servers[ ii ].rank;
427 if ((iOffset = pOutData->next_offset) == 0)
436 BOOL Config_SetServerPrefs (PSERVERPREFS pPrefs, ULONG *pStatus)
444 for (size_t ii = 0; ii < pPrefs->cPrefs; ++ii)
446 if (pPrefs->aPrefs[ ii ].fChanged)
452 if (Config_GetServiceState() != SERVICE_RUNNING)
455 status = ERROR_SERVICE_NOT_ACTIVE;
459 size_t cbInDataStorage = sizeof(cm_SSetPref_t) + cChanged * sizeof(cm_SPref_t);
461 PBYTE pInDataStorage;
462 if ((pInDataStorage = (PBYTE)Allocate (cbInDataStorage)) == NULL)
465 status = ERROR_NOT_ENOUGH_MEMORY;
469 memset (pInDataStorage, 0x00, sizeof(cbInDataStorage));
471 cm_SSetPref_t *pInData = (cm_SSetPref_t*)pInDataStorage;
472 pInData->flags = (pPrefs->fVLServers) ? CM_SPREF_VLONLY : 0;
473 pInData->num_servers = cChanged;
476 for (ii = 0; ii < pPrefs->cPrefs; ++ii)
478 if (pPrefs->aPrefs[ ii ].fChanged)
480 pInData->servers[ iOut ].host.s_addr = pPrefs->aPrefs[ ii ].ipServer;
481 pInData->servers[ iOut ].rank = (unsigned short)pPrefs->aPrefs[ ii ].iRank;
486 BYTE OutDataStorage[ PIOCTL_MAXSIZE ];
488 struct ViceIoctl IOInfo;
489 IOInfo.in_size = cbInDataStorage;
490 IOInfo.in = (char *)pInData;
491 IOInfo.out = (char *)OutDataStorage;
492 IOInfo.out_size = PIOCTL_MAXSIZE;
494 if ((status = pioctl (0, VIOC_SETSPREFS, &IOInfo, 1)) != 0)
499 Free (pInDataStorage);
508 Message (MB_ICONHAND, GetErrorTitle(), IDS_FAILCONFIG_PREFS, TEXT("%ld"), status);
513 void Config_FreeServerPrefs (PSERVERPREFS pPrefs)
516 Free (pPrefs->aPrefs);
517 memset (pPrefs, 0xFD, sizeof(SERVERPREFS));
522 void Config_GetCacheSize (ULONG *pckCache)
524 if (!Config_ReadNum (TEXT("CacheSize"), (DWORD*)pckCache))
525 *pckCache = CM_CONFIGDEFAULT_CACHESIZE;
529 BOOL Config_SetCacheSize (ULONG ckCache, ULONG *pStatus)
534 if (Config_GetServiceState() == SERVICE_RUNNING)
537 Config_GetCacheSize (&ckCacheNow);
538 if (ckCacheNow > ckCache)
540 Message (MB_ICONHAND, GetErrorTitle(), IDS_SHRINKCACHE);
544 struct ViceIoctl IOInfo;
545 IOInfo.in_size = sizeof(ULONG);
546 IOInfo.in = (char *)&ckCache;
547 IOInfo.out = (char *)0;
550 if ((status = pioctl (0, VIOCSETCACHESIZE, &IOInfo, 1)) != 0)
558 Config_WriteNum (TEXT("CacheSize"), ckCache);
564 Message (MB_ICONHAND, GetErrorTitle(), IDS_FAILCONFIG_CACHE, TEXT("%ld"), status);
570 void Config_GetChunkSize (ULONG *pckChunk)
572 if (!Config_ReadNum (TEXT("ChunkSize"), (DWORD*)pckChunk))
573 *pckChunk = CM_CONFIGDEFAULT_CHUNKSIZE;
574 *pckChunk = max (*pckChunk, 10);
575 *pckChunk = (1 << ((*pckChunk)-10));
579 BOOL Config_SetChunkSize (ULONG ckChunk, ULONG *pStatus)
581 Config_WriteNum (TEXT("ChunkSize"), log2(ckChunk * 1024));
582 g.fNeedRestart = TRUE;
588 void Config_GetStatEntries (ULONG *pcEntries)
590 if (!Config_ReadNum (TEXT("Stats"), (DWORD*)pcEntries))
591 *pcEntries = CM_CONFIGDEFAULT_STATS;
595 BOOL Config_SetStatEntries (ULONG cEntries, ULONG *pStatus)
597 Config_WriteNum (TEXT("Stats"), cEntries);
598 g.fNeedRestart = TRUE;
604 void Config_GetProbeInt (ULONG *pcsecProbe)
607 // TODO: NEED REGISTRY SETTING
611 BOOL Config_SetProbeInt (ULONG csecProbe, ULONG *pStatus)
616 // TODO: NEED REGISTRY SETTING
617 if (Config_GetServiceState() == SERVICE_RUNNING)
619 struct chservinfo checkserv;
620 memset (&checkserv, 0x00, sizeof(checkserv));
621 checkserv.magic = 0x12345678;
622 checkserv.tinterval = csecProbe;
624 BYTE OutData[ PIOCTL_MAXSIZE ];
625 memset (OutData, 0x00, sizeof(OutData));
627 struct ViceIoctl IOInfo;
628 IOInfo.in_size = sizeof(checkserv);
629 IOInfo.in = (char *)&checkserv;
630 IOInfo.out = (char *)OutData;
631 IOInfo.out_size = PIOCTL_MAXSIZE;
633 if ((status = pioctl (0, VIOCCKSERV, &IOInfo, 1)) != 0)
642 Message (MB_ICONHAND, GetErrorTitle(), IDS_FAILCONFIG_PROBE, TEXT("%ld"), status);
648 void Config_GetNumThreads (ULONG *pcThreads)
650 if (!Config_ReadNum (TEXT("ServerThreads"), (DWORD*)pcThreads))
651 *pcThreads = CM_CONFIGDEFAULT_SVTHREADS;
655 BOOL Config_SetNumThreads (ULONG cThreads, ULONG *pStatus)
657 Config_WriteNum (TEXT("ServerThreads"), cThreads);
658 g.fNeedRestart = TRUE;
664 void Config_GetNumDaemons (ULONG *pcDaemons)
666 if (!Config_ReadNum (TEXT("Daemons"), (DWORD*)pcDaemons))
667 *pcDaemons = CM_CONFIGDEFAULT_DAEMONS;
671 BOOL Config_SetNumDaemons (ULONG cDaemons, ULONG *pStatus)
673 Config_WriteNum (TEXT("Daemons"), cDaemons);
674 g.fNeedRestart = TRUE;
680 void Config_GetSysName (LPTSTR pszName)
682 if (!Config_ReadString (TEXT("SysName"), pszName, MAX_PATH))
683 lstrcpy (pszName, TEXT("i386_nt40"));
687 BOOL Config_SetSysName (LPCTSTR pszName, ULONG *pStatus)
692 if (Config_GetServiceState() == SERVICE_RUNNING)
696 TCHAR szData[ PIOCTL_MAXSIZE ];
698 memset (&InData, 0x00, sizeof(InData));
699 InData.cbData = lstrlen(pszName);
700 lstrcpy (InData.szData, pszName);
702 BYTE OutData[ PIOCTL_MAXSIZE ];
703 memset (OutData, 0x00, sizeof(OutData));
705 struct ViceIoctl IOInfo;
706 IOInfo.in_size = sizeof(ULONG) +lstrlen(pszName) +1;
707 IOInfo.in = (char *)&InData;
708 IOInfo.out = (char *)OutData;
709 IOInfo.out_size = PIOCTL_MAXSIZE;
711 if ((status = pioctl (0, VIOC_AFS_SYSNAME, &IOInfo, 1)) != 0)
719 Config_WriteString (TEXT("SysName"), pszName);
725 Message (MB_ICONHAND, GetErrorTitle(), IDS_FAILCONFIG_SYSNAME, TEXT("%ld"), status);
731 void Config_GetRootVolume (LPTSTR pszName)
733 if (!Config_ReadString (TEXT("RootVolume"), pszName, MAX_PATH))
734 lstrcpy (pszName, TEXT("root.afs"));
738 BOOL Config_SetRootVolume (LPCTSTR pszName, ULONG *pStatus)
740 Config_WriteString (TEXT("RootVolume"), pszName);
741 g.fNeedRestart = TRUE;
747 void Config_GetMountRoot (LPTSTR pszPath)
749 if (!Config_ReadString (TEXT("MountRoot"), pszPath, MAX_PATH))
750 lstrcpy (pszPath, TEXT("/afs"));
754 BOOL Config_SetMountRoot (LPCTSTR pszPath, ULONG *pStatus)
756 Config_WriteString (TEXT("MountRoot"), pszPath);
757 g.fNeedRestart = TRUE;
762 BOOL Config_GetCacheInUse (ULONG *pckCacheInUse, ULONG *pStatus)
769 if (Config_GetServiceState() != SERVICE_RUNNING)
772 status = ERROR_SERVICE_NOT_ACTIVE;
776 BYTE OutData[ PIOCTL_MAXSIZE ];
777 memset (OutData, 0x00, sizeof(OutData));
779 struct ViceIoctl IOInfo;
781 IOInfo.in = (char *)0;
782 IOInfo.out = (char *)OutData;
783 IOInfo.out_size = PIOCTL_MAXSIZE;
785 if ((status = pioctl (0, VIOCGETCACHEPARMS, &IOInfo, 1)) != 0)
791 *pckCacheInUse = ((LONG*)OutData)[1];
800 void Config_GetCachePath (LPTSTR pszCachePath)
802 if (!Config_ReadString (TEXT("CachePath"), pszCachePath, MAX_PATH)) {
803 TCHAR szPath[MAX_PATH];
804 GetWindowsDirectory(szPath, sizeof(szPath));
805 szPath[2] = 0; /* get drive letter only */
806 strcat(szPath, "\\AFSCache");
808 lstrcpy (pszCachePath, szPath);
812 BOOL Config_SetCachePath(LPCTSTR pszPath, ULONG *pStatus)
814 Config_WriteString (TEXT("CachePath"), pszPath);
815 g.fNeedRestart = TRUE;
819 void Config_GetLanAdapter (ULONG *pnLanAdapter)
821 if (!Config_ReadNum (TEXT("LANadapter"), (DWORD*)pnLanAdapter))
825 BOOL Config_SetLanAdapter (ULONG nLanAdapter, ULONG *pStatus)
827 Config_WriteNum (TEXT("LANadapter"), nLanAdapter);
828 g.fNeedRestart = TRUE;
832 void Config_GetTrapOnPanic (BOOL *pfFlag)
834 if (!Config_ReadNum (TEXT("TrapOnPanic"), (DWORD*)pfFlag))
838 BOOL Config_SetTrapOnPanic (BOOL fFlag, ULONG *pStatus)
840 Config_WriteNum (TEXT("TrapOnPanic"), fFlag);
841 g.fNeedRestart = TRUE;
845 void Config_GetTraceBufferSize (ULONG *pnBufSize)
847 if (!Config_ReadNum (TEXT("TraceBufferSize"), (DWORD*)pnBufSize))
851 BOOL Config_SetTraceBufferSize (ULONG nBufSize, ULONG *pStatus)
853 Config_WriteNum (TEXT("TraceBufferSize"), nBufSize);
854 g.fNeedRestart = TRUE;
858 void Config_GetLoginRetryInterval (ULONG *pnInterval)
860 if (!Config_ReadNum (TEXT("LoginRetryInterval"), (DWORD*)pnInterval))
864 BOOL Config_SetLoginRetryInterval (ULONG nInterval, ULONG *pStatus)
866 Config_WriteNum (TEXT("LoginRetryInterval"), nInterval);
870 void Config_GetFailLoginsSilently (BOOL *pfFlag)
872 if (!Config_ReadNum (TEXT("FailLoginsSilently"), (DWORD*)pfFlag))
876 BOOL Config_SetFailLoginsSilently (BOOL fFlag, ULONG *pStatus)
878 Config_WriteNum (TEXT("FailLoginsSilently"), fFlag);
882 void Config_GetReportSessionStartups (BOOL *pfFlag)
884 if (!Config_ReadNum (TEXT("ReportSessionStartups"), (DWORD*)pfFlag))
888 BOOL Config_SetReportSessionStartups (BOOL fFlag, ULONG *pStatus)
890 Config_WriteNum (TEXT("ReportSessionStartups"), fFlag);