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