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