2 * Copyright 2000, International Business Machines Corporation and others.
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
11 #include <afs/param.h>
18 #include <WINNT/TaLocale.h>
23 * REGISTRY ___________________________________________________________________
27 static const TCHAR AFSConfigKeyName[] = TEXT("SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters");
31 * PROFILE SECTIONS ___________________________________________________________
35 #define cREALLOC_SUBMOUNTS 4
37 static TCHAR cszINIFILE[] = TEXT("afsdsbmt.ini");
38 static TCHAR cszSECTION_SUBMOUNTS[] = TEXT("AFS Submounts");
39 static TCHAR cszSECTION_MAPPINGS[] = TEXT("AFS Mappings");
41 static TCHAR cszAUTOSUBMOUNT[] = TEXT("Auto");
42 static TCHAR cszLANMANDEVICE[] = TEXT("\\Device\\LanmanRedirector\\");
46 * STRINGS ____________________________________________________________________
50 static LPTSTR AllocateStringMemory (size_t cch)
52 LPTSTR psz = (LPTSTR)Allocate (sizeof(TCHAR) * (cch+1));
53 memset (psz, 0x00, sizeof(TCHAR) * (cch+1));
57 static void FreeStringMemory (LPTSTR pszString)
62 static int lstrncmpi (LPCTSTR pszA, LPCTSTR pszB, size_t cch)
66 return (!pszB) - (!pszA); // A,!B:1, !A,B:-1, !A,!B:0
69 for ( ; cch > 0; cch--, pszA = CharNext(pszA), pszB = CharNext(pszB))
71 TCHAR chA = toupper( *pszA );
72 TCHAR chB = toupper( *pszB );
75 return (!chB) - (!chA); // A,!B:1, !A,B:-1, !A,!B:0
78 return (int)(chA) - (int)(chB); // -1:A<B, 0:A==B, 1:A>B
81 return 0; // no differences before told to stop comparing, so A==B
86 * REALLOC ____________________________________________________________________
91 #define REALLOC(_a,_c,_r,_i) DriveMapReallocFunction ((LPVOID*)&_a,sizeof(*_a),&_c,_r,_i)
92 BOOL DriveMapReallocFunction (LPVOID *ppTarget, size_t cbElement, size_t *pcTarget, size_t cReq, size_t cInc)
97 if (cReq <= *pcTarget)
100 if ((cNew = cInc * ((cReq + cInc-1) / cInc)) <= 0)
103 if ((pNew = Allocate (cbElement * cNew)) == NULL)
105 memset (pNew, 0x00, cbElement * cNew);
109 memcpy (pNew, *ppTarget, cbElement * (*pcTarget));
121 * WINDOWS NT STUFF ___________________________________________________________
125 static BOOL IsWindowsNT (void)
127 static BOOL fChecked = FALSE;
128 static BOOL fIsWinNT = FALSE;
134 OSVERSIONINFO Version;
135 memset (&Version, 0x00, sizeof(Version));
136 Version.dwOSVersionInfoSize = sizeof(Version);
138 if (GetVersionEx (&Version))
140 if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT)
149 BOOL IsWindows2000 (void)
151 static BOOL fChecked = FALSE;
152 static BOOL fIsWin2K = FALSE;
158 OSVERSIONINFO Version;
159 memset (&Version, 0x00, sizeof(Version));
160 Version.dwOSVersionInfoSize = sizeof(Version);
162 if (GetVersionEx (&Version))
164 if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
165 Version.dwMajorVersion >= 5)
174 * GENERAL ____________________________________________________________________
178 void GetClientNetbiosName (LPTSTR pszName)
180 *pszName = TEXT('\0');
185 if (RegOpenKey (HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Control\\ComputerName\\ComputerName"), &hk) == 0)
187 DWORD dwSize = MAX_PATH;
188 DWORD dwType = REG_SZ;
189 RegQueryValueEx (hk, TEXT("ComputerName"), NULL, &dwType, (PBYTE)pszName, &dwSize);
192 else // (!IsWindowsNT())
195 if (RegOpenKey (HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters"), &hk) == 0)
197 DWORD dwSize = MAX_PATH;
198 DWORD dwType = REG_SZ;
199 RegQueryValueEx (hk, TEXT("Gateway"), NULL, &dwType, (PBYTE)pszName, &dwSize);
203 // Shorten the server name from its FQDN
205 for (LPTSTR pch = pszName; *pch; ++pch)
207 if (*pch == TEXT('.'))
209 *(LPTSTR)pch = TEXT('\0');
214 // Form NetBIOS name from client's (possibly truncated) simple host name.
215 if (*pszName != TEXT('\0')) {
216 pszName[11] = TEXT('\0');
217 lstrcat(pszName, TEXT("-AFS"));
222 BOOL SubmountToPath (PDRIVEMAPLIST pList, LPTSTR pszPath, LPTSTR pszSubmount, BOOL fMarkInUse)
224 // We can't do this translation unless we're under Windows NT.
229 // \\computer-afs\all always maps to "/afs"
231 if (!lstrcmpi (pszSubmount, TEXT("all")))
233 lstrcpy (pszPath, TEXT("/afs"));
237 // Otherwise, look up our list of submounts.
239 for (size_t ii = 0; ii < pList->cSubmounts; ++ii)
241 if (!lstrcmpi (pList->aSubmounts[ii].szSubmount, pszSubmount))
244 pList->aSubmounts[ii].fInUse = TRUE;
245 AdjustAfsPath (pszPath, pList->aSubmounts[ii].szMapping, TRUE, TRUE);
254 BOOL IsValidSubmountName (LPTSTR pszSubmount)
258 if (lstrlen (pszSubmount) > 12)
261 for ( ; *pszSubmount; ++pszSubmount)
263 if (!isprint(*pszSubmount))
265 if (*pszSubmount == TEXT(' '))
267 if (*pszSubmount == TEXT('\t'))
276 * PIOCTL SUPPORT _____________________________________________________________
282 #include "../afsd/fs_utils.h"
284 #define __CM_CONFIG_INTERFACES_ONLY__
285 #include "../afsd/cm_config.h"
287 #define __CM_IOCTL_INTERFACES_ONLY__
288 #include "../afsd/cm_ioctl.h"
292 #define PIOCTL_MAXSIZE 2048
295 BOOL fCanIssuePIOCTL (void)
299 TCHAR szGateway[ 256 ] = TEXT("");
300 GetClientNetbiosName (szGateway);
301 return (szGateway[0]) ? TRUE : FALSE;
304 SERVICE_STATUS Status;
305 memset (&Status, 0x00, sizeof(Status));
306 Status.dwCurrentState = SERVICE_STOPPED;
309 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
312 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
314 QueryServiceStatus (hService, &Status);
315 CloseServiceHandle (hService);
318 CloseServiceHandle (hManager);
321 return (Status.dwCurrentState == SERVICE_RUNNING) ? TRUE : FALSE;
326 * QUERYDRIVEMAPLIST __________________________________________________________
330 void QueryDriveMapList_ReadSubmounts (PDRIVEMAPLIST pList)
334 size_t cchLHS = 1024;
335 LPTSTR mszLHS = AllocateStringMemory (cchLHS);
337 for (int iRetry = 0; iRetry < 5; ++iRetry)
339 DWORD rc = GetPrivateProfileString (cszSECTION_SUBMOUNTS, NULL, TEXT(""), mszLHS, cchLHS, cszINIFILE);
340 if ((rc != cchLHS-1) && (rc != cchLHS-2))
343 FreeStringMemory (mszLHS);
345 mszLHS = AllocateStringMemory (cchLHS);
348 for (LPTSTR psz = mszLHS; psz && *psz; psz += 1+lstrlen(psz))
351 memset (&Submount, 0x00, sizeof(SUBMOUNT));
352 lstrcpy (Submount.szSubmount, psz);
354 TCHAR szMapping[ MAX_PATH ] = TEXT("");
355 GetPrivateProfileString (cszSECTION_SUBMOUNTS, Submount.szSubmount, TEXT(""), szMapping, MAX_PATH, cszINIFILE);
356 if (szMapping[0] != TEXT('\0'))
358 AdjustAfsPath (Submount.szMapping, szMapping, FALSE, TRUE);
360 for (size_t ii = 0; ii < pList->cSubmounts; ++ii)
362 if (!pList->aSubmounts[ii].szSubmount[0])
365 if (REALLOC (pList->aSubmounts, pList->cSubmounts, 1+ii, cREALLOC_SUBMOUNTS))
367 memcpy (&pList->aSubmounts[ii], &Submount, sizeof(SUBMOUNT));
372 FreeStringMemory (mszLHS);
377 void QueryDriveMapList_ReadMappings (PDRIVEMAPLIST pList)
379 size_t cchLHS = 1024;
380 LPTSTR mszLHS = AllocateStringMemory (cchLHS);
382 for (int iRetry = 0; iRetry < 5; ++iRetry)
384 DWORD rc = GetPrivateProfileString (cszSECTION_MAPPINGS, NULL, TEXT(""), mszLHS, cchLHS, cszINIFILE);
385 if ((rc != cchLHS-1) && (rc != cchLHS-2))
388 FreeStringMemory (mszLHS);
390 mszLHS = AllocateStringMemory (cchLHS);
393 for (LPTSTR psz = mszLHS; psz && *psz; psz += 1+lstrlen(psz))
396 memset (&DriveMap, 0x00, sizeof(DRIVEMAP));
397 DriveMap.chDrive = toupper(*psz);
398 DriveMap.fPersistent = TRUE;
399 if ((DriveMap.chDrive < chDRIVE_A) || (DriveMap.chDrive > chDRIVE_Z))
402 TCHAR szMapping[ MAX_PATH ] = TEXT("");
403 GetPrivateProfileString (cszSECTION_MAPPINGS, psz, TEXT(""), szMapping, MAX_PATH, cszINIFILE);
404 if (szMapping[0] != TEXT('\0'))
406 AdjustAfsPath (DriveMap.szMapping, szMapping, TRUE, TRUE);
407 if (DriveMap.szMapping[ lstrlen(DriveMap.szMapping)-1 ] == TEXT('*'))
409 DriveMap.fPersistent = FALSE;
410 DriveMap.szMapping[ lstrlen(DriveMap.szMapping)-1 ] = TEXT('\0');
412 size_t iDrive = DriveMap.chDrive - chDRIVE_A;
413 memcpy (&pList->aDriveMap[ iDrive ], &DriveMap, sizeof(DRIVEMAP));
417 FreeStringMemory (mszLHS);
421 void QueryDriveMapList_WriteMappings (PDRIVEMAPLIST pList)
423 WriteDriveMappings (pList);
427 void WriteDriveMappings (PDRIVEMAPLIST pList)
429 WritePrivateProfileString (cszSECTION_MAPPINGS, NULL, NULL, cszINIFILE);
431 for (size_t iDrive = 0; iDrive < 26; ++iDrive)
433 if (pList->aDriveMap[iDrive].szMapping[0] != TEXT('\0'))
435 TCHAR szLHS[] = TEXT("*");
436 szLHS[0] = pList->aDriveMap[iDrive].chDrive;
438 TCHAR szRHS[MAX_PATH];
439 AdjustAfsPath (szRHS, pList->aDriveMap[iDrive].szMapping, TRUE, TRUE);
440 if (!pList->aDriveMap[iDrive].fPersistent)
441 lstrcat (szRHS, TEXT("*"));
443 WritePrivateProfileString (cszSECTION_MAPPINGS, szLHS, szRHS, cszINIFILE);
448 BOOL DriveIsGlobalAfsDrive(TCHAR chDrive)
450 TCHAR szKeyName[128];
451 TCHAR szValueName[128];
455 _stprintf(szKeyName, TEXT("%s\\GlobalAutoMapper"), AFSConfigKeyName);
457 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_QUERY_VALUE, &hKey) != ERROR_SUCCESS)
460 _stprintf(szValueName, TEXT("%c:"), chDrive);
462 DWORD dwSize = sizeof(szValue);
463 BOOL bIsGlobal = (RegQueryValueEx (hKey, szValueName, NULL, NULL, (PBYTE)szValue, &dwSize) == ERROR_SUCCESS);
471 void QueryDriveMapList_FindNetworkDrives (PDRIVEMAPLIST pList, BOOL *pfFoundNew)
473 for (TCHAR chDrive = chDRIVE_A; chDrive <= chDRIVE_Z; ++chDrive)
475 TCHAR szSubmount[ MAX_PATH ];
476 if (!GetDriveSubmount (chDrive, szSubmount))
479 // We've got a mapping! Drive {chDrive} is mapped to submount
480 // {szSubmount}. See if that submount makes sense.
484 size_t iDrive = chDrive - chDRIVE_A;
485 if (pList->aDriveMap[ iDrive ].szMapping[0] != TEXT('\0'))
487 pList->aDriveMap[ iDrive ].fActive = TRUE;
488 lstrcpy (pList->aDriveMap[ iDrive ].szSubmount, szSubmount);
492 else // (IsWindowsNT())
494 TCHAR szAfsPath[ MAX_PATH ];
495 if (!SubmountToPath (pList, szAfsPath, szSubmount, TRUE))
498 // Okay, we know that drive {chDrive} is mapped to afs path {szAfsPath}.
499 // If this drive is a global afs drive, then reject it. Otherwise, look
500 // at pList->aDriveMap, to see if this drive mapping is already in our
501 // list. If not, add it and set pfFoundNew.
503 if (DriveIsGlobalAfsDrive(chDrive))
506 size_t iDrive = chDrive - chDRIVE_A;
507 if (lstrcmpi (pList->aDriveMap[ iDrive ].szMapping, szAfsPath))
510 pList->aDriveMap[ iDrive ].fPersistent = TRUE;
512 pList->aDriveMap[ iDrive ].fActive = TRUE;
513 pList->aDriveMap[ iDrive ].chDrive = chDrive;
514 lstrcpy (pList->aDriveMap[ iDrive ].szSubmount, szSubmount);
515 AdjustAfsPath (pList->aDriveMap[ iDrive ].szMapping, szAfsPath, TRUE, TRUE);
521 void QueryDriveMapList (PDRIVEMAPLIST pList)
523 // Initialize the data structure
525 memset (pList, 0x00, sizeof(DRIVEMAPLIST));
526 for (size_t ii = 0; ii < 26; ++ii)
527 pList->aDriveMap[ii].chDrive = chDRIVE_A + ii;
529 // Read the current lists of submounts and drive letter mappings
531 QueryDriveMapList_ReadSubmounts (pList);
532 QueryDriveMapList_ReadMappings (pList);
534 // Look through the current list of network drives, and see if
535 // any are currently mapped to AFS. If we find any which are mapped
536 // into AFS unexpectedly, we'll have to rewrite the mappings list.
538 BOOL fFoundNew = FALSE;
539 QueryDriveMapList_FindNetworkDrives (pList, &fFoundNew);
543 QueryDriveMapList_WriteMappings (pList);
548 void FreeDriveMapList (PDRIVEMAPLIST pList)
550 if (pList->aSubmounts)
551 Free (pList->aSubmounts);
552 memset (pList, 0x00, sizeof(DRIVEMAPLIST));
556 BOOL PathToSubmount (LPTSTR pszSubmount, LPTSTR pszMapping, LPTSTR pszSubmountReq, ULONG *pStatus)
558 if (pszSubmountReq && !IsValidSubmountName (pszSubmountReq))
559 pszSubmountReq = NULL;
561 TCHAR szAfsPath[ MAX_PATH ];
562 AdjustAfsPath (szAfsPath, pszMapping, TRUE, TRUE);
564 // Try to ask AFSD for a new submount name.
566 if (!fCanIssuePIOCTL())
569 BYTE InData[ PIOCTL_MAXSIZE ];
570 memset (InData, 0x00, sizeof(InData));
572 LPTSTR pszInData = (LPTSTR)InData;
573 lstrcpy (pszInData, pszMapping);
574 pszInData += 1+lstrlen(pszInData);
576 lstrcpy (pszInData, pszSubmountReq);
578 BYTE OutData[ PIOCTL_MAXSIZE ];
579 memset (OutData, 0x00, sizeof(OutData));
581 struct ViceIoctl IOInfo;
582 IOInfo.in = (char *)InData;
583 IOInfo.in_size = PIOCTL_MAXSIZE;
584 IOInfo.out = (char *)OutData;
585 IOInfo.out_size = PIOCTL_MAXSIZE;
588 if ((status = pioctl (0, VIOC_MAKESUBMOUNT, &IOInfo, 1)) != 0)
591 lstrcpy (pszSubmount, (LPCTSTR)OutData);
592 return (pszSubmount[0] != TEXT('\0')) ? TRUE : FALSE;
596 BOOL ActivateDriveMap (TCHAR chDrive, LPTSTR pszMapping, LPTSTR pszSubmountReq, BOOL fPersistent, DWORD *pdwStatus)
598 // We can only map drives to places in AFS using this function.
600 if ( (lstrncmpi (pszMapping, TEXT("/afs"), lstrlen(TEXT("/afs")))) &&
601 (lstrncmpi (pszMapping, TEXT("\\afs"), lstrlen(TEXT("\\afs")))) )
604 *pdwStatus = ERROR_BAD_NETPATH;
608 // First we have to translate {pszMapping} into a submount, and if there is
609 // no current submount associated with this path, we'll have to make one.
612 TCHAR szSubmount[ MAX_PATH ];
613 if (!PathToSubmount (szSubmount, pszMapping, pszSubmountReq, &status))
620 // We now have a submount name and drive letter--map the network drive.
622 TCHAR szClient[ MAX_PATH ];
623 GetClientNetbiosName (szClient);
625 TCHAR szLocal[ MAX_PATH ] = TEXT("*:");
626 szLocal[0] = chDrive;
628 TCHAR szRemote[ MAX_PATH ];
629 wsprintf (szRemote, TEXT("\\\\%s\\%s"), szClient, szSubmount);
631 NETRESOURCE Resource;
632 memset (&Resource, 0x00, sizeof(NETRESOURCE));
633 Resource.dwScope = RESOURCE_GLOBALNET;
634 Resource.dwType = RESOURCETYPE_DISK;
635 Resource.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
636 Resource.dwUsage = RESOURCEUSAGE_CONNECTABLE;
637 Resource.lpLocalName = szLocal;
638 Resource.lpRemoteName = szRemote;
640 DWORD rc = WNetAddConnection2 (&Resource, NULL, NULL, ((fPersistent) ? CONNECT_UPDATE_PROFILE : 0));
650 BOOL InactivateDriveMap (TCHAR chDrive, DWORD *pdwStatus)
652 TCHAR szLocal[ MAX_PATH ] = TEXT("*:");
653 szLocal[0] = chDrive;
655 DWORD rc = WNetCancelConnection (szLocal, FALSE);
665 void AddSubMount (LPTSTR pszSubmount, LPTSTR pszMapping)
667 TCHAR szRHS[ MAX_PATH ];
668 AdjustAfsPath (szRHS, pszMapping, FALSE, TRUE);
670 lstrcpy (szRHS, TEXT("/"));
671 WritePrivateProfileString (cszSECTION_SUBMOUNTS, pszSubmount, szRHS, cszINIFILE);
675 void RemoveSubMount (LPTSTR pszSubmount)
677 WritePrivateProfileString (cszSECTION_SUBMOUNTS, pszSubmount, NULL, cszINIFILE);
681 void AdjustAfsPath (LPTSTR pszTarget, LPCTSTR pszSource, BOOL fWantAFS, BOOL fWantForwardSlashes)
684 lstrcpy (pszTarget, (fWantAFS) ? TEXT("/afs") : TEXT(""));
685 else if ((*pszSource != TEXT('/')) && (*pszSource != TEXT('\\')))
686 wsprintf (pszTarget, TEXT("/afs/%s"), pszSource);
687 // We don't want to strip afs off the start if it is part of something for example afscell.company.com
688 else if (fWantAFS && (lstrncmpi (&pszSource[1], TEXT("afs"), 3)) || !((pszSource[4] == TEXT('/')) ||
689 (pszSource[4] == TEXT('\\')) ||
690 (lstrlen(pszSource) == 4)))
691 wsprintf (pszTarget, TEXT("/afs%s"), pszSource);
692 else if (!fWantAFS && (!lstrncmpi (&pszSource[1], TEXT("afs"), 3) && ((pszSource[4] == TEXT('/')) ||
693 (pszSource[4] == TEXT('\\')) ||
694 (lstrlen(pszSource) == 4))))
695 lstrcpy (pszTarget, &pszSource[4]);
697 lstrcpy (pszTarget, pszSource);
699 for (LPTSTR pch = pszTarget; *pch; ++pch)
701 if (fWantForwardSlashes)
703 *pch = (*pch == TEXT('\\')) ? TEXT('/') : (*pch);
705 else // (!fWantForwardSlashes)
707 *pch = (*pch == TEXT('/')) ? TEXT('\\') : (*pch);
711 if (lstrlen(pszTarget) &&
712 ((pszTarget[lstrlen(pszTarget)-1] == TEXT('/')) ||
713 (pszTarget[lstrlen(pszTarget)-1] == TEXT('\\'))))
715 pszTarget[lstrlen(pszTarget)-1] = TEXT('\0');
720 BOOL GetDriveSubmount (TCHAR chDrive, LPTSTR pszSubmountNow)
722 TCHAR szDrive[] = TEXT("*:");
723 szDrive[0] = chDrive;
725 TCHAR szMapping[ MAX_PATH ] = TEXT("");
726 LPTSTR pszSubmount = szMapping;
730 QueryDosDevice (szDrive, szMapping, MAX_PATH);
732 // Now if this is an AFS network drive mapping, {szMapping} will be:
734 // \Device\LanmanRedirector\Q:\machine-afs\submount
736 // on Windows NT. On Windows 2000, it will be:
738 // \Device\LanmanRedirector\;Q:0\machine-afs\submount
740 // (This is presumably to support multiple drive mappings with
743 if (lstrncmpi (szMapping, cszLANMANDEVICE, lstrlen(cszLANMANDEVICE)))
745 pszSubmount = &szMapping[ lstrlen(cszLANMANDEVICE) ];
748 if (*(pszSubmount) != TEXT(';'))
751 if (toupper(*(++pszSubmount)) != chDrive)
754 if (*(++pszSubmount) != TEXT(':'))
758 if (*(++pszSubmount) != TEXT('0'))
761 if (*(++pszSubmount) != TEXT('\\'))
763 for (++pszSubmount; *pszSubmount && (*pszSubmount != TEXT('\\')); ++pszSubmount)
764 if (!lstrncmpi (pszSubmount, TEXT("-afs\\"), lstrlen(TEXT("-afs\\"))))
766 if ((!*pszSubmount) || (*pszSubmount == TEXT('\\')))
768 pszSubmount += lstrlen("-afs\\");
770 else // (!IsWindowsNT())
772 DWORD dwSize = MAX_PATH;
773 if (WNetGetConnection (szDrive, szMapping, &dwSize) != NO_ERROR)
775 if (*(pszSubmount++) != TEXT('\\'))
777 if (*(pszSubmount++) != TEXT('\\'))
779 for ( ; *pszSubmount && (*pszSubmount != TEXT('\\')); ++pszSubmount)
780 if (!lstrncmpi (pszSubmount, TEXT("-afs\\"), lstrlen(TEXT("-afs\\"))))
782 if ((!*pszSubmount) || (*pszSubmount == TEXT('\\')))
784 pszSubmount += lstrlen("-afs\\");
787 if (!pszSubmount || !*pszSubmount)
790 lstrcpy (pszSubmountNow, pszSubmount);