no-more-ini-files-20040713
[openafs.git] / src / WINNT / client_config / drivemap.cpp
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 extern "C" {
11 #include <afs/param.h>
12 #include <afs/stds.h>
13 #include <rx/rxkad.h>
14 #include <afs/fs_utils.h>
15 }
16 #include <windows.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <WINNT/TaLocale.h>
20 #undef REALLOC
21 #include "drivemap.h"
22 #include <time.h>
23 #include <adssts.h>
24 #define DEBUG_VERBOSE
25 #include <osilog.h>
26 #include <lanahelper.h>
27
28 extern void Config_GetLanAdapter (ULONG *pnLanAdapter);
29
30 /*
31  * REGISTRY ___________________________________________________________________
32  *
33  */
34
35 #undef AFSConfigKeyName
36 const TCHAR sAFSConfigKeyName[] = TEXT("SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters");
37
38
39 /*
40  * PROFILE SECTIONS ___________________________________________________________
41  *
42  */
43
44 #define cREALLOC_SUBMOUNTS   4
45
46 static TCHAR cszSECTION_SUBMOUNTS[] = TEXT("SOFTWARE\\OpenAFS\\Client\\Submounts");
47 static TCHAR cszSECTION_MAPPINGS[] = TEXT("SOFTWARE\\OpenAFS\\Client\\Mappings");
48 static TCHAR cszSECTION_ACTIVE[] = TEXT("SOFTWARE\\OpenAFS\\Client\\Active Maps");
49
50 static TCHAR cszAUTOSUBMOUNT[] = TEXT("Auto");
51 static TCHAR cszLANMANDEVICE[] = TEXT("\\Device\\LanmanRedirector\\");
52
53
54 static BOOL 
55 WriteRegistryString(HKEY key, TCHAR * subkey, LPTSTR lhs, LPTSTR rhs)
56 {
57     HKEY hkSub = NULL;
58     RegCreateKeyEx( key,
59                     subkey,
60                     0,
61                     NULL,
62                     REG_OPTION_NON_VOLATILE,
63                     KEY_WRITE,
64                     NULL,
65                     &hkSub,
66                     NULL);
67
68     DWORD status = RegSetValueEx( hkSub, lhs, 0, REG_SZ, (const BYTE *)rhs, strlen(rhs)+1 );
69
70     if ( hkSub )
71         RegCloseKey( hkSub );
72
73     return (status == ERROR_SUCCESS);
74 }
75
76 static BOOL 
77 ReadRegistryString(HKEY key, TCHAR * subkey, LPTSTR lhs, LPTSTR rhs, DWORD * size)
78 {
79     HKEY hkSub = NULL;
80     RegCreateKeyEx( key,
81                     subkey,
82                     0,
83                     NULL,
84                     REG_OPTION_NON_VOLATILE,
85                     KEY_READ,
86                     NULL,
87                     &hkSub,
88                     NULL);
89
90     DWORD dwType;
91     DWORD status = RegQueryValueEx( hkSub, lhs, 0, &dwType, (LPBYTE)rhs, size );
92
93     if ( hkSub )
94         RegCloseKey( hkSub );
95
96     return (status == ERROR_SUCCESS);
97 }
98
99 static BOOL 
100 DeleteRegistryString(HKEY key, TCHAR * subkey, LPTSTR lhs)
101 {
102     HKEY hkSub = NULL;
103     RegCreateKeyEx( key,
104                     subkey,
105                     0,
106                     NULL,
107                     REG_OPTION_NON_VOLATILE,
108                     KEY_READ,
109                     NULL,
110                     &hkSub,
111                     NULL);
112
113     DWORD dwType;
114     DWORD status = RegDeleteValue( hkSub, lhs );
115
116     if ( hkSub )
117         RegCloseKey( hkSub );
118
119     return (status == ERROR_SUCCESS);
120 }
121
122 /*
123  * STRINGS ____________________________________________________________________
124  *
125  */
126
127 static LPTSTR AllocateStringMemory (size_t cch)
128 {
129    LPTSTR psz = (LPTSTR)Allocate (sizeof(TCHAR) * (cch+1));
130    memset (psz, 0x00, sizeof(TCHAR) * (cch+1));
131    return psz;
132 }
133
134 static void FreeStringMemory (LPTSTR pszString)
135 {
136    Free (pszString);
137 }
138
139 static int lstrncmpi (LPCTSTR pszA, LPCTSTR pszB, size_t cch)
140 {
141    if (!pszA || !pszB)
142       {
143       return (!pszB) - (!pszA);   // A,!B:1, !A,B:-1, !A,!B:0
144       }
145
146    for ( ; cch > 0; cch--, pszA = CharNext(pszA), pszB = CharNext(pszB))
147       {
148       TCHAR chA = toupper( *pszA );
149       TCHAR chB = toupper( *pszB );
150
151       if (!chA || !chB)
152          return (!chB) - (!chA);    // A,!B:1, !A,B:-1, !A,!B:0
153
154       if (chA != chB)
155          return (int)(chA) - (int)(chB);   // -1:A<B, 0:A==B, 1:A>B
156       }
157
158    return 0;  // no differences before told to stop comparing, so A==B
159 }
160
161
162 /*
163  * REALLOC ____________________________________________________________________
164  *
165  */
166
167 #ifndef REALLOC
168 #define REALLOC(_a,_c,_r,_i) DriveMapReallocFunction ((LPVOID*)&_a,sizeof(*_a),&_c,_r,_i)
169 BOOL DriveMapReallocFunction (LPVOID *ppTarget, size_t cbElement, size_t *pcTarget, size_t cReq, size_t cInc)
170 {
171    LPVOID pNew;
172    size_t cNew;
173
174    if (cReq <= *pcTarget)
175       return TRUE;
176
177    if ((cNew = cInc * ((cReq + cInc-1) / cInc)) <= 0)
178       return FALSE;
179
180    if ((pNew = Allocate (cbElement * cNew)) == NULL)
181       return FALSE;
182    memset (pNew, 0x00, cbElement * cNew);
183
184    if (*pcTarget != 0)
185    {
186       memcpy (pNew, *ppTarget, cbElement * (*pcTarget));
187       Free (*ppTarget);
188    }
189
190    *ppTarget = pNew;
191    *pcTarget = cNew;
192    return TRUE;
193 }
194 #endif
195
196
197 /*
198  * WINDOWS NT STUFF ___________________________________________________________
199  *
200  */
201
202 static BOOL IsWindowsNT (void)
203 {
204    static BOOL fChecked = FALSE;
205    static BOOL fIsWinNT = FALSE;
206
207    if (!fChecked)
208       {
209       fChecked = TRUE;
210
211       OSVERSIONINFO Version;
212       memset (&Version, 0x00, sizeof(Version));
213       Version.dwOSVersionInfoSize = sizeof(Version);
214
215       if (GetVersionEx (&Version))
216          {
217          if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT)
218             fIsWinNT = TRUE;
219          }
220       }
221
222    return fIsWinNT;
223 }
224
225 /* Check if the OS is Windows 2000 or higher.
226 */
227 BOOL IsWindows2000 (void)
228 {
229    static BOOL fChecked = FALSE;
230    static BOOL fIsWin2K = FALSE;
231
232    if (!fChecked)
233       {
234       fChecked = TRUE;
235
236       OSVERSIONINFO Version;
237       memset (&Version, 0x00, sizeof(Version));
238       Version.dwOSVersionInfoSize = sizeof(Version);
239
240       if (GetVersionEx (&Version))
241          {
242          if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
243              Version.dwMajorVersion >= 5)
244              fIsWin2K = TRUE;
245          }
246       }
247
248    return fIsWin2K;
249 }
250
251 /*
252  * GENERAL ____________________________________________________________________
253  *
254  */
255
256 void GetClientNetbiosName (LPTSTR pszName)
257 {
258     static TCHAR szNetbiosName[32] = "";
259
260     if ( szNetbiosName[0] == 0 ) {
261         lana_GetNetbiosName(szNetbiosName, LANA_NETBIOS_NAME_FULL);
262     }
263     _tcscpy(pszName, szNetbiosName);
264 }
265
266
267 BOOL SubmountToPath (PDRIVEMAPLIST pList, LPTSTR pszPath, LPTSTR pszSubmount, BOOL fMarkInUse)
268 {
269    // We can't do this translation unless we're under Windows NT.
270    //
271    if (!IsWindowsNT())
272       return FALSE;
273
274    // \\computer-afs\all always maps to "/afs"
275    //
276    if (!lstrcmpi (pszSubmount, TEXT("all")))
277       {
278       lstrcpy (pszPath, cm_slash_mount_root);
279       return TRUE;
280       }
281
282    // Otherwise, look up our list of submounts.
283    //
284    for (size_t ii = 0; ii < pList->cSubmounts; ++ii)
285       {
286       if (!lstrcmpi (pList->aSubmounts[ii].szSubmount, pszSubmount))
287          {
288          if (fMarkInUse)
289             pList->aSubmounts[ii].fInUse = TRUE;
290          AdjustAfsPath (pszPath, pList->aSubmounts[ii].szMapping, TRUE, TRUE);
291          return TRUE;
292          }
293       }
294
295    return FALSE;
296 }
297
298
299 BOOL IsValidSubmountName (LPTSTR pszSubmount)
300 {
301    if (!*pszSubmount)
302       return FALSE;
303    if (lstrlen (pszSubmount) > 12)
304       return FALSE;
305
306    for ( ; *pszSubmount; ++pszSubmount)
307       {
308       if (!isprint(*pszSubmount))
309          return FALSE;
310       if (*pszSubmount == TEXT(' '))
311          return FALSE;
312       if (*pszSubmount == TEXT('\t'))
313          return FALSE;
314       }
315
316    return TRUE;
317 }
318
319
320 /*
321  * PIOCTL SUPPORT _____________________________________________________________
322  *
323  */
324
325 extern "C" {
326
327 #include "../afsd/fs_utils.h"
328
329 #define __CM_CONFIG_INTERFACES_ONLY__
330 #include "../afsd/cm_config.h"
331
332 #define __CM_IOCTL_INTERFACES_ONLY__
333 #include "../afsd/cm_ioctl.h"
334
335 } // extern "C"
336
337 #define PIOCTL_MAXSIZE     2048
338
339
340 BOOL fCanIssuePIOCTL (void)
341 {
342    if (!IsWindowsNT())
343       {
344       TCHAR szGateway[ 256 ] = TEXT("");
345       GetClientNetbiosName (szGateway);
346       return (szGateway[0]) ? TRUE : FALSE;
347       }
348
349    SERVICE_STATUS Status;
350    memset (&Status, 0x00, sizeof(Status));
351    Status.dwCurrentState = SERVICE_STOPPED;
352
353    SC_HANDLE hManager;
354    if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
355       {
356       SC_HANDLE hService;
357       if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
358          {
359          QueryServiceStatus (hService, &Status);
360          CloseServiceHandle (hService);
361          }
362
363       CloseServiceHandle (hManager);
364       }
365
366    return (Status.dwCurrentState == SERVICE_RUNNING) ? TRUE : FALSE;
367 }
368
369
370 /*
371  * QUERYDRIVEMAPLIST __________________________________________________________
372  *
373  */
374
375 void QueryDriveMapList_ReadSubmounts (PDRIVEMAPLIST pList)
376 {
377     if (IsWindowsNT())
378     {
379         HKEY hkSubmounts;
380
381         RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
382                         "SOFTWARE\\OpenAFS\\Client\\Submounts",
383                         0, 
384                         "AFS", 
385                         REG_OPTION_NON_VOLATILE,
386                         KEY_READ|KEY_QUERY_VALUE,
387                         NULL, 
388                         &hkSubmounts,
389                         NULL );
390
391         DWORD dwSubmounts;
392         RegQueryInfoKey( hkSubmounts,
393                          NULL,  /* lpClass */
394                          NULL,  /* lpcClass */
395                          NULL,  /* lpReserved */
396                          NULL,  /* lpcSubKeys */
397                          NULL,  /* lpcMaxSubKeyLen */
398                          NULL,  /* lpcMaxClassLen */
399                          &dwSubmounts, /* lpcValues */
400                          NULL,  /* lpcMaxValueNameLen */
401                          NULL,  /* lpcMaxValueLen */
402                          NULL,  /* lpcbSecurityDescriptor */
403                          NULL   /* lpftLastWriteTime */
404                          );
405
406         for ( DWORD dwIndex = 0; dwIndex < dwSubmounts; dwIndex ++ ) {
407             TCHAR submountPath[MAX_PATH] = "";
408             DWORD submountPathLen = MAX_PATH;
409             TCHAR submountName[MAX_PATH];
410             DWORD submountNameLen = MAX_PATH;
411             DWORD dwType;
412
413             RegEnumValue( hkSubmounts, dwIndex, submountName, &submountNameLen, NULL,
414                           &dwType, (LPBYTE)submountPath, &submountPathLen);
415
416             SUBMOUNT Submount;
417             memset (&Submount, 0x00, sizeof(SUBMOUNT));
418             lstrcpy (Submount.szSubmount, submountName);
419
420             if ( submountPath[0] != TEXT('\0') ) {
421                 AdjustAfsPath (Submount.szMapping, submountPath, FALSE, TRUE);
422
423                 for (size_t ii = 0; ii < pList->cSubmounts; ++ii)
424                 {
425                     if (!pList->aSubmounts[ii].szSubmount[0])
426                         break;
427                 }
428                 if (REALLOC (pList->aSubmounts, pList->cSubmounts, 1+ii, cREALLOC_SUBMOUNTS))
429                 {
430                     memcpy (&pList->aSubmounts[ii], &Submount, sizeof(SUBMOUNT));
431                 }
432             }
433
434         }
435         RegCloseKey(hkSubmounts);
436     }
437 }
438
439
440 void QueryDriveMapList_ReadMappings (PDRIVEMAPLIST pList)
441 {
442     HKEY hkMappings;
443     RegCreateKeyEx( HKEY_CURRENT_USER,
444                     "SOFTWARE\\OpenAFS\\Client\\Mappings",
445                     0, 
446                     "AFS", 
447                     REG_OPTION_NON_VOLATILE,
448                     KEY_READ|KEY_QUERY_VALUE,
449                     NULL, 
450                     &hkMappings,
451                     NULL );
452
453     DWORD dwMappings;
454     RegQueryInfoKey( hkMappings,
455                      NULL,  /* lpClass */
456                      NULL,  /* lpcClass */
457                      NULL,  /* lpReserved */
458                      NULL,  /* lpcSubKeys */
459                      NULL,  /* lpcMaxSubKeyLen */
460                      NULL,  /* lpcMaxClassLen */
461                      &dwMappings, /* lpcValues */
462                      NULL,  /* lpcMaxValueNameLen */
463                      NULL,  /* lpcMaxValueLen */
464                      NULL,  /* lpcbSecurityDescriptor */
465                      NULL   /* lpftLastWriteTime */
466                      );
467
468     for ( DWORD dwIndex = 0; dwIndex < dwMappings; dwIndex ++ ) {
469         TCHAR mapping[MAX_PATH] = "";
470         DWORD mappingLen = MAX_PATH;
471         TCHAR drive[MAX_PATH];
472         DWORD driveLen = MAX_PATH;
473         DWORD dwType;
474
475         RegEnumValue( hkMappings, dwIndex, drive, &driveLen, NULL,
476                       &dwType, (LPBYTE)mapping, &mappingLen);
477
478        DRIVEMAP DriveMap;
479        memset (&DriveMap, 0x00, sizeof(DRIVEMAP));
480        DriveMap.chDrive = toupper(*drive);
481        DriveMap.fPersistent = TRUE;
482        if ((DriveMap.chDrive < chDRIVE_A) || (DriveMap.chDrive > chDRIVE_Z))
483            continue;
484
485        if (mapping[0] != TEXT('\0'))
486        {
487            AdjustAfsPath (DriveMap.szMapping, mapping, TRUE, TRUE);
488            if (DriveMap.szMapping[ lstrlen(DriveMap.szMapping)-1 ] == TEXT('*'))
489            {
490                DriveMap.fPersistent = FALSE;
491                DriveMap.szMapping[ lstrlen(DriveMap.szMapping)-1 ] = TEXT('\0');
492            }
493            size_t iDrive = DriveMap.chDrive - chDRIVE_A;
494            memcpy (&pList->aDriveMap[ iDrive ], &DriveMap, sizeof(DRIVEMAP));
495        }
496     }
497
498     RegCloseKey(hkMappings);
499 }
500
501 BOOL ForceMapActive (TCHAR chDrive)
502 {
503     TCHAR szDrive[2];
504     TCHAR szActive[32];
505
506     szDrive[0] = chDrive;
507     szDrive[1] = 0;
508
509     DWORD len = sizeof(szActive);
510     ReadRegistryString( HKEY_CURRENT_USER, cszSECTION_ACTIVE, szDrive, szActive, &len);
511
512     if ( !lstrcmp(szActive,"1") || !lstrcmpi(szActive,"true") || !lstrcmpi(szActive,"on") || !lstrcmpi(szActive,"yes") )
513         return TRUE;
514     return FALSE;
515 }
516
517
518 void WriteActiveMap (TCHAR chDrive, BOOL on)
519 {
520     TCHAR szDrive[2];
521
522     szDrive[0] = chDrive;
523     szDrive[1] = 0;
524
525     WriteRegistryString(HKEY_CURRENT_USER, cszSECTION_ACTIVE, szDrive, on ? "1" : "0");
526 }
527
528 void QueryDriveMapList_WriteMappings (PDRIVEMAPLIST pList)
529 {
530     WriteDriveMappings (pList);
531 }
532
533
534 void WriteDriveMappings (PDRIVEMAPLIST pList)
535 {
536     HKEY hkMappings;
537     RegCreateKeyEx( HKEY_CURRENT_USER, 
538                     "SOFTWARE\\OpenAFS\\Client\\Mappings",
539                     0, 
540                     "AFS", 
541                     REG_OPTION_NON_VOLATILE,
542                     KEY_READ|KEY_QUERY_VALUE|KEY_WRITE,
543                     NULL, 
544                     &hkMappings,
545                     NULL );
546
547     DWORD dwMappings;
548     RegQueryInfoKey( hkMappings,
549                      NULL,  /* lpClass */
550                      NULL,  /* lpcClass */
551                      NULL,  /* lpReserved */
552                      NULL,  /* lpcSubKeys */
553                      NULL,  /* lpcMaxSubKeyLen */
554                      NULL,  /* lpcMaxClassLen */
555                      &dwMappings, /* lpcValues */
556                      NULL,  /* lpcMaxValueNameLen */
557                      NULL,  /* lpcMaxValueLen */
558                      NULL,  /* lpcbSecurityDescriptor */
559                      NULL   /* lpftLastWriteTime */
560                      );
561
562     if ( dwMappings > 0 ) {
563         for ( long dwIndex = dwMappings - 1; dwIndex >= 0; dwIndex-- ) {
564             TCHAR drive[MAX_PATH];
565             DWORD driveLen = MAX_PATH;
566
567             RegEnumValue( hkMappings, dwIndex, drive, &driveLen, NULL, NULL, NULL, NULL);
568             RegDeleteValue( hkMappings, drive );
569         }
570     }
571
572    for (size_t iDrive = 0; iDrive < 26; ++iDrive)
573    {
574        if (pList->aDriveMap[iDrive].szMapping[0] != TEXT('\0'))
575        {
576            TCHAR szLHS[] = TEXT("*");
577            szLHS[0] = pList->aDriveMap[iDrive].chDrive;
578
579            TCHAR szRHS[MAX_PATH];
580            AdjustAfsPath (szRHS, pList->aDriveMap[iDrive].szMapping, TRUE, TRUE);
581            if (!pList->aDriveMap[iDrive].fPersistent)
582                lstrcat (szRHS, TEXT("*"));
583
584            RegSetValueEx( hkMappings, szLHS, 0, REG_SZ, (const BYTE *)szRHS, lstrlen(szRHS) + 1);
585        }
586    }
587    RegCloseKey( hkMappings );
588 }
589
590 BOOL DriveIsGlobalAfsDrive(TCHAR chDrive)
591 {
592    TCHAR szKeyName[128];
593    TCHAR szValueName[128];
594    TCHAR szValue[128];
595    HKEY hKey;
596
597    _stprintf(szKeyName, TEXT("%s\\GlobalAutoMapper"), sAFSConfigKeyName);
598
599    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
600       return FALSE;
601
602    _stprintf(szValueName, TEXT("%c:"), chDrive);
603
604    DWORD dwSize = sizeof(szValue);
605    BOOL bIsGlobal = (RegQueryValueEx (hKey, szValueName, NULL, NULL, (PBYTE)szValue, &dwSize) == ERROR_SUCCESS);
606
607    RegCloseKey (hKey);
608    
609    return bIsGlobal;
610 }
611
612
613 void QueryDriveMapList_FindNetworkDrives (PDRIVEMAPLIST pList, BOOL *pfFoundNew)
614 {
615    for (TCHAR chDrive = chDRIVE_A; chDrive <= chDRIVE_Z; ++chDrive)
616       {
617       TCHAR szSubmount[ MAX_PATH ];
618       if (!GetDriveSubmount (chDrive, szSubmount))
619          continue;
620
621       // We've got a mapping!  Drive {chDrive} is mapped to submount
622       // {szSubmount}. See if that submount makes sense.
623       //
624       if (!IsWindowsNT())
625          {
626          size_t iDrive = chDrive - chDRIVE_A;
627          if (pList->aDriveMap[ iDrive ].szMapping[0] != TEXT('\0'))
628             {
629             pList->aDriveMap[ iDrive ].fActive = TRUE;
630             lstrcpy (pList->aDriveMap[ iDrive ].szSubmount, szSubmount);
631             }
632          continue;
633          }
634       else // (IsWindowsNT())
635          {
636          TCHAR szAfsPath[ MAX_PATH ];
637          if (!SubmountToPath (pList, szAfsPath, szSubmount, TRUE))
638             continue;
639
640          // Okay, we know that drive {chDrive} is mapped to afs path {szAfsPath}.
641          // If this drive is a global afs drive, then reject it.  Otherwise, look 
642          // at pList->aDriveMap, to see if this drive mapping is already in our 
643          // list. If not, add it and set pfFoundNew.
644          //
645          if (DriveIsGlobalAfsDrive(chDrive))
646             continue;
647          
648          size_t iDrive = chDrive - chDRIVE_A;
649          if (lstrcmpi (pList->aDriveMap[ iDrive ].szMapping, szAfsPath))
650             {
651             *pfFoundNew = TRUE;
652             pList->aDriveMap[ iDrive ].fPersistent = TRUE;
653             }
654          pList->aDriveMap[ iDrive ].fActive = TRUE;
655          pList->aDriveMap[ iDrive ].chDrive = chDrive;
656          lstrcpy (pList->aDriveMap[ iDrive ].szSubmount, szSubmount);
657          AdjustAfsPath (pList->aDriveMap[ iDrive ].szMapping, szAfsPath, TRUE, TRUE);
658          }
659       }
660 }
661
662
663 void QueryDriveMapList (PDRIVEMAPLIST pList)
664 {
665    // Initialize the data structure
666    //
667    memset (pList, 0x00, sizeof(DRIVEMAPLIST));
668    for (size_t ii = 0; ii < 26; ++ii)
669       pList->aDriveMap[ii].chDrive = chDRIVE_A + ii;
670
671    // Read the current lists of submounts and drive letter mappings
672    //
673    QueryDriveMapList_ReadSubmounts (pList);
674    QueryDriveMapList_ReadMappings (pList);
675
676    // Look through the current list of network drives, and see if
677    // any are currently mapped to AFS. If we find any which are mapped
678    // into AFS unexpectedly, we'll have to rewrite the mappings list.
679    //
680    BOOL fFoundNew = FALSE;
681    QueryDriveMapList_FindNetworkDrives (pList, &fFoundNew);
682
683    if (fFoundNew)
684       {
685       QueryDriveMapList_WriteMappings (pList);
686       }
687 }
688
689
690 void FreeDriveMapList (PDRIVEMAPLIST pList)
691 {
692    if (pList->aSubmounts)
693       Free (pList->aSubmounts);
694    memset (pList, 0x00, sizeof(DRIVEMAPLIST));
695 }
696
697
698 BOOL PathToSubmount (LPTSTR pszSubmount, LPTSTR pszMapping, LPTSTR pszSubmountReq, ULONG *pStatus)
699 {
700    if (pszSubmountReq && !IsValidSubmountName (pszSubmountReq))
701       pszSubmountReq = NULL;
702
703    TCHAR szAfsPath[ MAX_PATH ];
704    AdjustAfsPath (szAfsPath, pszMapping, TRUE, TRUE);
705
706    // Try to ask AFSD for a new submount name.
707    //
708    if (!fCanIssuePIOCTL())
709       return FALSE;
710
711    BYTE InData[ PIOCTL_MAXSIZE ];
712    memset (InData, 0x00, sizeof(InData));
713
714    LPTSTR pszInData = (LPTSTR)InData;
715    lstrcpy (pszInData, pszMapping);
716    pszInData += 1+lstrlen(pszInData);
717    if (pszSubmountReq)
718       lstrcpy (pszInData, pszSubmountReq);
719
720    BYTE OutData[ PIOCTL_MAXSIZE ];
721    memset (OutData, 0x00, sizeof(OutData));
722
723    struct ViceIoctl IOInfo;
724    IOInfo.in = (char *)InData;
725    IOInfo.in_size = PIOCTL_MAXSIZE;
726    IOInfo.out = (char *)OutData;
727    IOInfo.out_size = PIOCTL_MAXSIZE;
728
729    ULONG status = pioctl (0, VIOC_MAKESUBMOUNT, &IOInfo, 1);
730    if (pStatus)
731        *pStatus = status;
732
733    if (status)
734       return FALSE;
735
736    lstrcpy (pszSubmount, (LPCTSTR)OutData);
737    return (pszSubmount[0] != TEXT('\0')) ? TRUE : FALSE;
738 }
739
740
741 BOOL ActivateDriveMap (TCHAR chDrive, LPTSTR pszMapping, LPTSTR pszSubmountReq, BOOL fPersistent, DWORD *pdwStatus)
742 {
743    // We can only map drives to places in AFS using this function.
744    //
745    if ( (lstrncmpi (pszMapping, cm_slash_mount_root, lstrlen(cm_slash_mount_root))) &&
746         (lstrncmpi (pszMapping, cm_back_slash_mount_root, lstrlen(cm_back_slash_mount_root))) )
747       {
748       if (pdwStatus)
749          *pdwStatus = ERROR_BAD_NETPATH;
750       return FALSE;
751       }
752
753    // First we have to translate {pszMapping} into a submount, and if there is
754    // no current submount associated with this path, we'll have to make one.
755    //
756    ULONG status;
757    TCHAR szSubmount[ MAX_PATH ];
758    if (!PathToSubmount (szSubmount, pszMapping, pszSubmountReq, &status))
759       {
760       if (pdwStatus)
761          *pdwStatus = status;
762       return FALSE;
763       }
764
765    // We now have a submount name and drive letter--map the network drive.
766    DWORD rc=MountDOSDrive(chDrive,szSubmount,fPersistent,NULL);
767    if (rc == NO_ERROR)
768       return TRUE;
769
770    if (pdwStatus)
771       *pdwStatus = rc;
772    return FALSE;
773 }
774
775
776 BOOL InactivateDriveMap (TCHAR chDrive, DWORD *pdwStatus)
777 {
778     DWORD rc = DisMountDOSDrive(chDrive, FALSE);
779     if (rc == NO_ERROR)
780         return TRUE;
781
782     if (pdwStatus)
783         *pdwStatus = rc;
784     return FALSE;
785 }
786
787
788 void AddSubMount (LPTSTR pszSubmount, LPTSTR pszMapping)
789 {
790     TCHAR szRHS[ MAX_PATH ];
791     AdjustAfsPath (szRHS, pszMapping, FALSE, TRUE);
792     if (!szRHS[0])
793         lstrcpy (szRHS, TEXT("/"));
794
795     WriteRegistryString(HKEY_LOCAL_MACHINE, cszSECTION_SUBMOUNTS, pszSubmount, szRHS);
796 }
797
798
799 void RemoveSubMount (LPTSTR pszSubmount)
800 {
801     DeleteRegistryString(HKEY_LOCAL_MACHINE, cszSECTION_SUBMOUNTS, pszSubmount);
802 }
803
804
805 void AdjustAfsPath (LPTSTR pszTarget, LPCTSTR pszSource, BOOL fWantAFS, BOOL fWantForwardSlashes)
806 {
807     if (!*pszSource)
808         lstrcpy (pszTarget, (fWantAFS) ? cm_slash_mount_root : TEXT(""));
809     else if ((*pszSource != TEXT('/')) && (*pszSource != TEXT('\\')))
810         wsprintf (pszTarget, TEXT("%s/%s"),cm_slash_mount_root, pszSource);
811     // We don't want to strip afs off the start if it is part of something for example afscell.company.com
812     else if (fWantAFS && (lstrncmpi (&pszSource[1], cm_mount_root, strlen(cm_mount_root))) || !((pszSource[strlen(cm_slash_mount_root)] == TEXT('/')) ||
813                                                                                                  (pszSource[strlen(cm_slash_mount_root)] == TEXT('\\')) ||
814                                                                                                  (lstrlen(pszSource) == strlen(cm_slash_mount_root))))
815         wsprintf (pszTarget, TEXT("%s%s"),cm_slash_mount_root, pszSource);
816     else if (!fWantAFS && (!lstrncmpi (&pszSource[1], cm_mount_root, strlen(cm_mount_root)) && ((pszSource[strlen(cm_slash_mount_root)] == TEXT('/')) ||
817                                                                                                  (pszSource[strlen(cm_slash_mount_root)] == TEXT('\\')) ||
818                                                                                                  (lstrlen(pszSource) == strlen(cm_slash_mount_root)))))
819         lstrcpy (pszTarget, &pszSource[strlen(cm_slash_mount_root)]);
820     else
821         lstrcpy (pszTarget, pszSource);
822
823    for (LPTSTR pch = pszTarget; *pch; ++pch)
824       {
825       if (fWantForwardSlashes)
826          {
827          *pch = (*pch == TEXT('\\')) ? TEXT('/') : (*pch);
828          }
829       else // (!fWantForwardSlashes)
830          {
831          *pch = (*pch == TEXT('/')) ? TEXT('\\') : (*pch);
832          }
833       }
834
835    if (lstrlen(pszTarget) &&
836        ((pszTarget[lstrlen(pszTarget)-1] == TEXT('/')) ||
837         (pszTarget[lstrlen(pszTarget)-1] == TEXT('\\'))))
838       {
839       pszTarget[lstrlen(pszTarget)-1] = TEXT('\0');
840       }
841 }
842
843 BOOL GetDriveSubmount (TCHAR chDrive, LPTSTR pszSubmountNow)
844 {
845         BOOL isWinNT = IsWindowsNT();
846
847         TCHAR szDrive[] = TEXT("*:");
848     szDrive[0] = chDrive;
849
850     TCHAR szMapping[ _MAX_PATH ] = TEXT("");
851
852     if (isWinNT && !QueryDosDevice (szDrive, szMapping, MAX_PATH))
853            return FALSE;
854
855     LPTSTR pszSubmount = szMapping;
856     
857         TCHAR szNetBiosName[32];
858     memset(szNetBiosName, '\0', sizeof(szNetBiosName));
859     GetClientNetbiosName(szNetBiosName);
860     _tcscat(szNetBiosName, TEXT("\\"));
861
862    if (isWinNT)
863    {
864       // Now if this is an AFS network drive mapping, {szMapping} will be:
865       //
866       //   \Device\LanmanRedirector\<Drive>:\<netbiosname>\submount
867       //
868       // on Windows NT. On Windows 2000, it will be:
869       //
870       //   \Device\LanmanRedirector\;<Drive>:0\<netbiosname>\submount
871       //
872       // (This is presumably to support multiple drive mappings with
873       // Terminal Server).
874       //
875       // on Windows XP and 2003, it will be :
876       //   \Device\LanmanRedirector\;<Drive>:<AuthID>\<netbiosname>\submount
877       //
878       //   where : <Drive> : DOS drive letter
879       //           <AuthID>: Authentication ID, 16 char hex.
880       //           <netbiosname>: Netbios name of server
881       //
882       if (_tcsnicmp(szMapping, cszLANMANDEVICE, _tcslen(cszLANMANDEVICE)))
883          return FALSE;
884       pszSubmount = &szMapping[ _tcslen(cszLANMANDEVICE) ];
885
886       if (IsWindows2000())
887           {
888           if (*(pszSubmount) != TEXT(';'))
889              return FALSE;
890           } else 
891                 --pszSubmount;
892
893       if (toupper(*(++pszSubmount)) != chDrive)
894          return FALSE;
895
896       if (*(++pszSubmount) != TEXT(':'))
897          return FALSE;
898
899 #ifdef COMMENT
900        // No longer a safe assumption on XP
901       if (IsWindows2000())
902           if (*(++pszSubmount) != TEXT('0'))
903              return FALSE;
904 #endif
905
906       // scan for next "\"
907       while (*(++pszSubmount) != TEXT('\\'))
908       {
909           if (*pszSubmount==0)
910               return FALSE;
911       }
912
913        // note that szNetBiosName has a '\\' tagged in the end earlier
914       for (++pszSubmount; *pszSubmount && (*pszSubmount != TEXT('\\')); ++pszSubmount)
915          if (!_tcsncicmp(pszSubmount, szNetBiosName, _tcslen(szNetBiosName)))
916             break;
917       if ((!*pszSubmount) || (*pszSubmount == TEXT('\\')))
918          return FALSE;
919
920        pszSubmount += _tcslen(szNetBiosName);
921       }
922    else // (!IsWindowsNT())
923       {
924       DWORD dwSize = MAX_PATH;
925       if (WNetGetConnection (szDrive, szMapping, &dwSize) != NO_ERROR)
926          return FALSE;
927       if (*(pszSubmount++) != TEXT('\\'))
928          return FALSE;
929       if (*(pszSubmount++) != TEXT('\\'))
930          return FALSE;
931       for ( ; *pszSubmount && (*pszSubmount != TEXT('\\')); ++pszSubmount)
932          if (!lstrncmpi (pszSubmount, szNetBiosName, lstrlen(szNetBiosName)))
933             break;
934       if ((!*pszSubmount) || (*pszSubmount == TEXT('\\')))
935          return FALSE;
936       pszSubmount += lstrlen(szNetBiosName);
937       }
938
939    if (!pszSubmount || !*pszSubmount)
940       return FALSE;
941
942    lstrcpy (pszSubmountNow, pszSubmount);
943    return TRUE;
944 }
945
946 /* Generate Random User name random acording to time*/
947 DWORD dwOldState=0;
948 TCHAR pUserName[MAXRANDOMNAMELEN]=TEXT("");
949 BOOL fUserName=FALSE;
950 #define AFSLogonOptionName TEXT("System\\CurrentControlSet\\Services\\TransarcAFSDaemon\\NetworkProvider")
951
952 void SetBitLogonOption(BOOL set,DWORD value)
953 {
954
955    RWLogonOption(FALSE,((set)?value | RWLogonOption(TRUE,0):RWLogonOption(TRUE,0) & ~value) );  
956 }
957
958 DWORD RWLogonOption(BOOL read,DWORD value)
959 {
960         // if read is true then if value==0 return registry value
961         // if read and value!=0 then use value to test registry, return TRUE if value bits match value read
962    HKEY hk;
963    DWORD dwDisp;
964         DWORD LSPtype, LSPsize;
965         DWORD rval;
966    if (read)
967    {
968            rval=0;
969                 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSLogonOptionName, 0, KEY_QUERY_VALUE, &hk)==ERROR_SUCCESS)
970                 {
971                         LSPsize=sizeof(rval);
972                         RegQueryValueEx(hk, "LogonOptions", NULL,
973                                                 &LSPtype, (LPBYTE)&rval, &LSPsize);
974                         RegCloseKey (hk);
975                 }
976                 return (value==0)?rval:((rval & value)==value);
977
978    } else {     //write
979                 if (RegCreateKeyEx (HKEY_LOCAL_MACHINE, AFSLogonOptionName, 0, NULL, 0, KEY_SET_VALUE, NULL, &hk, &dwDisp) == ERROR_SUCCESS)
980                 {
981                         RegSetValueEx(hk,TEXT("LogonOptions"),NULL,REG_DWORD,(LPBYTE)&value,sizeof(value));
982                         RegCloseKey (hk);
983                 }
984                 return TRUE;
985    }
986 }
987
988 void MapShareName(char *pszCmdLineA)
989 {
990         fUserName = TRUE;
991         TCHAR *p=pUserName;
992         pszCmdLineA++;
993         while (*pszCmdLineA && (*pszCmdLineA != ' '))
994         {
995           *p++=*pszCmdLineA++;
996         }
997 }
998
999 void GenRandomName(TCHAR *pname,int len)
1000 {
1001         if (fUserName)
1002         {               //user name was passed through command line, use once
1003                 fUserName=FALSE;
1004                 return;
1005         }
1006         srand( (unsigned)time( NULL ) );
1007         for (int i=0;i<len;i++)
1008                 pname[i]='a'+(rand() % 26);
1009         pname[len]=0;
1010         return;
1011 }
1012
1013 /*
1014         Make a connection using users name
1015         if fUserName then force a connection
1016 */
1017
1018 BOOL TestAndDoMapShare(DWORD dwState)
1019 {
1020     if ((dwState!=SERVICE_RUNNING) || (dwOldState!=SERVICE_START_PENDING))
1021         {
1022                 dwOldState=dwState;
1023                 return TRUE;
1024         }
1025         dwOldState=SERVICE_RUNNING;
1026         if (RWLogonOption(TRUE,LOGON_OPTION_HIGHSECURITY))
1027             return (DoMapShare() && GlobalMountDrive());
1028         return GlobalMountDrive();
1029 }
1030
1031 BOOL IsServiceActive()
1032 {
1033    SC_HANDLE hManager;
1034    SERVICE_STATUS Status;
1035    if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
1036       {
1037       SC_HANDLE hService;
1038       if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
1039          {
1040          QueryServiceStatus (hService, &Status);
1041          CloseServiceHandle (hService);
1042          }
1043
1044       CloseServiceHandle (hManager);
1045       }
1046
1047    return (Status.dwCurrentState == SERVICE_RUNNING) ? TRUE : FALSE;
1048 }
1049
1050 void TestAndDoUnMapShare()
1051 {
1052         if (!RWLogonOption(TRUE,LOGON_OPTION_HIGHSECURITY))
1053                 return;
1054         DoUnMapShare(FALSE);    
1055 }
1056
1057 void DoUnMapShare(BOOL drivemap)        //disconnect drivemap 
1058 {
1059         TCHAR szMachine[MAX_PATH],szPath[MAX_PATH];
1060         DWORD rc=28;
1061         HANDLE hEnum;
1062         LPNETRESOURCE lpnrLocal,lpnr=NULL;
1063         DWORD res;
1064         DWORD cbBuffer=16384;
1065         DWORD cEntries=-1;
1066         CHAR *pSubmount="";
1067
1068     memset(szMachine, '\0', sizeof(szMachine));
1069     GetClientNetbiosName(szMachine);
1070
1071    // Initialize the data structure
1072         if ((res=WNetOpenEnum(RESOURCE_CONNECTED,RESOURCETYPE_DISK,RESOURCEUSAGE_CONNECTABLE,lpnr,&hEnum))!=NO_ERROR)
1073                 return;
1074         sprintf(szPath,"\\\\%s\\",szMachine);
1075         _strlwr(szPath);
1076         lpnrLocal=(LPNETRESOURCE) GlobalAlloc(GPTR,cbBuffer);
1077         do {
1078                 memset(lpnrLocal,0,cbBuffer);
1079                 if ((res = WNetEnumResource(hEnum,&cEntries,lpnrLocal,&cbBuffer))==NO_ERROR)
1080                 {
1081                         for (DWORD i=0;i<cEntries;i++)
1082                         {
1083                                 if (strstr(_strlwr(lpnrLocal[i].lpRemoteName),szPath))
1084                                 {
1085                                         if ((lpnrLocal[i].lpLocalName) && (strlen(lpnrLocal[i].lpLocalName)>0))
1086                                         {
1087                                                 if (drivemap) {
1088                                                     DisMountDOSDrive(*lpnrLocal[i].lpLocalName);
1089                             DEBUG_EVENT1("AFS DriveUnMap","UnMap-Local=%x",res);
1090                         }
1091                                         } else {
1092                                             DisMountDOSDriveFull(lpnrLocal[i].lpRemoteName);
1093                         DEBUG_EVENT1("AFS DriveUnMap","UnMap-Remote=%x",res);
1094                     }
1095                                 }
1096                         }
1097                 }
1098         } while (res!=ERROR_NO_MORE_ITEMS);
1099         GlobalFree((HGLOBAL)lpnrLocal);
1100         WNetCloseEnum(hEnum);
1101 }
1102
1103 BOOL DoMapShareChange()
1104 {
1105         DRIVEMAPLIST List;
1106         TCHAR szMachine[ MAX_PATH],szPath[MAX_PATH];
1107         DWORD rc=28;
1108         HANDLE hEnum;
1109         LPNETRESOURCE lpnrLocal,lpnr=NULL;
1110         DWORD res;
1111         DWORD cEntries=-1;
1112     DWORD cbBuffer=16384;
1113
1114     memset(szMachine, '\0', sizeof(szMachine));
1115     GetClientNetbiosName(szMachine);
1116
1117     // Initialize the data structure
1118         if (!IsServiceActive())
1119                 return TRUE;
1120         memset (&List, 0x00, sizeof(DRIVEMAPLIST));
1121         for (size_t ii = 0; ii < 26; ++ii)
1122                 List.aDriveMap[ii].chDrive = chDRIVE_A + ii;
1123         QueryDriveMapList_ReadSubmounts (&List);
1124         if ((res=WNetOpenEnum(RESOURCE_CONNECTED,RESOURCETYPE_DISK,RESOURCEUSAGE_CONNECTABLE,lpnr,&hEnum))!=NO_ERROR)
1125                 return FALSE;
1126         lpnrLocal=(LPNETRESOURCE) GlobalAlloc(GPTR,cbBuffer);
1127         sprintf(szPath,"\\\\%s\\",szMachine);
1128         _strlwr(szPath);
1129         do {
1130                 memset(lpnrLocal,0,cbBuffer);
1131                 if ((res = WNetEnumResource(hEnum,&cEntries,lpnrLocal,&cbBuffer))==NO_ERROR)
1132                 {
1133                         for (DWORD i=0;i<cEntries;i++)
1134                         {
1135                                 if (strstr(_strlwr(lpnrLocal[i].lpRemoteName),szPath)==NULL)
1136                                         continue;       //only look at real afs mappings
1137                                 CHAR * pSubmount=strrchr(lpnrLocal[i].lpRemoteName,'\\')+1;
1138                                 if (lstrcmpi(pSubmount,"all")==0) 
1139                                         continue;                               // do not remove 'all'
1140                                 for (DWORD j=0;j<List.cSubmounts;j++)
1141                                 {
1142                                         if (
1143                                                 (List.aSubmounts[j].szSubmount[0]) &&
1144                                                 (lstrcmpi(List.aSubmounts[j].szSubmount,pSubmount)==0)
1145                                                 ) 
1146                                         {
1147                                                 List.aSubmounts[j].fInUse=TRUE; 
1148                                                 goto nextname;
1149                                         }
1150                                 }
1151                                 // wasn't on list so lets remove
1152                                 DisMountDOSDrive(pSubmount);
1153                                 nextname:;
1154                         }
1155                 }
1156         } while (res!=ERROR_NO_MORE_ITEMS);
1157         GlobalFree((HGLOBAL)lpnrLocal);
1158         WNetCloseEnum(hEnum);
1159         sprintf(szPath,"\\\\%s\\all",szMachine);
1160
1161         // Lets connect all submounts that weren't connectd
1162     DWORD cbUser=MAXRANDOMNAMELEN-1;
1163         CHAR szUser[MAXRANDOMNAMELEN];
1164     CHAR * pUser = NULL;
1165         if (WNetGetUser(szPath,(LPSTR)szUser,&cbUser)!=NO_ERROR) {
1166         if (RWLogonOption(TRUE,LOGON_OPTION_HIGHSECURITY)) {
1167             if (!pUserName[0]) {
1168                 GenRandomName(szUser,MAXRANDOMNAMELEN-1);
1169                 pUser = szUser;
1170             } else {
1171                 pUser = pUserName;
1172             }
1173         }
1174     } else {
1175                 if ((pUser=strchr(szUser,'\\'))!=NULL)
1176             pUser++;
1177         }
1178
1179     for (DWORD j=0;j<List.cSubmounts;j++)
1180         {
1181                 if (List.aSubmounts[j].fInUse)
1182                         continue;
1183                 DWORD res=MountDOSDrive(0,List.aSubmounts[j].szSubmount,FALSE,pUser);
1184         }
1185         return TRUE;
1186 }
1187
1188 BOOL DoMapShare()
1189 {
1190         DRIVEMAPLIST List;
1191         DWORD rc=28;
1192         BOOL bMappedAll=FALSE;
1193
1194    // Initialize the data structure
1195         DEBUG_EVENT0("AFS DoMapShare");
1196         QueryDriveMapList (&List);
1197         DoUnMapShare(TRUE);
1198         // All connections have been removed
1199         // Lets restore them after making the connection from the random name
1200
1201         TCHAR szMachine[ MAX_PATH],szPath[MAX_PATH];
1202     memset(szMachine, '\0', sizeof(szMachine));
1203     GetClientNetbiosName(szMachine);
1204     sprintf(szPath,"\\\\%s\\all",szMachine);
1205
1206     // Lets connect all submounts that weren't connectd
1207     DWORD cbUser=MAXRANDOMNAMELEN-1;
1208         CHAR szUser[MAXRANDOMNAMELEN];
1209     CHAR * pUser = NULL;
1210         if (WNetGetUser(szPath,(LPSTR)szUser,&cbUser)!=NO_ERROR) {
1211         if (RWLogonOption(TRUE,LOGON_OPTION_HIGHSECURITY)) {
1212             if (!pUserName[0]) {
1213                 GenRandomName(szUser,MAXRANDOMNAMELEN-1);
1214                 pUser = szUser;
1215             } else {
1216                 pUser = pUserName;
1217             }
1218         }
1219     } else {
1220                 if ((pUser=strchr(szUser,'\\'))!=NULL)
1221             pUser++;
1222         }
1223
1224         for (DWORD i=0;i<List.cSubmounts;i++)
1225         {
1226                 if (List.aSubmounts[i].szSubmount[0])
1227                 {
1228                         DWORD res=MountDOSDrive(0,List.aSubmounts[i].szSubmount,FALSE,pUser);
1229                         if (lstrcmpi("all",List.aSubmounts[i].szSubmount)==0)
1230                                 bMappedAll=TRUE;
1231                 }
1232         }
1233         if (!bMappedAll)        //make sure all is mapped also
1234         {
1235         DWORD res=MountDOSDrive(0,"all",FALSE,pUser);
1236         if (res==ERROR_SESSION_CREDENTIAL_CONFLICT)
1237         {
1238             DisMountDOSDrive("all");
1239             MountDOSDrive(0,"all",FALSE,pUser);
1240         }
1241         }
1242         for (TCHAR chDrive = chDRIVE_A; chDrive <= chDRIVE_Z; ++chDrive)
1243         {
1244                 if (List.aDriveMap[chDrive-chDRIVE_A].fActive ||
1245             ForceMapActive(chDrive))
1246                 {
1247             TCHAR szSubmount[ MAX_PATH ];
1248             if (List.aDriveMap[chDrive-chDRIVE_A].szSubmount[0])
1249                 lstrcpy(szSubmount,List.aDriveMap[chDrive-chDRIVE_A].szSubmount);
1250             else if (!PathToSubmount (szSubmount, List.aDriveMap[chDrive-chDRIVE_A].szMapping, NULL, NULL))
1251                 continue;
1252
1253             BOOL fPersistent = List.aDriveMap[chDrive-chDRIVE_A].fPersistent;
1254             if (RWLogonOption(TRUE,LOGON_OPTION_HIGHSECURITY))
1255                 fPersistent = FALSE;
1256                     DWORD res=MountDOSDrive(chDrive
1257                                             ,szSubmount
1258                                             ,fPersistent,pUser);
1259                 }
1260         }
1261         return TRUE;
1262 }
1263
1264 BOOL GlobalMountDrive()
1265 {
1266     char szDriveToMapTo[5];
1267     DWORD dwResult;
1268     char szKeyName[256];
1269     HKEY hKey;
1270     DWORD dwIndex = 0;
1271     DWORD dwDriveSize;
1272     DWORD dwSubMountSize;
1273     char unsigned szSubMount[256];
1274     char cm_HostName[200];
1275     DWORD dwType=sizeof(cm_HostName);
1276     if (!IsServiceActive())
1277         return TRUE;
1278     if (!GetComputerName(cm_HostName, &dwType))
1279         return TRUE;
1280     sprintf(szKeyName, "%s\\GlobalAutoMapper", sAFSConfigKeyName);
1281     
1282     dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE,
1283                             &hKey);
1284     if (dwResult != ERROR_SUCCESS)
1285         return TRUE;
1286     
1287     while (1) {
1288         dwDriveSize = sizeof(szDriveToMapTo);
1289         dwSubMountSize = sizeof(szSubMount);
1290         dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 
1291                                 0, &dwType, szSubMount, &dwSubMountSize);
1292         if (dwResult != ERROR_MORE_DATA) {
1293             if (dwResult != ERROR_SUCCESS) {
1294                 if (dwResult != ERROR_NO_MORE_ITEMS)
1295                 {
1296                     DEBUG_EVENT1("AFS DriveMap","Failed to read GlobalAutoMapper values: %d",dwResult);
1297                 }
1298                 break;
1299             }
1300         }
1301         dwResult=MountDOSDrive(*szDriveToMapTo,(const char *)szSubMount,FALSE,NULL);
1302     }
1303     RegCloseKey(hKey);
1304     return TRUE;
1305 }
1306
1307 DWORD MountDOSDrive(char chDrive,const char *szSubmount,BOOL bPersistent,const char * pUsername)
1308 {
1309     TCHAR szPath[MAX_PATH];
1310     TCHAR szClient[MAX_PATH];
1311     TCHAR szDrive[3] = TEXT("?:");
1312     sprintf(szDrive,"%c:",chDrive);
1313     GetClientNetbiosName (szClient);
1314     sprintf(szPath,"\\\\%s\\%s",szClient,szSubmount);
1315     NETRESOURCE nr;
1316     memset (&nr, 0x00, sizeof(NETRESOURCE));
1317     nr.dwType=RESOURCETYPE_DISK;
1318     nr.lpLocalName=szDrive;
1319     nr.lpRemoteName=szPath;
1320     nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
1321     DWORD res=WNetAddConnection2(&nr,NULL,pUsername,(bPersistent)?CONNECT_UPDATE_PROFILE:0);
1322     DEBUG_EVENT5("AFS DriveMap","Mount %s Local[%s] Remote[%s] User[%s]=%x",
1323                   (bPersistent)?"Persistant" : "NonPresistant",
1324                   szDrive,szPath,pUsername?pUsername:"NULL",res);
1325     return res;
1326 }
1327
1328 DWORD DisMountDOSDriveFull(const char *szPath,BOOL bForce)
1329 {
1330     DWORD res=WNetCancelConnection(szPath,bForce);
1331     DEBUG_EVENT3("AFS DriveMap","%sDismount Remote[%s]=%x",
1332                   bForce ? "Forced " : "",szPath,res);
1333     return (res==ERROR_NOT_CONNECTED)?NO_ERROR:res;
1334 }
1335
1336 DWORD DisMountDOSDrive(const char *pSubmount,BOOL bForce)
1337 {
1338     TCHAR szPath[MAX_PATH];
1339     TCHAR szClient[MAX_PATH];
1340     GetClientNetbiosName (szClient);
1341     sprintf(szPath,"\\\\%s\\%s",szClient,pSubmount);
1342     return DisMountDOSDriveFull(szPath,bForce);
1343 }
1344
1345
1346 DWORD DisMountDOSDrive(const char chDrive,BOOL bForce)
1347 {
1348     TCHAR szPath[MAX_PATH];
1349     sprintf(szPath,"%c:",chDrive);
1350     return DisMountDOSDriveFull(szPath,bForce);
1351 }