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