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