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