86fc0ae25243a6e524a1e2e756f296c08924a757
[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     TCHAR szDrive[] = TEXT("*:");
702     szDrive[0] = chDrive;
703
704     TCHAR szMapping[ _MAX_PATH ] = TEXT("");
705     LPTSTR pszSubmount = szMapping;
706     TCHAR szNetBiosName[32];
707
708     memset(szNetBiosName, '\0', sizeof(szNetBiosName));
709     lana_GetNetbiosName(szNetBiosName, LANA_NETBIOS_NAME_FULL);
710     _tcscat(szNetBiosName, TEXT("\\"));
711
712    if (IsWindowsNT())
713    {
714        if (!QueryDosDevice (szDrive, szMapping, MAX_PATH))
715            return FALSE;
716
717       // Now if this is an AFS network drive mapping, {szMapping} will be:
718       //
719       //   \Device\LanmanRedirector\<Drive>:\<netbiosname>\submount
720       //
721       // on Windows NT. On Windows 2000, it will be:
722       //
723       //   \Device\LanmanRedirector\;<Drive>:0\<netbiosname>\submount
724       //
725       // (This is presumably to support multiple drive mappings with
726       // Terminal Server).
727       //
728       // on Windows XP and 2003, it will be :
729       //   \Device\LanmanRedirector\;<Drive>:<AuthID>\<netbiosname>\submount
730       //
731       //   where : <Drive> : DOS drive letter
732       //           <AuthID>: Authentication ID, 16 char hex.
733       //           <netbiosname>: Netbios name of server
734       //
735       if (_tcsnicmp(szMapping, cszLANMANDEVICE, _tcslen(cszLANMANDEVICE)))
736          return FALSE;
737       pszSubmount = &szMapping[ _tcslen(cszLANMANDEVICE) ];
738
739       if (IsWindows2000())
740           {
741           if (*(pszSubmount) != TEXT(';'))
742              return FALSE;
743           } else 
744                 --pszSubmount;
745
746       if (toupper(*(++pszSubmount)) != chDrive)
747          return FALSE;
748
749       if (*(++pszSubmount) != TEXT(':'))
750          return FALSE;
751
752 #ifdef COMMENT
753        // No longer a safe assumption on XP
754       if (IsWindows2000())
755           if (*(++pszSubmount) != TEXT('0'))
756              return FALSE;
757 #endif
758
759       // scan for next "\"
760       while (*(++pszSubmount) != TEXT('\\'))
761       {
762           if (*pszSubmount==0)
763               return FALSE;
764       }
765
766        // note that szNetBiosName has a '\\' tagged in the end earlier
767       for (++pszSubmount; *pszSubmount && (*pszSubmount != TEXT('\\')); ++pszSubmount)
768          if (!_tcsncicmp(pszSubmount, szNetBiosName, _tcslen(szNetBiosName)))
769             break;
770       if ((!*pszSubmount) || (*pszSubmount == TEXT('\\')))
771          return FALSE;
772
773        pszSubmount += _tcslen(szNetBiosName);
774       }
775    else // (!IsWindowsNT())
776       {
777       DWORD dwSize = MAX_PATH;
778       if (WNetGetConnection (szDrive, szMapping, &dwSize) != NO_ERROR)
779          return FALSE;
780       if (*(pszSubmount++) != TEXT('\\'))
781          return FALSE;
782       if (*(pszSubmount++) != TEXT('\\'))
783          return FALSE;
784       for ( ; *pszSubmount && (*pszSubmount != TEXT('\\')); ++pszSubmount)
785          if (!lstrncmpi (pszSubmount, szNetBiosName, lstrlen(szNetBiosName)))
786             break;
787       if ((!*pszSubmount) || (*pszSubmount == TEXT('\\')))
788          return FALSE;
789       pszSubmount += lstrlen(szNetBiosName);
790       }
791
792    if (!pszSubmount || !*pszSubmount)
793       return FALSE;
794
795    lstrcpy (pszSubmountNow, pszSubmount);
796    return TRUE;
797 }
798
799 /* Generate Random User name random acording to time*/
800 DWORD dwOldState=0;
801 TCHAR pUserName[MAXRANDOMNAMELEN]=TEXT("");
802 BOOL fUserName=FALSE;
803 #define AFSLogonOptionName TEXT("System\\CurrentControlSet\\Services\\TransarcAFSDaemon\\NetworkProvider")
804
805 void SetBitLogonOption(BOOL set,DWORD value)
806 {
807
808    RWLogonOption(FALSE,((set)?value | RWLogonOption(TRUE,0):RWLogonOption(TRUE,0) & ~value) );  
809 }
810
811 DWORD RWLogonOption(BOOL read,DWORD value)
812 {
813         // if read is true then if value==0 return registry value
814         // if read and value!=0 then use value to test registry, return TRUE if value bits match value read
815    HKEY hk;
816    DWORD dwDisp;
817         DWORD LSPtype, LSPsize;
818         DWORD rval;
819    if (read)
820    {
821            rval=0;
822                 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSLogonOptionName,0, KEY_QUERY_VALUE, &hk)==ERROR_SUCCESS)
823                 {
824                         LSPsize=sizeof(rval);
825                         RegQueryValueEx(hk, "LogonOptions", NULL,
826                                                 &LSPtype, (LPBYTE)&rval, &LSPsize);
827                         RegCloseKey (hk);
828                 }
829                 return (value==0)?rval:((rval & value)==value);
830
831    } else {     //write
832                 if (RegCreateKeyEx (HKEY_LOCAL_MACHINE, AFSLogonOptionName, 0, NULL, 0, KEY_SET_VALUE, NULL, &hk, &dwDisp) == ERROR_SUCCESS)
833                 {
834                         RegSetValueEx(hk,TEXT("LogonOptions"),NULL,REG_DWORD,(LPBYTE)&value,sizeof(value));
835                         RegCloseKey (hk);
836                 }
837                 return TRUE;
838    }
839 }
840
841 void MapShareName(char *pszCmdLineA)
842 {
843         fUserName = TRUE;
844         TCHAR *p=pUserName;
845         pszCmdLineA++;
846         while (*pszCmdLineA && (*pszCmdLineA != ' '))
847         {
848           *p++=*pszCmdLineA++;
849         }
850 }
851
852 void GenRandomName(TCHAR *pname,int len)
853 {
854         if (fUserName)
855         {               //user name was passed through command line, use once
856                 fUserName=FALSE;
857                 return;
858         }
859         srand( (unsigned)time( NULL ) );
860         for (int i=0;i<len;i++)
861                 pname[i]='a'+(rand() % 26);
862         pname[len]=0;
863         return;
864 }
865
866 /*
867         Make a connection using users name
868         if fUserName then force a connection
869 */
870
871 BOOL TestAndDoMapShare(DWORD dwState)
872 {
873     if ((dwState!=SERVICE_RUNNING) || (dwOldState!=SERVICE_START_PENDING))
874         {
875                 dwOldState=dwState;
876                 return TRUE;
877         }
878         dwOldState=SERVICE_RUNNING;
879         if (RWLogonOption(TRUE,LOGON_OPTION_HIGHSECURITY))
880             return (DoMapShare() && GlobalMountDrive());
881         return GlobalMountDrive();
882 }
883
884 BOOL IsServiceActive()
885 {
886    SC_HANDLE hManager;
887    SERVICE_STATUS Status;
888    if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
889       {
890       SC_HANDLE hService;
891       if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
892          {
893          QueryServiceStatus (hService, &Status);
894          CloseServiceHandle (hService);
895          }
896
897       CloseServiceHandle (hManager);
898       }
899
900    return (Status.dwCurrentState == SERVICE_RUNNING) ? TRUE : FALSE;
901 }
902
903 void TestAndDoUnMapShare()
904 {
905         if (!RWLogonOption(TRUE,LOGON_OPTION_HIGHSECURITY))
906                 return;
907         DoUnMapShare(FALSE);    
908 }
909
910 void DoUnMapShare(BOOL drivemap)        //disconnect drivemap 
911 {
912         TCHAR szMachine[MAX_PATH],szPath[MAX_PATH];
913         DWORD rc=28;
914         HANDLE hEnum;
915         LPNETRESOURCE lpnrLocal,lpnr=NULL;
916         DWORD res;
917         DWORD cbBuffer=16384;
918         DWORD cEntries=-1;
919         CHAR *pSubmount="";
920
921     memset(szMachine, '\0', sizeof(szMachine));
922     lana_GetNetbiosName(szMachine, LANA_NETBIOS_NAME_FULL);
923
924    // Initialize the data structure
925         if ((res=WNetOpenEnum(RESOURCE_CONNECTED,RESOURCETYPE_DISK,RESOURCEUSAGE_CONNECTABLE,lpnr,&hEnum))!=NO_ERROR)
926                 return;
927         sprintf(szPath,"\\\\%s\\",szMachine);
928         _strlwr(szPath);
929         lpnrLocal=(LPNETRESOURCE) GlobalAlloc(GPTR,cbBuffer);
930         do {
931                 memset(lpnrLocal,0,cbBuffer);
932                 if ((res = WNetEnumResource(hEnum,&cEntries,lpnrLocal,&cbBuffer))==NO_ERROR)
933                 {
934                         for (DWORD i=0;i<cEntries;i++)
935                         {
936                                 if (strstr(_strlwr(lpnrLocal[i].lpRemoteName),szPath))
937                                 {
938                                         if ((lpnrLocal[i].lpLocalName) && (strlen(lpnrLocal[i].lpLocalName)>0))
939                                         {
940                                                 if (drivemap) {
941                                                     DisMountDOSDrive(*lpnrLocal[i].lpLocalName);
942                             DEBUG_EVENT1("AFS DriveUnMap","UnMap-Local=%x",res);
943                         }
944                                         } else {
945                                             DisMountDOSDriveFull(lpnrLocal[i].lpRemoteName);
946                         DEBUG_EVENT1("AFS DriveUnMap","UnMap-Remote=%x",res);
947                     }
948                                 }
949                         }
950                 }
951         } while (res!=ERROR_NO_MORE_ITEMS);
952         GlobalFree((HGLOBAL)lpnrLocal);
953         WNetCloseEnum(hEnum);
954 }
955
956 BOOL DoMapShareChange()
957 {
958         DRIVEMAPLIST List;
959         TCHAR szMachine[ MAX_PATH],szPath[MAX_PATH];
960         DWORD rc=28;
961         HANDLE hEnum;
962         LPNETRESOURCE lpnrLocal,lpnr=NULL;
963         DWORD res;
964         DWORD cEntries=-1;
965     DWORD cbBuffer=16384;
966
967     memset(szMachine, '\0', sizeof(szMachine));
968     lana_GetNetbiosName(szMachine, LANA_NETBIOS_NAME_FULL);
969
970     // Initialize the data structure
971         if (!IsServiceActive())
972                 return TRUE;
973         memset (&List, 0x00, sizeof(DRIVEMAPLIST));
974         for (size_t ii = 0; ii < 26; ++ii)
975                 List.aDriveMap[ii].chDrive = chDRIVE_A + ii;
976         QueryDriveMapList_ReadSubmounts (&List);
977         if ((res=WNetOpenEnum(RESOURCE_CONNECTED,RESOURCETYPE_DISK,RESOURCEUSAGE_CONNECTABLE,lpnr,&hEnum))!=NO_ERROR)
978                 return FALSE;
979         lpnrLocal=(LPNETRESOURCE) GlobalAlloc(GPTR,cbBuffer);
980         sprintf(szPath,"\\\\%s\\",szMachine);
981         _strlwr(szPath);
982         do {
983                 memset(lpnrLocal,0,cbBuffer);
984                 if ((res = WNetEnumResource(hEnum,&cEntries,lpnrLocal,&cbBuffer))==NO_ERROR)
985                 {
986                         for (DWORD i=0;i<cEntries;i++)
987                         {
988                                 if (strstr(_strlwr(lpnrLocal[i].lpRemoteName),szPath)==NULL)
989                                         continue;       //only look at real afs mappings
990                                 CHAR * pSubmount=strrchr(lpnrLocal[i].lpRemoteName,'\\')+1;
991                                 if (lstrcmpi(pSubmount,"all")==0) 
992                                         continue;                               // do not remove 'all'
993                                 for (DWORD j=0;j<List.cSubmounts;j++)
994                                 {
995                                         if (
996                                                 (List.aSubmounts[j].szSubmount[0]) &&
997                                                 (lstrcmpi(List.aSubmounts[j].szSubmount,pSubmount)==0)
998                                                 ) 
999                                         {
1000                                                 List.aSubmounts[j].fInUse=TRUE; 
1001                                                 goto nextname;
1002                                         }
1003                                 }
1004                                 // wasn't on list so lets remove
1005                                 DisMountDOSDrive(pSubmount);
1006                                 nextname:;
1007                         }
1008                 }
1009         } while (res!=ERROR_NO_MORE_ITEMS);
1010         GlobalFree((HGLOBAL)lpnrLocal);
1011         WNetCloseEnum(hEnum);
1012         sprintf(szPath,"\\\\%s\\all",szMachine);
1013
1014         // Lets connect all submounts that weren't connectd
1015     DWORD cbUser=MAXRANDOMNAMELEN-1;
1016         CHAR szUser[MAXRANDOMNAMELEN];
1017     CHAR * pUser = NULL;
1018         if (WNetGetUser(szPath,(LPSTR)szUser,&cbUser)!=NO_ERROR) {
1019         if (RWLogonOption(TRUE,LOGON_OPTION_HIGHSECURITY)) {
1020             if (!pUserName[0]) {
1021                 GenRandomName(szUser,MAXRANDOMNAMELEN-1);
1022                 pUser = szUser;
1023             } else {
1024                 pUser = pUserName;
1025             }
1026         }
1027     } else {
1028                 if ((pUser=strchr(szUser,'\\'))!=NULL)
1029             pUser++;
1030         }
1031
1032     for (DWORD j=0;j<List.cSubmounts;j++)
1033         {
1034                 if (List.aSubmounts[j].fInUse)
1035                         continue;
1036                 DWORD res=MountDOSDrive(0,List.aSubmounts[j].szSubmount,FALSE,pUser);
1037         }
1038         return TRUE;
1039 }
1040
1041 BOOL DoMapShare()
1042 {
1043         DRIVEMAPLIST List;
1044         DWORD rc=28;
1045         BOOL bMappedAll=FALSE;
1046
1047    // Initialize the data structure
1048         DEBUG_EVENT0("AFS DoMapShare");
1049         QueryDriveMapList (&List);
1050         DoUnMapShare(TRUE);
1051         // All connections have been removed
1052         // Lets restore them after making the connection from the random name
1053
1054         TCHAR szMachine[ MAX_PATH],szPath[MAX_PATH];
1055     memset(szMachine, '\0', sizeof(szMachine));
1056     lana_GetNetbiosName(szMachine, LANA_NETBIOS_NAME_FULL);
1057     sprintf(szPath,"\\\\%s\\all",szMachine);
1058
1059     // Lets connect all submounts that weren't connectd
1060     DWORD cbUser=MAXRANDOMNAMELEN-1;
1061         CHAR szUser[MAXRANDOMNAMELEN];
1062     CHAR * pUser = NULL;
1063         if (WNetGetUser(szPath,(LPSTR)szUser,&cbUser)!=NO_ERROR) {
1064         if (RWLogonOption(TRUE,LOGON_OPTION_HIGHSECURITY)) {
1065             if (!pUserName[0]) {
1066                 GenRandomName(szUser,MAXRANDOMNAMELEN-1);
1067                 pUser = szUser;
1068             } else {
1069                 pUser = pUserName;
1070             }
1071         }
1072     } else {
1073                 if ((pUser=strchr(szUser,'\\'))!=NULL)
1074             pUser++;
1075         }
1076
1077         for (DWORD i=0;i<List.cSubmounts;i++)
1078         {
1079                 if (List.aSubmounts[i].szSubmount[0])
1080                 {
1081                         DWORD res=MountDOSDrive(0,List.aSubmounts[i].szSubmount,FALSE,pUser);
1082                         if (lstrcmpi("all",List.aSubmounts[i].szSubmount)==0)
1083                                 bMappedAll=TRUE;
1084                 }
1085         }
1086         if (!bMappedAll)        //make sure all is mapped also
1087         {
1088         DWORD res=MountDOSDrive(0,"all",FALSE,pUser);
1089         if (res==ERROR_SESSION_CREDENTIAL_CONFLICT)
1090         {
1091             DisMountDOSDrive("all");
1092             MountDOSDrive(0,"all",FALSE,pUser);
1093         }
1094         }
1095         for (TCHAR chDrive = chDRIVE_A; chDrive <= chDRIVE_Z; ++chDrive)
1096         {
1097                 if (List.aDriveMap[chDrive-chDRIVE_A].fActive ||
1098             ForceMapActive(chDrive))
1099                 {
1100             TCHAR szSubmount[ MAX_PATH ];
1101             if (List.aDriveMap[chDrive-chDRIVE_A].szSubmount[0])
1102                 lstrcpy(szSubmount,List.aDriveMap[chDrive-chDRIVE_A].szSubmount);
1103             else if (!PathToSubmount (szSubmount, List.aDriveMap[chDrive-chDRIVE_A].szMapping, NULL, NULL))
1104                 continue;
1105
1106             BOOL fPersistent = List.aDriveMap[chDrive-chDRIVE_A].fPersistent;
1107             if (RWLogonOption(TRUE,LOGON_OPTION_HIGHSECURITY))
1108                 fPersistent = FALSE;
1109                     DWORD res=MountDOSDrive(chDrive
1110                                             ,szSubmount
1111                                             ,fPersistent,pUser);
1112                 }
1113         }
1114         return TRUE;
1115 }
1116
1117 BOOL GlobalMountDrive()
1118 {
1119     char szDriveToMapTo[5];
1120     DWORD dwResult;
1121     char szKeyName[256];
1122     HKEY hKey;
1123     DWORD dwIndex = 0;
1124     DWORD dwDriveSize;
1125     DWORD dwSubMountSize;
1126     char unsigned szSubMount[256];
1127     char cm_HostName[200];
1128     DWORD dwType=sizeof(cm_HostName);
1129     if (!IsServiceActive())
1130         return TRUE;
1131     if (!GetComputerName(cm_HostName, &dwType))
1132         return TRUE;
1133     sprintf(szKeyName, "%s\\GlobalAutoMapper", sAFSConfigKeyName);
1134     
1135     dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE,
1136                             &hKey);
1137     if (dwResult != ERROR_SUCCESS)
1138         return TRUE;
1139     
1140     while (1) {
1141         dwDriveSize = sizeof(szDriveToMapTo);
1142         dwSubMountSize = sizeof(szSubMount);
1143         dwResult = RegEnumValue(hKey, dwIndex++, szDriveToMapTo, &dwDriveSize, 
1144                                 0, &dwType, szSubMount, &dwSubMountSize);
1145         if (dwResult != ERROR_MORE_DATA) {
1146             if (dwResult != ERROR_SUCCESS) {
1147                 if (dwResult != ERROR_NO_MORE_ITEMS)
1148                 {
1149                     DEBUG_EVENT1("AFS DriveMap","Failed to read GlobalAutoMapper values: %d",dwResult);
1150                 }
1151                 break;
1152             }
1153         }
1154         dwResult=MountDOSDrive(*szDriveToMapTo,(const char *)szSubMount,FALSE);
1155     }
1156     RegCloseKey(hKey);
1157     return TRUE;
1158 }
1159
1160 DWORD MountDOSDrive(char chDrive,const char *szSubmount,BOOL bPersistent,const char * pUsername)
1161 {
1162     TCHAR szPath[MAX_PATH];
1163     TCHAR szClient[MAX_PATH];
1164     TCHAR szDrive[3] = TEXT("?:");
1165     sprintf(szDrive,"%c:",chDrive);
1166     GetClientNetbiosName (szClient);
1167     sprintf(szPath,"\\\\%s\\%s",szClient,szSubmount);
1168     NETRESOURCE nr;
1169     memset (&nr, 0x00, sizeof(NETRESOURCE));
1170     nr.dwType=RESOURCETYPE_DISK;
1171     nr.lpLocalName=szDrive;
1172     nr.lpRemoteName=szPath;
1173     nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
1174     DWORD res=WNetAddConnection2(&nr,NULL,pUsername,(bPersistent)?CONNECT_UPDATE_PROFILE:0);
1175     DEBUG_EVENT5("AFS DriveMap","Mount %s Local[%s] Remote[%s] User[%s]=%x",
1176                   (bPersistent)?"Persistant" : "NonPresistant",
1177                   szDrive,szPath,pUsername?pUsername:"NULL",res);
1178     return res;
1179 }
1180
1181 DWORD DisMountDOSDriveFull(const char *szPath,BOOL bForce)
1182 {
1183     DWORD res=WNetCancelConnection(szPath,bForce);
1184     DEBUG_EVENT3("AFS DriveMap","%sDismount Remote[%s]=%x",
1185                   bForce ? "Forced " : "",szPath,res);
1186     return (res==ERROR_NOT_CONNECTED)?NO_ERROR:res;
1187 }
1188
1189 DWORD DisMountDOSDrive(const char *pSubmount,BOOL bForce)
1190 {
1191     TCHAR szPath[MAX_PATH];
1192     TCHAR szClient[MAX_PATH];
1193     GetClientNetbiosName (szClient);
1194     sprintf(szPath,"\\\\%s\\%s",szClient,pSubmount);
1195     return DisMountDOSDriveFull(szPath,bForce);
1196 }
1197
1198
1199 DWORD DisMountDOSDrive(const char chDrive,BOOL bForce)
1200 {
1201     TCHAR szPath[MAX_PATH];
1202     sprintf(szPath,"%c:",chDrive);
1203     return DisMountDOSDriveFull(szPath,bForce);
1204 }