e5e4a4d1a1f846d9881abc4bdc075e52b75c50f2
[openafs.git] / src / sys / pioctl_nt.c
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 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #include <windows.h>
17 #include <winioctl.h>
18 #include <winsock2.h>
19 #define SECURITY_WIN32
20 #include <security.h>
21 #include <nb30.h>
22 #include <tchar.h>
23 #include <strsafe.h>
24
25 #include <osi.h>
26
27 #include <cm.h>
28 #include <cm_nls.h>
29 #include <cm_server.h>
30 #include <cm_cell.h>
31 #include <cm_user.h>
32 #include <cm_conn.h>
33 #include <cm_scache.h>
34 #include <cm_buf.h>
35 #include <cm_dir.h>
36 #include <cm_utils.h>
37 #include <cm_ioctl.h>
38 #include <smb_iocons.h>
39 #include <smb.h>
40 #include <pioctl_nt.h>
41 #include <WINNT/afsreg.h>
42 #include <lanahelper.h>
43
44 #include <krb5.h>
45 #include <..\WINNT\afsrdr\common\AFSUserDefines.h>
46 #include <..\WINNT\afsrdr\common\AFSUserIoctl.h>
47 #include <..\WINNT\afsrdr\common\AFSUserStructs.h>
48
49 static char AFSConfigKeyName[] = AFSREG_CLT_SVC_PARAM_SUBKEY;
50
51 static const char utf8_prefix[] = UTF8_PREFIX;
52 static const int  utf8_prefix_size = sizeof(utf8_prefix) -  sizeof(char);
53
54 #define FS_IOCTLREQUEST_MAXSIZE 8192
55 /* big structure for representing and storing an IOCTL request */
56 typedef struct fs_ioctlRequest {
57     char *mp;                   /* marshalling/unmarshalling ptr */
58     long nbytes;                /* bytes received (when unmarshalling) */
59     char data[FS_IOCTLREQUEST_MAXSIZE]; /* data we're marshalling */
60 } fs_ioctlRequest_t;
61
62
63 static int
64 CMtoUNIXerror(int cm_code)
65 {
66     switch (cm_code) {
67     case CM_ERROR_TIMEDOUT:
68         return ETIMEDOUT;
69     case CM_ERROR_NOACCESS:
70         return EACCES;
71     case CM_ERROR_NOSUCHFILE:
72     case CM_ERROR_NOSUCHPATH:
73     case CM_ERROR_BPLUS_NOMATCH:
74         return ENOENT;
75     case CM_ERROR_INVAL:
76         return EINVAL;
77     case CM_ERROR_BADFD:
78         return EBADF;
79     case CM_ERROR_EXISTS:
80     case CM_ERROR_INEXACT_MATCH:
81         return EEXIST;
82     case CM_ERROR_CROSSDEVLINK:
83         return EXDEV;
84     case CM_ERROR_NOTDIR:
85         return ENOTDIR;
86     case CM_ERROR_ISDIR:
87         return EISDIR;
88     case CM_ERROR_READONLY:
89         return EROFS;
90     case CM_ERROR_WOULDBLOCK:
91         return EWOULDBLOCK;
92     case CM_ERROR_NOSUCHCELL:
93         return ESRCH;           /* hack */
94     case CM_ERROR_NOSUCHVOLUME:
95         return EPIPE;           /* hack */
96     case CM_ERROR_NOMORETOKENS:
97         return EDOM;            /* hack */
98     case CM_ERROR_TOOMANYBUFS:
99         return EFBIG;           /* hack */
100     case CM_ERROR_ALLBUSY:
101         return EBUSY;
102     case CM_ERROR_ALLDOWN:
103         return ENOSYS;          /* hack */
104     case CM_ERROR_ALLOFFLINE:
105         return ENXIO;           /* hack */
106     default:
107         if (cm_code > 0 && cm_code < EILSEQ)
108             return cm_code;
109         else
110             return ENOTTY;
111     }
112 }
113
114 static void
115 InitFSRequest(fs_ioctlRequest_t * rp)
116 {
117     rp->mp = rp->data;
118     rp->nbytes = 0;
119 }
120
121 static BOOL
122 IoctlDebug(void)
123 {
124     static int init = 0;
125     static BOOL debug = 0;
126
127     if ( !init ) {
128         HKEY hk;
129
130         if (RegOpenKey (HKEY_LOCAL_MACHINE,
131                          TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
132         {
133             DWORD dwSize = sizeof(BOOL);
134             DWORD dwType = REG_DWORD;
135             RegQueryValueEx (hk, TEXT("IoctlDebug"), NULL, &dwType, (PBYTE)&debug, &dwSize);
136             RegCloseKey (hk);
137         }
138
139         init = 1;
140     }
141
142     return debug;
143 }
144
145 static BOOL
146 RDR_Ready(void)
147 {
148     HANDLE hDevHandle = NULL;
149     DWORD bytesReturned;
150     AFSDriverStatusRespCB *respBuffer = NULL;
151     DWORD rc = 0;
152     BOOL ready = FALSE;
153
154     hDevHandle = CreateFileW( AFS_SYMLINK_W,
155                              GENERIC_READ | GENERIC_WRITE,
156                              FILE_SHARE_READ | FILE_SHARE_WRITE,
157                              NULL,
158                              OPEN_EXISTING,
159                              0,
160                              NULL);
161     if( hDevHandle == INVALID_HANDLE_VALUE)
162     {
163         DWORD gle = GetLastError();
164
165         if (gle && IoctlDebug() ) {
166             char buf[4096];
167             int saveerrno;
168
169             saveerrno = errno;
170             if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
171                                NULL,
172                                gle,
173                                MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
174                                buf,
175                                4096,
176                                (va_list *) NULL
177                                ) )
178             {
179                 fprintf(stderr,"RDR_Ready CreateFile(%S) failed: 0x%X\r\n\t[%s]\r\n",
180                         AFS_SYMLINK_W,gle,buf);
181             }
182             errno = saveerrno;
183         }
184         return FALSE;
185     }
186
187     //
188     // Allocate a response buffer.
189     //
190     respBuffer = (AFSDriverStatusRespCB *)malloc( sizeof( AFSDriverStatusRespCB));
191     if( respBuffer)
192     {
193
194         memset( respBuffer, '\0', sizeof( AFSDriverStatusRespCB));
195
196         if( !DeviceIoControl( hDevHandle,
197                               IOCTL_AFS_STATUS_REQUEST,
198                               NULL,
199                               0,
200                               (void *)respBuffer,
201                               sizeof( AFSDriverStatusRespCB),
202                               &bytesReturned,
203                               NULL))
204         {
205             //
206             // Error condition back from driver
207             //
208             DWORD gle = GetLastError();
209
210             if (gle && IoctlDebug() ) {
211                 char buf[4096];
212                 int saveerrno;
213
214                 saveerrno = errno;
215                 if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
216                                     NULL,
217                                     gle,
218                                     MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
219                                     buf,
220                                     4096,
221                                     (va_list *) NULL
222                                     ) )
223                 {
224                     fprintf(stderr,"RDR_Ready CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
225                              AFS_SYMLINK,gle,buf);
226                 }
227                 errno = saveerrno;
228             }
229             rc = -1;
230             goto cleanup;
231         }
232
233         if (bytesReturned == sizeof(AFSDriverStatusRespCB))
234         {
235             ready = ( respBuffer->Status == AFS_DRIVER_STATUS_READY );
236         }
237     } else
238         rc = ENOMEM;
239
240   cleanup:
241     if (respBuffer)
242         free( respBuffer);
243
244     if (hDevHandle != INVALID_HANDLE_VALUE)
245         CloseHandle(hDevHandle);
246
247     return ready;
248 }
249
250 static BOOL
251 DisableServiceManagerCheck(void)
252 {
253     static int init = 0;
254     static BOOL smcheck = 0;
255
256     if ( !init ) {
257         HKEY hk;
258
259         if (RegOpenKey (HKEY_LOCAL_MACHINE,
260                          TEXT("Software\\OpenAFS\\Client"), &hk) == 0)
261         {
262             DWORD dwSize = sizeof(BOOL);
263             DWORD dwType = REG_DWORD;
264             RegQueryValueEx (hk, TEXT("DisableIoctlSMCheck"), NULL, &dwType, (PBYTE)&smcheck, &dwSize);
265             RegCloseKey (hk);
266         }
267
268         init = 1;
269     }
270
271     return smcheck;
272 }
273
274 static DWORD
275 GetServiceStatus(
276     LPSTR lpszMachineName,
277     LPSTR lpszServiceName,
278     DWORD *lpdwCurrentState)
279 {
280     DWORD           hr               = NOERROR;
281     SC_HANDLE       schSCManager     = NULL;
282     SC_HANDLE       schService       = NULL;
283     DWORD           fdwDesiredAccess = 0;
284     SERVICE_STATUS  ssServiceStatus  = {0};
285     BOOL            fRet             = FALSE;
286
287     *lpdwCurrentState = 0;
288
289     fdwDesiredAccess = GENERIC_READ;
290
291     schSCManager = OpenSCManager(lpszMachineName,
292                                  NULL,
293                                  fdwDesiredAccess);
294
295     if(schSCManager == NULL)
296     {
297         hr = GetLastError();
298         goto cleanup;
299     }
300
301     schService = OpenService(schSCManager,
302                              lpszServiceName,
303                              fdwDesiredAccess);
304
305     if(schService == NULL)
306     {
307         hr = GetLastError();
308         goto cleanup;
309     }
310
311     fRet = QueryServiceStatus(schService,
312                               &ssServiceStatus);
313
314     if(fRet == FALSE)
315     {
316         hr = GetLastError();
317         goto cleanup;
318     }
319
320     *lpdwCurrentState = ssServiceStatus.dwCurrentState;
321
322 cleanup:
323
324     CloseServiceHandle(schService);
325     CloseServiceHandle(schSCManager);
326
327     return(hr);
328 }
329
330 static BOOL
331 UnicodeToANSI(LPCWSTR lpInputString, LPSTR lpszOutputString, int nOutStringLen)
332 {
333     CPINFO CodePageInfo;
334
335     GetCPInfo(CP_ACP, &CodePageInfo);
336
337     if (CodePageInfo.MaxCharSize > 1) {
338         // Only supporting non-Unicode strings
339         int reqLen = WideCharToMultiByte( CP_ACP, 0,
340                                           lpInputString, -1,
341                                           NULL, 0, NULL, NULL);
342         if ( reqLen > nOutStringLen)
343         {
344             return FALSE;
345         } else {
346             if (WideCharToMultiByte( CP_ACP,
347                                      WC_COMPOSITECHECK,
348                                      lpInputString, -1,
349                                      lpszOutputString,
350                                      nOutStringLen, NULL, NULL) == 0)
351                 return FALSE;
352         }
353     }
354     else
355     {
356         // Looks like unicode, better translate it
357         if (WideCharToMultiByte( CP_ACP,
358                                  WC_COMPOSITECHECK,
359                                  lpInputString, -1,
360                                  lpszOutputString,
361                                  nOutStringLen, NULL, NULL) == 0)
362             return FALSE;
363     }
364
365     return TRUE;
366 }
367
368 static BOOL
369 GetLSAPrincipalName(char * pszUser, DWORD dwUserSize)
370 {
371     KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
372     PKERB_RETRIEVE_TKT_RESPONSE pTicketResponse = NULL;
373     ULONG ResponseSize;
374     PKERB_EXTERNAL_NAME pClientName = NULL;
375     PUNICODE_STRING     pDomainName = NULL;
376     LSA_STRING Name;
377     HANDLE hLogon = INVALID_HANDLE_VALUE;
378     ULONG PackageId;
379     NTSTATUS ntStatus;
380     NTSTATUS ntSubStatus = 0;
381     WCHAR * wchUser = NULL;
382     DWORD   dwSize;
383     SHORT   sCount;
384     BOOL bRet = FALSE;
385
386     ntStatus = LsaConnectUntrusted( &hLogon);
387     if (FAILED(ntStatus))
388         goto cleanup;
389
390     Name.Buffer = MICROSOFT_KERBEROS_NAME_A;
391     Name.Length = (USHORT)(sizeof(MICROSOFT_KERBEROS_NAME_A) - sizeof(char));
392     Name.MaximumLength = Name.Length;
393
394     ntStatus = LsaLookupAuthenticationPackage( hLogon, &Name, &PackageId);
395     if (FAILED(ntStatus))
396         goto cleanup;
397
398     memset(&CacheRequest, 0, sizeof(KERB_QUERY_TKT_CACHE_REQUEST));
399     CacheRequest.MessageType = KerbRetrieveTicketMessage;
400     CacheRequest.LogonId.LowPart = 0;
401     CacheRequest.LogonId.HighPart = 0;
402
403     ntStatus = LsaCallAuthenticationPackage( hLogon,
404                                              PackageId,
405                                              &CacheRequest,
406                                              sizeof(CacheRequest),
407                                              &pTicketResponse,
408                                              &ResponseSize,
409                                              &ntSubStatus);
410     if (FAILED(ntStatus) || FAILED(ntSubStatus))
411         goto cleanup;
412
413     /* We have a ticket in the response */
414     pClientName = pTicketResponse->Ticket.ClientName;
415     pDomainName = &pTicketResponse->Ticket.DomainName;
416
417     /* We want to return ClientName @ DomainName */
418
419     dwSize = 0;
420     for ( sCount = 0; sCount < pClientName->NameCount; sCount++)
421     {
422         dwSize += pClientName->Names[sCount].Length;
423     }
424     dwSize += pDomainName->Length + sizeof(WCHAR);
425
426     if ( dwSize / sizeof(WCHAR) > dwUserSize )
427         goto cleanup;
428
429     wchUser = malloc(dwSize);
430     if (wchUser == NULL)
431         goto cleanup;
432
433     for ( sCount = 0, wchUser[0] = L'\0'; sCount < pClientName->NameCount; sCount++)
434     {
435         StringCbCatNW( wchUser, dwSize,
436                        pClientName->Names[sCount].Buffer,
437                        pClientName->Names[sCount].Length);
438     }
439     StringCbCatNW( wchUser, dwSize,
440                    pDomainName->Buffer,
441                    pDomainName->Length);
442
443     if ( !UnicodeToANSI( wchUser, pszUser, dwUserSize) )
444         goto cleanup;
445
446     bRet = TRUE;
447
448   cleanup:
449
450     if (wchUser)
451         free(wchUser);
452
453     if ( hLogon != INVALID_HANDLE_VALUE)
454         LsaDeregisterLogonProcess(hLogon);
455
456     if ( pTicketResponse ) {
457         SecureZeroMemory(pTicketResponse,ResponseSize);
458         LsaFreeReturnBuffer(pTicketResponse);
459     }
460
461     return bRet;
462 }
463
464 //
465 // Recursively evaluate drivestr to find the final
466 // dos drive letter to which the source is mapped.
467 //
468 static BOOL
469 DriveSubstitution(char *drivestr, char *subststr, size_t substlen)
470 {
471     char device[MAX_PATH];
472
473     if ( QueryDosDevice(drivestr, device, MAX_PATH) )
474     {
475         if ( device[0] == '\\' &&
476              device[1] == '?' &&
477              device[2] == '?' &&
478              device[3] == '\\' &&
479              isalpha(device[4]) &&
480              device[5] == ':')
481         {
482             device[0] = device[4];
483             device[1] = ':';
484             device[2] = '\0';
485             if ( DriveSubstitution(device, subststr, substlen) )
486             {
487                 return TRUE;
488             } else {
489                 subststr[0] = device[0];
490                 subststr[1] = ':';
491                 subststr[2] = '\0';
492                 return TRUE;
493             }
494         } else
495         if ( device[0] == '\\' &&
496              device[1] == '?' &&
497              device[2] == '?' &&
498              device[3] == '\\' &&
499              device[4] == 'U' &&
500              device[5] == 'N' &&
501              device[6] == 'C' &&
502              device[7] == '\\')
503         {
504              subststr[0] = '\\';
505              strncpy(&subststr[1], &device[7], substlen-1);
506              subststr[substlen-1] = '\0';
507              return TRUE;
508         }
509     }
510
511     return FALSE;
512 }
513
514 //
515 // drivestr - is "<drive-letter>:"
516 //
517 static BOOL
518 DriveIsMappedToAFS(char *drivestr, char *NetbiosName)
519 {
520     DWORD dwResult, dwResultEnum;
521     HANDLE hEnum;
522     DWORD cbBuffer = 16384;     // 16K is a good size
523     DWORD cEntries = -1;        // enumerate all possible entries
524     LPNETRESOURCE lpnrLocal;    // pointer to enumerated structures
525     DWORD i;
526     BOOL  bIsAFS = FALSE;
527     char  subststr[MAX_PATH];
528     char  device[MAX_PATH];
529
530     //
531     // Handle drive letter substitution created with "SUBST <drive> <path>".
532     // If a substitution has occurred, use the target drive letter instead
533     // of the source.
534     //
535     if ( DriveSubstitution(drivestr, subststr, MAX_PATH) )
536     {
537         if (subststr[0] == '\\' &&
538             subststr[1] == '\\')
539         {
540             if (_strnicmp( &subststr[2], NetbiosName, strlen(NetbiosName)) == 0)
541                 return TRUE;
542             else
543                 return FALSE;
544         }
545         drivestr = subststr;
546     }
547
548     //
549     // Check for \Device\AFSRedirector
550     //
551     if (QueryDosDevice(drivestr, device, MAX_PATH) &&
552         _strnicmp( device, "\\Device\\AFSRedirector", strlen("\\Device\\AFSRedirector")) == 0) {
553         return TRUE;
554     }
555
556     //
557     // Call the WNetOpenEnum function to begin the enumeration.
558     //
559     dwResult = WNetOpenEnum(RESOURCE_CONNECTED,
560                             RESOURCETYPE_DISK,
561                             RESOURCEUSAGE_ALL,
562                             NULL,       // NULL first time the function is called
563                             &hEnum);    // handle to the resource
564
565     if (dwResult != NO_ERROR)
566         return FALSE;
567
568     //
569     // Call the GlobalAlloc function to allocate resources.
570     //
571     lpnrLocal = (LPNETRESOURCE) GlobalAlloc(GPTR, cbBuffer);
572     if (lpnrLocal == NULL)
573         return FALSE;
574
575     do {
576         //
577         // Initialize the buffer.
578         //
579         ZeroMemory(lpnrLocal, cbBuffer);
580         //
581         // Call the WNetEnumResource function to continue
582         //  the enumeration.
583         //
584         cEntries = -1;
585         dwResultEnum = WNetEnumResource(hEnum,          // resource handle
586                                         &cEntries,      // defined locally as -1
587                                         lpnrLocal,      // LPNETRESOURCE
588                                         &cbBuffer);     // buffer size
589         //
590         // If the call succeeds, loop through the structures.
591         //
592         if (dwResultEnum == NO_ERROR) {
593             for (i = 0; i < cEntries; i++) {
594                 if (lpnrLocal[i].lpLocalName &&
595                     toupper(lpnrLocal[i].lpLocalName[0]) == toupper(drivestr[0])) {
596                     //
597                     // Skip the two backslashes at the start of the UNC device name
598                     //
599                     if ( _strnicmp( &(lpnrLocal[i].lpRemoteName[2]), NetbiosName, strlen(NetbiosName)) == 0 )
600                     {
601                         bIsAFS = TRUE;
602                         break;
603                     }
604                 }
605             }
606         }
607         // Process errors.
608         //
609         else if (dwResultEnum != ERROR_NO_MORE_ITEMS)
610             break;
611     }
612     while (dwResultEnum != ERROR_NO_MORE_ITEMS);
613
614     //
615     // Call the GlobalFree function to free the memory.
616     //
617     GlobalFree((HGLOBAL) lpnrLocal);
618     //
619     // Call WNetCloseEnum to end the enumeration.
620     //
621     dwResult = WNetCloseEnum(hEnum);
622
623     return bIsAFS;
624 }
625
626 static BOOL
627 DriveIsGlobalAutoMapped(char *drivestr)
628 {
629     DWORD dwResult;
630     HKEY hKey;
631     DWORD dwSubMountSize;
632     char szSubMount[260];
633     DWORD dwType;
634
635     dwResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
636                             AFSREG_CLT_SVC_PARAM_SUBKEY "\\GlobalAutoMapper",
637                             0, KEY_QUERY_VALUE, &hKey);
638     if (dwResult != ERROR_SUCCESS)
639         return FALSE;
640
641     dwSubMountSize = sizeof(szSubMount);
642     dwType = REG_SZ;
643     dwResult = RegQueryValueEx(hKey, drivestr, 0, &dwType, szSubMount, &dwSubMountSize);
644     RegCloseKey(hKey);
645
646     if (dwResult == ERROR_SUCCESS && dwType == REG_SZ)
647         return TRUE;
648     else
649         return FALSE;
650 }
651
652 static long
653 GetIoctlHandle(char *fileNamep, HANDLE * handlep)
654 {
655     HKEY hk;
656     char *drivep = NULL;
657     char netbiosName[MAX_NB_NAME_LENGTH]="AFS";
658     DWORD CurrentState = 0;
659     char  HostName[64] = "";
660     char tbuffer[MAX_PATH]="";
661     HANDLE fh;
662     char szUser[128] = "";
663     char szClient[MAX_PATH] = "";
664     char szPath[MAX_PATH] = "";
665     NETRESOURCE nr;
666     DWORD res;
667     DWORD ioctlDebug = IoctlDebug();
668     DWORD gle;
669     DWORD dwSize = sizeof(szUser);
670     BOOL  usingRDR = FALSE;
671     int saveerrno;
672     UINT driveType;
673     int sharingViolation;
674
675     memset(HostName, '\0', sizeof(HostName));
676     gethostname(HostName, sizeof(HostName));
677     if (!DisableServiceManagerCheck() &&
678         GetServiceStatus(HostName, TEXT("TransarcAFSDaemon"), &CurrentState) == NOERROR &&
679         CurrentState != SERVICE_RUNNING)
680     {
681         if ( ioctlDebug ) {
682             saveerrno = errno;
683             fprintf(stderr, "pioctl GetServiceStatus(%s) == %d\r\n",
684                     HostName, CurrentState);
685             errno = saveerrno;
686         }
687         return -1;
688     }
689
690     if (RDR_Ready()) {
691         usingRDR = TRUE;
692
693         if ( ioctlDebug ) {
694             saveerrno = errno;
695             fprintf(stderr, "pioctl Redirector is ready\r\n");
696             errno = saveerrno;
697         }
698
699         if (RegOpenKey (HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, &hk) == 0)
700         {
701             DWORD dwSize = sizeof(netbiosName);
702             DWORD dwType = REG_SZ;
703             RegQueryValueExA (hk, "NetbiosName", NULL, &dwType, (PBYTE)netbiosName, &dwSize);
704             RegCloseKey (hk);
705
706             if ( ioctlDebug ) {
707                 saveerrno = errno;
708                 fprintf(stderr, "pioctl NetbiosName = \"%s\"\r\n", netbiosName);
709                 errno = saveerrno;
710             }
711         } else {
712             if ( ioctlDebug ) {
713                 saveerrno = errno;
714                 gle = GetLastError();
715                 fprintf(stderr, "pioctl Unable to open \"HKLM\\%s\" using NetbiosName = \"AFS\" GLE=0x%x\r\n",
716                         HostName, CurrentState, gle);
717                 errno = saveerrno;
718             }
719         }
720     } else {
721         if ( ioctlDebug ) {
722             saveerrno = errno;
723             fprintf(stderr, "pioctl Redirector is not ready\r\n");
724             errno = saveerrno;
725         }
726
727         if (!GetEnvironmentVariable("AFS_PIOCTL_SERVER", netbiosName, sizeof(netbiosName)))
728             lana_GetNetbiosName(netbiosName,LANA_NETBIOS_NAME_FULL);
729
730         if ( ioctlDebug ) {
731             saveerrno = errno;
732             fprintf(stderr, "pioctl NetbiosName = \"%s\"\r\n", netbiosName);
733             errno = saveerrno;
734         }
735     }
736
737     if (fileNamep) {
738         drivep = strchr(fileNamep, ':');
739         if (drivep && (drivep - fileNamep) >= 1) {
740             tbuffer[0] = *(drivep - 1);
741             tbuffer[1] = ':';
742             tbuffer[2] = '\0';
743
744             driveType = GetDriveType(tbuffer);
745             switch (driveType) {
746             case DRIVE_UNKNOWN:
747             case DRIVE_REMOTE:
748                 if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
749                     DriveIsGlobalAutoMapped(tbuffer))
750                     strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
751                 else
752                     return -1;
753                 break;
754             default:
755                 if (DriveIsGlobalAutoMapped(tbuffer))
756                     strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
757                 else
758                     return -1;
759             }
760         } else if (fileNamep[0] == fileNamep[1] &&
761                    (fileNamep[0] == '\\' || fileNamep[0] == '/'))
762         {
763             int count = 0, i = 0;
764
765             while (count < 4 && fileNamep[i]) {
766                 tbuffer[i] = fileNamep[i];
767                 if ( tbuffer[i] == '\\' ||
768                      tbuffer[i] == '/')
769                     count++;
770                 i++;
771             }
772             if (fileNamep[i] == 0 || (fileNamep[i-1] != '\\' && fileNamep[i-1] != '/'))
773                 tbuffer[i++] = '\\';
774             tbuffer[i] = 0;
775             strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
776         } else {
777             char curdir[MAX_PATH]="";
778
779             GetCurrentDirectory(sizeof(curdir), curdir);
780             if ( curdir[1] == ':' ) {
781                 tbuffer[0] = curdir[0];
782                 tbuffer[1] = ':';
783                 tbuffer[2] = '\0';
784
785                 driveType = GetDriveType(tbuffer);
786                 switch (driveType) {
787                 case DRIVE_UNKNOWN:
788                 case DRIVE_REMOTE:
789                     if (DriveIsMappedToAFS(tbuffer, netbiosName) ||
790                         DriveIsGlobalAutoMapped(tbuffer))
791                         strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
792                     else
793                         return -1;
794                     break;
795                 default:
796                     if (DriveIsGlobalAutoMapped(tbuffer))
797                         strcpy(&tbuffer[2], SMB_IOCTL_FILENAME);
798                     else
799                         return -1;
800                 }
801             } else if (curdir[0] == curdir[1] &&
802                        (curdir[0] == '\\' || curdir[0] == '/'))
803             {
804                 int count = 0, i = 0;
805
806                 while (count < 4 && curdir[i]) {
807                     tbuffer[i] = curdir[i];
808                     if ( tbuffer[i] == '\\' ||
809                          tbuffer[i] == '/')
810                         count++;
811                     i++;
812                 }
813                 if (curdir[i] == 0 || (curdir[i-1] != '\\' && curdir[i-1] != '/'))
814                     tbuffer[i++] = '\\';
815                 tbuffer[i] = 0;
816                 strcat(tbuffer, SMB_IOCTL_FILENAME_NOSLASH);
817             }
818         }
819     }
820     if (!tbuffer[0]) {
821         /* No file name starting with drive colon specified, use UNC name */
822         sprintf(tbuffer,"\\\\%s\\all%s",netbiosName,SMB_IOCTL_FILENAME);
823     }
824
825     if ( ioctlDebug ) {
826         saveerrno = errno;
827         fprintf(stderr, "pioctl filename = \"%s\"\r\n", tbuffer);
828         errno = saveerrno;
829     }
830
831     fflush(stdout);
832     /* now open the file */
833     sharingViolation = 0;
834     do {
835         if (sharingViolation)
836             Sleep(100);
837         fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
838                         FILE_SHARE_READ, NULL, OPEN_EXISTING,
839                         FILE_FLAG_WRITE_THROUGH, NULL);
840         sharingViolation++;
841     } while (fh == INVALID_HANDLE_VALUE &&
842              GetLastError() == ERROR_SHARING_VIOLATION &&
843              sharingViolation < 100);
844     fflush(stdout);
845
846     if (fh == INVALID_HANDLE_VALUE) {
847         gle = GetLastError();
848         if (gle && ioctlDebug ) {
849             char buf[4096];
850
851             saveerrno = errno;
852             if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
853                                NULL,
854                                gle,
855                                MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
856                                buf,
857                                4096,
858                                (va_list *) NULL
859                                ) )
860             {
861                 fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
862                         tbuffer,gle,buf);
863             }
864             errno = saveerrno;
865             SetLastError(gle);
866         }
867     }
868
869     if (fh == INVALID_HANDLE_VALUE &&
870         GetLastError() != ERROR_SHARING_VIOLATION) {
871         int  gonext = 0;
872
873         /* with the redirector interface, fail immediately.  there is nothing to retry */
874         if (usingRDR)
875             return -1;
876
877         if (!GetEnvironmentVariable("AFS_PIOCTL_SERVER", szClient, sizeof(szClient)))
878             lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
879
880         if (RegOpenKey (HKEY_CURRENT_USER,
881                          TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"), &hk) == 0)
882         {
883             DWORD dwType = REG_SZ;
884             RegQueryValueEx (hk, TEXT("Logon User Name"), NULL, &dwType, (PBYTE)szUser, &dwSize);
885             RegCloseKey (hk);
886         }
887
888         if ( szUser[0] ) {
889             if ( ioctlDebug ) {
890                 saveerrno = errno;
891                 fprintf(stderr, "pioctl Explorer logon user: [%s]\r\n",szUser);
892                 errno = saveerrno;
893             }
894             sprintf(szPath, "\\\\%s", szClient);
895             memset (&nr, 0x00, sizeof(NETRESOURCE));
896             nr.dwType=RESOURCETYPE_DISK;
897             nr.lpLocalName=0;
898             nr.lpRemoteName=szPath;
899             res = WNetAddConnection2(&nr,NULL,szUser,0);
900             if (res) {
901                 if ( ioctlDebug ) {
902                     saveerrno = errno;
903                     fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
904                              szPath,szUser,res);
905                     errno = saveerrno;
906                 }
907                 gonext = 1;
908             }
909
910             sprintf(szPath, "\\\\%s\\all", szClient);
911             res = WNetAddConnection2(&nr,NULL,szUser,0);
912             if (res) {
913                 if ( ioctlDebug ) {
914                     saveerrno = errno;
915                     fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
916                              szPath,szUser,res);
917                     errno = saveerrno;
918                 }
919                 gonext = 1;
920             }
921
922             if (gonext)
923                 goto try_lsa_principal;
924
925             sharingViolation = 0;
926             do {
927                 if (sharingViolation)
928                     Sleep(100);
929                 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
930                                 FILE_SHARE_READ, NULL, OPEN_EXISTING,
931                                 FILE_FLAG_WRITE_THROUGH, NULL);
932                 sharingViolation++;
933             } while (fh == INVALID_HANDLE_VALUE &&
934                      GetLastError() == ERROR_SHARING_VIOLATION &&
935                      sharingViolation < 100);
936             fflush(stdout);
937             if (fh == INVALID_HANDLE_VALUE) {
938                 gle = GetLastError();
939                 if (gle && ioctlDebug ) {
940                     char buf[4096];
941
942                     saveerrno = errno;
943                     if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
944                                         NULL,
945                                         gle,
946                                         MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
947                                         buf,
948                                         4096,
949                                         (va_list *) NULL
950                                         ) )
951                     {
952                         fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
953                                  tbuffer,gle,buf);
954                     }
955                     errno = saveerrno;
956                     SetLastError(gle);
957                 }
958             }
959         }
960     }
961
962   try_lsa_principal:
963     if (!usingRDR &&
964         fh == INVALID_HANDLE_VALUE &&
965         GetLastError() != ERROR_SHARING_VIOLATION) {
966         int  gonext = 0;
967
968         dwSize = sizeof(szUser);
969         if (GetLSAPrincipalName(szUser, dwSize)) {
970             if ( ioctlDebug ) {
971                 saveerrno = errno;
972                 fprintf(stderr, "pioctl LSA Principal logon user: [%s]\r\n",szUser);
973                 errno = saveerrno;
974             }
975             sprintf(szPath, "\\\\%s", szClient);
976             memset (&nr, 0x00, sizeof(NETRESOURCE));
977             nr.dwType=RESOURCETYPE_DISK;
978             nr.lpLocalName=0;
979             nr.lpRemoteName=szPath;
980             res = WNetAddConnection2(&nr,NULL,szUser,0);
981             if (res) {
982                 if ( ioctlDebug ) {
983                     saveerrno = errno;
984                     fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
985                              szPath,szUser,res);
986                     errno = saveerrno;
987                 }
988                 gonext = 1;
989             }
990
991             sprintf(szPath, "\\\\%s\\all", szClient);
992             res = WNetAddConnection2(&nr,NULL,szUser,0);
993             if (res) {
994                 if ( ioctlDebug ) {
995                     saveerrno = errno;
996                     fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
997                              szPath,szUser,res);
998                     errno = saveerrno;
999                 }
1000                 gonext = 1;
1001             }
1002
1003             if (gonext)
1004                 goto try_sam_compat;
1005
1006             sharingViolation = 0;
1007             do {
1008                 if (sharingViolation)
1009                     Sleep(100);
1010                 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
1011                                 FILE_SHARE_READ, NULL, OPEN_EXISTING,
1012                                 FILE_FLAG_WRITE_THROUGH, NULL);
1013                 sharingViolation++;
1014             } while (fh == INVALID_HANDLE_VALUE &&
1015                      GetLastError() == ERROR_SHARING_VIOLATION &&
1016                      sharingViolation < 100);
1017             fflush(stdout);
1018             if (fh == INVALID_HANDLE_VALUE) {
1019                 gle = GetLastError();
1020                 if (gle && ioctlDebug ) {
1021                     char buf[4096];
1022
1023                     saveerrno = errno;
1024                     if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1025                                         NULL,
1026                                         gle,
1027                                         MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
1028                                         buf,
1029                                         4096,
1030                                         (va_list *) NULL
1031                                         ) )
1032                     {
1033                         fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
1034                                  tbuffer,gle,buf);
1035                     }
1036                     errno = saveerrno;
1037                     SetLastError(gle);
1038                 }
1039             }
1040         }
1041     }
1042
1043   try_sam_compat:
1044     if (!usingRDR &&
1045         fh == INVALID_HANDLE_VALUE &&
1046         GetLastError() != ERROR_SHARING_VIOLATION) {
1047         dwSize = sizeof(szUser);
1048         if (GetUserNameEx(NameSamCompatible, szUser, &dwSize)) {
1049             if ( ioctlDebug ) {
1050                 saveerrno = errno;
1051                 fprintf(stderr, "pioctl SamCompatible logon user: [%s]\r\n",szUser);
1052                 errno = saveerrno;
1053             }
1054             sprintf(szPath, "\\\\%s", szClient);
1055             memset (&nr, 0x00, sizeof(NETRESOURCE));
1056             nr.dwType=RESOURCETYPE_DISK;
1057             nr.lpLocalName=0;
1058             nr.lpRemoteName=szPath;
1059             res = WNetAddConnection2(&nr,NULL,szUser,0);
1060             if (res) {
1061                 if ( ioctlDebug ) {
1062                     saveerrno = errno;
1063                     fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
1064                              szPath,szUser,res);
1065                     errno = saveerrno;
1066                 }
1067             }
1068
1069             sprintf(szPath, "\\\\%s\\all", szClient);
1070             res = WNetAddConnection2(&nr,NULL,szUser,0);
1071             if (res) {
1072                 if ( ioctlDebug ) {
1073                     saveerrno = errno;
1074                     fprintf(stderr, "pioctl WNetAddConnection2(%s,%s) failed: 0x%X\r\n",
1075                              szPath,szUser,res);
1076                     errno = saveerrno;
1077                 }
1078                 return -1;
1079             }
1080
1081             sharingViolation = 0;
1082             do {
1083                 if (sharingViolation)
1084                     Sleep(100);
1085                 fh = CreateFile(tbuffer, FILE_READ_DATA | FILE_WRITE_DATA,
1086                                 FILE_SHARE_READ, NULL, OPEN_EXISTING,
1087                                 FILE_FLAG_WRITE_THROUGH, NULL);
1088                 sharingViolation++;
1089             } while (fh == INVALID_HANDLE_VALUE &&
1090                      GetLastError() == ERROR_SHARING_VIOLATION &&
1091                      sharingViolation < 100);
1092             fflush(stdout);
1093             if (fh == INVALID_HANDLE_VALUE) {
1094                 gle = GetLastError();
1095                 if (gle && ioctlDebug ) {
1096                     char buf[4096];
1097
1098                     saveerrno = errno;
1099                     if ( FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1100                                         NULL,
1101                                         gle,
1102                                         MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
1103                                         buf,
1104                                         4096,
1105                                         (va_list *) NULL
1106                                         ) )
1107                     {
1108                         fprintf(stderr,"pioctl CreateFile(%s) failed: 0x%X\r\n\t[%s]\r\n",
1109                                  tbuffer,gle,buf);
1110                     }
1111                     errno = saveerrno;
1112                 }
1113                 return -1;
1114             }
1115         } else {
1116             fprintf(stderr, "GetUserNameEx(NameSamCompatible) failed: 0x%X\r\n", GetLastError());
1117             return -1;
1118         }
1119     }
1120
1121     if (fh == INVALID_HANDLE_VALUE)
1122         return -1;
1123
1124     /* return fh and success code */
1125     *handlep = fh;
1126     return 0;
1127 }
1128
1129 static long
1130 Transceive(HANDLE handle, fs_ioctlRequest_t * reqp)
1131 {
1132     long rcount;
1133     long ioCount;
1134     DWORD gle;
1135     DWORD ioctlDebug = IoctlDebug();
1136     int save;
1137
1138     rcount = (long)(reqp->mp - reqp->data);
1139     if (rcount <= 0) {
1140         if ( ioctlDebug ) {
1141             save = errno;
1142             fprintf(stderr, "pioctl Transceive rcount <= 0: %d\r\n",rcount);
1143             errno = save;
1144         }
1145         return EINVAL;          /* not supposed to happen */
1146     }
1147
1148     if (!WriteFile(handle, reqp->data, rcount, &ioCount, NULL)) {
1149         /* failed to write */
1150         gle = GetLastError();
1151
1152         if ( ioctlDebug ) {
1153             save = errno;
1154             fprintf(stderr, "pioctl Transceive WriteFile failed: 0x%X\r\n",gle);
1155             errno = save;
1156         }
1157         return gle;
1158     }
1159
1160     if (!ReadFile(handle, reqp->data, sizeof(reqp->data), &ioCount, NULL)) {
1161         /* failed to read */
1162         gle = GetLastError();
1163
1164         if ( ioctlDebug ) {
1165             save = errno;
1166             fprintf(stderr, "pioctl Transceive ReadFile failed: 0x%X\r\n",gle);
1167             errno = save;
1168         }
1169         return gle;
1170     }
1171
1172     reqp->nbytes = ioCount;     /* set # of bytes available */
1173     reqp->mp = reqp->data;      /* restart marshalling */
1174
1175     /* return success */
1176     return 0;
1177 }
1178
1179 static long
1180 MarshallLong(fs_ioctlRequest_t * reqp, long val)
1181 {
1182     memcpy(reqp->mp, &val, 4);
1183     reqp->mp += 4;
1184     return 0;
1185 }
1186
1187 static long
1188 UnmarshallLong(fs_ioctlRequest_t * reqp, long *valp)
1189 {
1190     int save;
1191
1192     /* not enough data left */
1193     if (reqp->nbytes < 4) {
1194         if ( IoctlDebug() ) {
1195             save = errno;
1196             fprintf(stderr, "pioctl UnmarshallLong reqp->nbytes < 4: %d\r\n",
1197                      reqp->nbytes);
1198             errno = save;
1199         }
1200         return -1;
1201     }
1202
1203     memcpy(valp, reqp->mp, 4);
1204     reqp->mp += 4;
1205     reqp->nbytes -= 4;
1206     return 0;
1207 }
1208
1209 /* includes marshalling NULL pointer as a null (0 length) string */
1210 static long
1211 MarshallString(fs_ioctlRequest_t * reqp, char *stringp, int is_utf8)
1212 {
1213     int count;
1214     int save;
1215
1216     if (stringp)
1217         count = (int)strlen(stringp) + 1;/* space required including null */
1218     else
1219         count = 1;
1220
1221     if (is_utf8) {
1222         count += utf8_prefix_size;
1223     }
1224
1225     /* watch for buffer overflow */
1226     if ((reqp->mp - reqp->data) + count > sizeof(reqp->data)) {
1227         if ( IoctlDebug() ) {
1228             save = errno;
1229             fprintf(stderr, "pioctl MarshallString buffer overflow\r\n");
1230             errno = save;
1231         }
1232         return -1;
1233     }
1234
1235     if (is_utf8) {
1236         memcpy(reqp->mp, utf8_prefix, utf8_prefix_size);
1237         reqp->mp += utf8_prefix_size;
1238         count -= utf8_prefix_size;
1239     }
1240
1241     if (stringp)
1242         memcpy(reqp->mp, stringp, count);
1243     else
1244         *(reqp->mp) = 0;
1245     reqp->mp += count;
1246     return 0;
1247 }
1248
1249 /* take a path with a drive letter, possibly relative, and return a full path
1250  * without the drive letter.  This is the full path relative to the working
1251  * dir for that drive letter.  The input and output paths can be the same.
1252  */
1253 static long
1254 fs_GetFullPath(char *pathp, char *outPathp, long outSize)
1255 {
1256     char tpath[1000];
1257     char origPath[1000];
1258     char *firstp;
1259     long code;
1260     int pathHasDrive;
1261     int doSwitch;
1262     char newPath[3];
1263     char * p;
1264     int save;
1265
1266     if (pathp[0] != 0 && pathp[1] == ':') {
1267         /* there's a drive letter there */
1268         firstp = pathp + 2;
1269         pathHasDrive = 1;
1270     } else {
1271         firstp = pathp;
1272         pathHasDrive = 0;
1273     }
1274
1275     if ( firstp[0] == '\\' && firstp[1] == '\\' ||
1276          firstp[0] == '/' && firstp[1] == '/') {
1277         /* UNC path - strip off the server and sharename */
1278         int i, count;
1279         for ( i=2,count=2; count < 4 && firstp[i]; i++ ) {
1280             if ( firstp[i] == '\\' || firstp[i] == '/' ) {
1281                 count++;
1282             }
1283         }
1284         if ( firstp[i] == 0 ) {
1285             strcpy(outPathp,"\\");
1286         } else {
1287             strcpy(outPathp,&firstp[--i]);
1288         }
1289         for (p=outPathp ;*p; p++) {
1290             if (*p == '/')
1291                 *p = '\\';
1292         }
1293         return 0;
1294     } else if (firstp[0] == '\\' || firstp[0] == '/') {
1295         /* already an absolute pathname, just copy it back */
1296         strcpy(outPathp, firstp);
1297         for (p=outPathp ;*p; p++) {
1298             if (*p == '/')
1299                 *p = '\\';
1300         }
1301         return 0;
1302     }
1303
1304     GetCurrentDirectory(sizeof(origPath), origPath);
1305
1306     doSwitch = 0;
1307     if (pathHasDrive && (*pathp & ~0x20) != (origPath[0] & ~0x20)) {
1308         /* a drive has been specified and it isn't our current drive.
1309          * to get path, switch to it first.  Must case-fold drive letters
1310          * for user convenience.
1311          */
1312         doSwitch = 1;
1313         newPath[0] = *pathp;
1314         newPath[1] = ':';
1315         newPath[2] = 0;
1316         if (!SetCurrentDirectory(newPath)) {
1317             code = GetLastError();
1318
1319             if ( IoctlDebug() ) {
1320                 save = errno;
1321                 fprintf(stderr, "pioctl fs_GetFullPath SetCurrentDirectory(%s) failed: 0x%X\r\n",
1322                          newPath, code);
1323                 errno = save;
1324             }
1325             return code;
1326         }
1327     }
1328
1329     /* now get the absolute path to the current wdir in this drive */
1330     GetCurrentDirectory(sizeof(tpath), tpath);
1331     if (tpath[1] == ':')
1332         strcpy(outPathp, tpath + 2);    /* skip drive letter */
1333     else if ( tpath[0] == '\\' && tpath[1] == '\\'||
1334               tpath[0] == '/' && tpath[1] == '/') {
1335         /* UNC path - strip off the server and sharename */
1336         int i, count;
1337         for ( i=2,count=2; count < 4 && tpath[i]; i++ ) {
1338             if ( tpath[i] == '\\' || tpath[i] == '/' ) {
1339                 count++;
1340             }
1341         }
1342         if ( tpath[i] == 0 ) {
1343             strcpy(outPathp,"\\");
1344         } else {
1345             strcpy(outPathp,&tpath[--i]);
1346         }
1347     } else {
1348         /* this should never happen */
1349         strcpy(outPathp, tpath);
1350     }
1351
1352     /* if there is a non-null name after the drive, append it */
1353     if (*firstp != 0) {
1354         int len = (int)strlen(outPathp);
1355         if (outPathp[len-1] != '\\' && outPathp[len-1] != '/')
1356             strcat(outPathp, "\\");
1357         strcat(outPathp, firstp);
1358     }
1359
1360     /* finally, if necessary, switch back to our home drive letter */
1361     if (doSwitch) {
1362         SetCurrentDirectory(origPath);
1363     }
1364
1365     for (p=outPathp ;*p; p++) {
1366         if (*p == '/')
1367             *p = '\\';
1368     }
1369     return 0;
1370 }
1371
1372 static int
1373 pioctl_int(char *pathp, afs_int32 opcode, struct ViceIoctl *blobp, afs_int32 follow, afs_int32 is_utf8)
1374 {
1375     fs_ioctlRequest_t preq;
1376     long code;
1377     long temp;
1378     char fullPath[1000];
1379     char altPath[1024];
1380     HANDLE reqHandle;
1381     int save;
1382     int i,j,count,all;
1383
1384     /*
1385      * The pioctl operations for creating a mount point and a symlink are broken.
1386      * Instead of 'pathp' referring to the directory object in which the symlink
1387      * or mount point within which the new object is to be created, 'pathp' refers
1388      * to the object itself.  This results in a problem when the object being created
1389      * is located within the Freelance root.afs volume.  \\afs\foo will not be a
1390      * valid share name since the 'foo' object does not yet exist.  Therefore,
1391      * \\afs\foo\_._.afs_ioctl_._ cannot be opened.  Instead in these two cases
1392      * we must force the use of the \\afs\all\foo form of the path.
1393      *
1394      * We cannot use this form in all cases because of smb submounts which are
1395      * not located within the Freelance local root.
1396      */
1397     switch ( opcode ) {
1398     case VIOC_AFS_CREATE_MT_PT:
1399     case VIOC_SYMLINK:
1400         if (pathp &&
1401              (pathp[0] == '\\' && pathp[1] == '\\' ||
1402               pathp[0] == '/' && pathp[1] == '/')) {
1403             for (all = count = j = 0; pathp[j]; j++) {
1404                 if (pathp[j] == '\\' || pathp[j] == '/')
1405                     count++;
1406
1407                 /* Test to see if the second component is 'all' */
1408                 if (count == 3) {
1409                     all = 1;
1410                     for (i=0; pathp[i+j]; i++) {
1411                         switch(i) {
1412                         case 0:
1413                             if (pathp[i+j] != 'a' &&
1414                                 pathp[i+j] != 'A') {
1415                                 all = 0;
1416                                 goto notall;
1417                             }
1418                             break;
1419                         case 1:
1420                         case 2:
1421                             if (pathp[i+j] != 'l' &&
1422                                  pathp[i+j] != 'L') {
1423                                 all = 0;
1424                                 goto notall;
1425                             }
1426                             break;
1427                         default:
1428                             all = 0;
1429                             goto notall;
1430                         }
1431                     }
1432                     if (i != 3)
1433                         all = 0;
1434                 }
1435
1436               notall:
1437                 if (all)
1438                     break;
1439             }
1440
1441             /*
1442              * if count is three and the second component is not 'all',
1443              * then we are attempting to create an object in the
1444              * Freelance root.afs volume.  Substitute the path.
1445              */
1446
1447             if (count == 3 && !all) {
1448                 /* Normalize the name to use \\afs\all as the root */
1449                 for (count = i = j = 0; pathp[j] && i < sizeof(altPath); j++) {
1450                     if (pathp[j] == '\\' || pathp[j] == '/') {
1451                         altPath[i++] = '\\';
1452                         count++;
1453
1454                         if (count == 3) {
1455                             altPath[i++] = 'a';
1456                             altPath[i++] = 'l';
1457                             altPath[i++] = 'l';
1458                             altPath[i++] = '\\';
1459                             count++;
1460                         }
1461                     } else {
1462                         altPath[i++] = pathp[j];
1463                     }
1464                 }
1465                 altPath[i] = '\0';
1466                 pathp = altPath;
1467             }
1468         }
1469     }
1470
1471     code = GetIoctlHandle(pathp, &reqHandle);
1472     if (code) {
1473         if (pathp)
1474             errno = EINVAL;
1475         else
1476             errno = ENODEV;
1477         return code;
1478     }
1479
1480     /* init the request structure */
1481     InitFSRequest(&preq);
1482
1483     /* marshall the opcode, the path name and the input parameters */
1484     MarshallLong(&preq, opcode);
1485     /* when marshalling the path, remove the drive letter, since we already
1486      * used the drive letter to find the AFS daemon; we don't need it any more.
1487      * Eventually we'll expand relative path names here, too, since again, only
1488      * we understand those.
1489      */
1490     if (pathp) {
1491         code = fs_GetFullPath(pathp, fullPath, sizeof(fullPath));
1492         if (code) {
1493             CloseHandle(reqHandle);
1494             errno = EINVAL;
1495             return code;
1496         }
1497     } else {
1498         strcpy(fullPath, "");
1499     }
1500
1501     MarshallString(&preq, fullPath, is_utf8);
1502     if (blobp->in_size) {
1503         if (blobp->in_size > sizeof(preq.data) - (preq.mp - preq.data)*sizeof(char)) {
1504             errno = E2BIG;
1505             return -1;
1506         }
1507         memcpy(preq.mp, blobp->in, blobp->in_size);
1508         preq.mp += blobp->in_size;
1509     }
1510
1511     /* now make the call */
1512     code = Transceive(reqHandle, &preq);
1513     if (code) {
1514         CloseHandle(reqHandle);
1515         return code;
1516     }
1517
1518     /* now unmarshall the return value */
1519     if (UnmarshallLong(&preq, &temp) != 0) {
1520         CloseHandle(reqHandle);
1521         return -1;
1522     }
1523
1524     if (temp != 0) {
1525         CloseHandle(reqHandle);
1526         errno = CMtoUNIXerror(temp);
1527         if ( IoctlDebug() ) {
1528             save = errno;
1529             fprintf(stderr, "pioctl temp != 0: 0x%X\r\n",temp);
1530             errno = save;
1531         }
1532         return -1;
1533     }
1534
1535     /* otherwise, unmarshall the output parameters */
1536     if (blobp->out_size) {
1537         temp = blobp->out_size;
1538         if (preq.nbytes < temp)
1539             temp = preq.nbytes;
1540         memcpy(blobp->out, preq.mp, temp);
1541         blobp->out_size = temp;
1542     }
1543
1544     /* and return success */
1545     CloseHandle(reqHandle);
1546     return 0;
1547 }
1548
1549 int
1550 pioctl_utf8(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1551 {
1552     return pioctl_int(pathp, opcode, blobp, follow, TRUE);
1553 }
1554
1555 int
1556 pioctl(char * pathp, afs_int32 opcode, struct ViceIoctl * blobp, afs_int32 follow)
1557 {
1558     return pioctl_int(pathp, opcode, blobp, follow, FALSE);
1559 }
1560