/*
* Copyright 2000, International Business Machines Corporation and others.
* All Rights Reserved.
- *
+ *
* This software has been released under the terms of the IBM Public
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
#include <afsconfig.h>
#include <afs/param.h>
+#include <afs/stds.h>
-RCSID
- ("$Header$");
+#include <roken.h>
-#include <afs/stds.h>
#include <windows.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <malloc.h>
-#include <string.h>
#include <winioctl.h>
#include <winsock2.h>
#define SECURITY_WIN32
#include <cm_dir.h>
#include <cm_utils.h>
#include <cm_ioctl.h>
-
+#include <smb_iocons.h>
#include <smb.h>
#include <pioctl_nt.h>
#include <WINNT/afsreg.h>
if ( !init ) {
HKEY hk;
- if (RegOpenKey (HKEY_LOCAL_MACHINE,
+ if (RegOpenKey (HKEY_LOCAL_MACHINE,
TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
{
DWORD dwSize = sizeof(BOOL);
if ( !init ) {
HKEY hk;
- if (RegOpenKey (HKEY_LOCAL_MACHINE,
+ if (RegOpenKey (HKEY_LOCAL_MACHINE,
TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
{
DWORD dwSize = sizeof(BOOL);
return smcheck;
}
-static DWORD
+static DWORD
GetServiceStatus(
- LPSTR lpszMachineName,
+ LPSTR lpszMachineName,
LPSTR lpszServiceName,
- DWORD *lpdwCurrentState)
-{
- DWORD hr = NOERROR;
- SC_HANDLE schSCManager = NULL;
- SC_HANDLE schService = NULL;
- DWORD fdwDesiredAccess = 0;
- SERVICE_STATUS ssServiceStatus = {0};
- BOOL fRet = FALSE;
-
- *lpdwCurrentState = 0;
-
- fdwDesiredAccess = GENERIC_READ;
-
- schSCManager = OpenSCManager(lpszMachineName,
+ DWORD *lpdwCurrentState)
+{
+ DWORD hr = NOERROR;
+ SC_HANDLE schSCManager = NULL;
+ SC_HANDLE schService = NULL;
+ DWORD fdwDesiredAccess = 0;
+ SERVICE_STATUS ssServiceStatus = {0};
+ BOOL fRet = FALSE;
+
+ *lpdwCurrentState = 0;
+
+ fdwDesiredAccess = GENERIC_READ;
+
+ schSCManager = OpenSCManager(lpszMachineName,
NULL,
- fdwDesiredAccess);
-
- if(schSCManager == NULL)
- {
+ fdwDesiredAccess);
+
+ if(schSCManager == NULL)
+ {
hr = GetLastError();
- goto cleanup;
- }
-
+ goto cleanup;
+ }
+
schService = OpenService(schSCManager,
lpszServiceName,
- fdwDesiredAccess);
-
- if(schService == NULL)
- {
+ fdwDesiredAccess);
+
+ if(schService == NULL)
+ {
hr = GetLastError();
- goto cleanup;
- }
-
+ goto cleanup;
+ }
+
fRet = QueryServiceStatus(schService,
- &ssServiceStatus);
-
- if(fRet == FALSE)
- {
- hr = GetLastError();
- goto cleanup;
- }
-
- *lpdwCurrentState = ssServiceStatus.dwCurrentState;
-
-cleanup:
-
- CloseServiceHandle(schService);
- CloseServiceHandle(schSCManager);
-
- return(hr);
-}
+ &ssServiceStatus);
+
+ if(fRet == FALSE)
+ {
+ hr = GetLastError();
+ goto cleanup;
+ }
+
+ *lpdwCurrentState = ssServiceStatus.dwCurrentState;
+
+cleanup:
+
+ CloseServiceHandle(schService);
+ CloseServiceHandle(schSCManager);
+
+ return(hr);
+}
// krb5 functions
DECL_FUNC_PTR(krb5_cc_default_name);
return success;
}
+//
+// Recursively evaluate drivestr to find the final
+// dos drive letter to which the source is mapped.
+//
+static BOOL
+DriveSubstitution(char *drivestr, char *subststr, size_t substlen)
+{
+ char device[MAX_PATH];
+
+ if ( QueryDosDevice(drivestr, device, MAX_PATH) )
+ {
+ if ( device[0] == '\\' &&
+ device[1] == '?' &&
+ device[2] == '?' &&
+ device[3] == '\\' &&
+ isalpha(device[4]) &&
+ device[5] == ':')
+ {
+ device[0] = device[4];
+ device[1] = ':';
+ device[2] = '\0';
+ if ( DriveSubstitution(device, subststr, substlen) )
+ {
+ return TRUE;
+ } else {
+ subststr[0] = device[0];
+ subststr[1] = ':';
+ subststr[2] = '\0';
+ return TRUE;
+ }
+ } else
+ if ( device[0] == '\\' &&
+ device[1] == '?' &&
+ device[2] == '?' &&
+ device[3] == '\\' &&
+ device[4] == 'U' &&
+ device[5] == 'N' &&
+ device[6] == 'C' &&
+ device[7] == '\\')
+ {
+ subststr[0] = '\\';
+ strncpy(&subststr[1], &device[7], substlen-1);
+ subststr[substlen-1] = '\0';
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+//
+// drivestr - is "<drive-letter>:"
+//
static BOOL
DriveIsMappedToAFS(char *drivestr, char *NetbiosName)
{
LPNETRESOURCE lpnrLocal; // pointer to enumerated structures
DWORD i;
BOOL bIsAFS = FALSE;
+ char subststr[MAX_PATH];
+
+ //
+ // Handle drive letter substitution created with "SUBST <drive> <path>".
+ // If a substitution has occurred, use the target drive letter instead
+ // of the source.
+ //
+ if ( DriveSubstitution(drivestr, subststr, MAX_PATH) )
+ {
+ if (subststr[0] == '\\' &&
+ subststr[1] == '\\')
+ {
+ if (_strnicmp( &subststr[2], NetbiosName, strlen(NetbiosName)) == 0)
+ return TRUE;
+ else
+ return FALSE;
+ }
+ drivestr = subststr;
+ }
//
// Call the WNetOpenEnum function to begin the enumeration.
break;
}
while (dwResultEnum != ERROR_NO_MORE_ITEMS);
-
+
//
// Call the GlobalFree function to free the memory.
//
return bIsAFS;
}
+static BOOL
+DriveIsGlobalAutoMapped(char *drivestr)
+{
+ DWORD dwResult;
+ HKEY hKey;
+ DWORD dwSubMountSize;
+ char szSubMount[260];
+ DWORD dwType;
+
+ dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ AFSREG_CLT_SVC_PARAM_SUBKEY "\\GlobalAutoMapper",
+ 0, KEY_QUERY_VALUE, &hKey);
+ if (dwResult != ERROR_SUCCESS)
+ return FALSE;
+
+ dwSubMountSize = sizeof(szSubMount);
+ dwType = REG_SZ;
+ dwResult = RegQueryValueEx(hKey, drivestr, 0, &dwType, szSubMount, &dwSubMountSize);
+ RegCloseKey(hKey);
+
+ if (dwResult == ERROR_SUCCESS && dwType == REG_SZ)
+ return TRUE;
+ else
+ return FALSE;
+}
+
static long
GetIoctlHandle(char *fileNamep, HANDLE * handlep)
{
DWORD gle;
DWORD dwSize = sizeof(szUser);
int saveerrno;
+ UINT driveType;
+ int sharingViolation;
memset(HostName, '\0', sizeof(HostName));
gethostname(HostName, sizeof(HostName));
if (fileNamep) {
drivep = strchr(fileNamep, ':');
if (drivep && (drivep - fileNamep) >= 1) {
- UINT driveType;
tbuffer[0] = *(drivep - 1);
tbuffer[1] = ':';
- tbuffer[2] = '\\';
- tbuffer[3] = '\0';
+ tbuffer[2] = '\0';
driveType = GetDriveType(tbuffer);
switch (driveType) {
case DRIVE_UNKNOWN:
case DRIVE_REMOTE:
- if (DriveIsMappedToAFS(tbuffer, netbiosName))
+ if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
+ DriveIsGlobalAutoMapped(tbuffer))
strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
- else
+ else
return -1;
break;
default:
- return -1;
+ if (DriveIsGlobalAutoMapped(tbuffer))
+ strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
+ else
+ return -1;
}
- } else if (fileNamep[0] == fileNamep[1] &&
+ } else if (fileNamep[0] == fileNamep[1] &&
(fileNamep[0] == '\\' || fileNamep[0] == '/'))
{
int count = 0, i = 0;
count++;
i++;
}
- if (fileNamep[i] == 0)
+ if (fileNamep[i] == 0 || (fileNamep[i-1] != '\\' && fileNamep[i-1] != '/'))
tbuffer[i++] = '\\';
tbuffer[i] = 0;
- strcat(tbuffer, SMB_IOCTL_FILENAME);
+ strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
} else {
char curdir[MAX_PATH]="";
if ( curdir[1] == ':' ) {
tbuffer[0] = curdir[0];
tbuffer[1] = ':';
- strcpy(tbuffer + 2, SMB_IOCTL_FILENAME);
+ tbuffer[2] = '\0';
+
+ driveType = GetDriveType(tbuffer);
+ switch (driveType) {
+ case DRIVE_UNKNOWN:
+ case DRIVE_REMOTE:
+ if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
+ DriveIsGlobalAutoMapped(tbuffer))
+ strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
+ else
+ return -1;
+ break;
+ default:
+ if (DriveIsGlobalAutoMapped(tbuffer))
+ strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
+ else
+ return -1;
+ }
} else if (curdir[0] == curdir[1] &&
- (curdir[0] == '\\' || curdir[0] == '/'))
+ (curdir[0] == '\\' || curdir[0] == '/'))
{
int count = 0, i = 0;
count++;
i++;
}
- if (tbuffer[i] == 0)
+ if (curdir[i] == 0 || (curdir[i-1] != '\\' && curdir[i-1] != '/'))
tbuffer[i++] = '\\';
tbuffer[i] = 0;
strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
fflush(stdout);
/* now open the file */
- fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
- FILE_FLAG_WRITE_THROUGH, NULL);
-
- fflush(stdout);
+ sharingViolation = 0;
+ do {
+ if (sharingViolation)
+ Sleep(100);
+ fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_WRITE_THROUGH, NULL);
+ sharingViolation++;
+ } while (fh == INVALID_HANDLE_VALUE &&
+ GetLastError() == ERROR_SHARING_VIOLATION &&
+ sharingViolation < 100);
+ fflush(stdout);
if (fh == INVALID_HANDLE_VALUE) {
- int gonext = 0;
-
gle = GetLastError();
if (gle && ioctlDebug ) {
char buf[4096];
-
+
saveerrno = errno;
if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
tbuffer,gle,buf);
}
errno = saveerrno;
+ SetLastError(gle);
}
+ }
+
+ if (fh == INVALID_HANDLE_VALUE &&
+ GetLastError() != ERROR_SHARING_VIOLATION) {
+ int gonext = 0;
lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
- if (RegOpenKey (HKEY_CURRENT_USER,
+ if (RegOpenKey (HKEY_CURRENT_USER,
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
{
DWORD dwType = REG_SZ;
if (gonext)
goto try_lsa_principal;
- fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
- FILE_FLAG_WRITE_THROUGH, NULL);
+ sharingViolation = 0;
+ do {
+ if (sharingViolation)
+ Sleep(100);
+ fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_WRITE_THROUGH, NULL);
+ sharingViolation++;
+ } while (fh == INVALID_HANDLE_VALUE &&
+ GetLastError() == ERROR_SHARING_VIOLATION &&
+ sharingViolation < 100);
fflush(stdout);
if (fh == INVALID_HANDLE_VALUE) {
gle = GetLastError();
tbuffer,gle,buf);
}
errno = saveerrno;
+ SetLastError(gle);
}
}
}
}
try_lsa_principal:
- if (fh == INVALID_HANDLE_VALUE) {
+ if (fh == INVALID_HANDLE_VALUE &&
+ GetLastError() != ERROR_SHARING_VIOLATION) {
int gonext = 0;
dwSize = sizeof(szUser);
if (gonext)
goto try_sam_compat;
- fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
- FILE_FLAG_WRITE_THROUGH, NULL);
+ sharingViolation = 0;
+ do {
+ if (sharingViolation)
+ Sleep(100);
+ fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_WRITE_THROUGH, NULL);
+ sharingViolation++;
+ } while (fh == INVALID_HANDLE_VALUE &&
+ GetLastError() == ERROR_SHARING_VIOLATION &&
+ sharingViolation < 100);
fflush(stdout);
if (fh == INVALID_HANDLE_VALUE) {
gle = GetLastError();
tbuffer,gle,buf);
}
errno = saveerrno;
-
+ SetLastError(gle);
}
}
}
}
try_sam_compat:
- if ( fh == INVALID_HANDLE_VALUE ) {
+ if (fh == INVALID_HANDLE_VALUE &&
+ GetLastError() != ERROR_SHARING_VIOLATION) {
dwSize = sizeof(szUser);
if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
if ( ioctlDebug ) {
return -1;
}
- fh = CreateFile(tbuffer, GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
- FILE_FLAG_WRITE_THROUGH, NULL);
+ sharingViolation = 0;
+ do {
+ if (sharingViolation)
+ Sleep(100);
+ fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING,
+ FILE_FLAG_WRITE_THROUGH, NULL);
+ sharingViolation++;
+ } while (fh == INVALID_HANDLE_VALUE &&
+ GetLastError() == ERROR_SHARING_VIOLATION &&
+ sharingViolation < 100);
fflush(stdout);
if (fh == INVALID_HANDLE_VALUE) {
gle = GetLastError();
}
}
+ if (fh == INVALID_HANDLE_VALUE)
+ return -1;
+
/* return fh and success code */
*handlep = fh;
return 0;
pathHasDrive = 0;
}
- if ( firstp[0] == '\\' && firstp[1] == '\\' ||
+ if ( firstp[0] == '\\' && firstp[1] == '\\' ||
firstp[0] == '/' && firstp[1] == '/') {
/* UNC path - strip off the server and sharename */
int i, count;
/* if there is a non-null name after the drive, append it */
if (*firstp != 0) {
int len = (int)strlen(outPathp);
- if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
+ if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
strcat(outPathp, "\\");
strcat(outPathp, firstp);
}
return 0;
}
-static long
-pioctl_int(char *pathp, long opcode, struct ViceIoctl *blobp, int follow, int is_utf8)
+static int
+pioctl_int(char *pathp, afs_int32 opcode, struct ViceIoctl *blobp, afs_int32 follow, afs_int32 is_utf8)
{
fs_ioctlRequest_t preq;
long code;
long temp;
char fullPath[1000];
+ char altPath[1024];
HANDLE reqHandle;
int save;
+ int i,j,count,all;
+
+ /*
+ * The pioctl operations for creating a mount point and a symlink are broken.
+ * Instead of 'pathp' referring to the directory object in which the symlink
+ * or mount point within which the new object is to be created, 'pathp' refers
+ * to the object itself. This results in a problem when the object being created
+ * is located within the Freelance root.afs volume. \\afs\foo will not be a
+ * valid share name since the 'foo' object does not yet exist. Therefore,
+ * \\afs\foo\_._.afs_ioctl_._ cannot be opened. Instead in these two cases
+ * we must force the use of the \\afs\all\foo form of the path.
+ *
+ * We cannot use this form in all cases because of smb submounts which are
+ * not located within the Freelance local root.
+ */
+ switch ( opcode ) {
+ case VIOC_AFS_CREATE_MT_PT:
+ case VIOC_SYMLINK:
+ if (pathp &&
+ (pathp[0] == '\\' && pathp[1] == '\\' ||
+ pathp[0] == '/' && pathp[1] == '/')) {
+ for (all = count = j = 0; pathp[j]; j++) {
+ if (pathp[j] == '\\' || pathp[j] == '/')
+ count++;
+
+ /* Test to see if the second component is 'all' */
+ if (count == 3) {
+ all = 1;
+ for (i=0; pathp[i+j]; i++) {
+ switch(i) {
+ case 0:
+ if (pathp[i+j] != 'a' &&
+ pathp[i+j] != 'A') {
+ all = 0;
+ goto notall;
+ }
+ break;
+ case 1:
+ case 2:
+ if (pathp[i+j] != 'l' &&
+ pathp[i+j] != 'L') {
+ all = 0;
+ goto notall;
+ }
+ break;
+ default:
+ all = 0;
+ goto notall;
+ }
+ }
+ if (i != 3)
+ all = 0;
+ }
+
+ notall:
+ if (all)
+ break;
+ }
+
+ /*
+ * if count is three and the second component is not 'all',
+ * then we are attempting to create an object in the
+ * Freelance root.afs volume. Substitute the path.
+ */
+
+ if (count == 3 && !all) {
+ /* Normalize the name to use \\afs\all as the root */
+ for (count = i = j = 0; pathp[j] && i < sizeof(altPath); j++) {
+ if (pathp[j] == '\\' || pathp[j] == '/') {
+ altPath[i++] = '\\';
+ count++;
+
+ if (count == 3) {
+ altPath[i++] = 'a';
+ altPath[i++] = 'l';
+ altPath[i++] = 'l';
+ altPath[i++] = '\\';
+ count++;
+ }
+ } else {
+ altPath[i++] = pathp[j];
+ }
+ }
+ altPath[i] = '\0';
+ pathp = altPath;
+ }
+ }
+ }
code = GetIoctlHandle(pathp, &reqHandle);
if (code) {
return 0;
}
-long
-pioctl_utf8(char * pathp, long opcode, struct ViceIoctl * blobp, int follow)
+int
+pioctl_utf8(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
{
return pioctl_int(pathp, opcode, blobp, follow, TRUE);
}
-long
-pioctl(char * pathp, long opcode, struct ViceIoctl * blobp, int follow)
+int
+pioctl(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
{
return pioctl_int(pathp, opcode, blobp, follow, FALSE);
}