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