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