Windows: do not leak space allocation
[openafs.git] / src / WINNT / afsd / smb3.c
1
2 /*
3  * Copyright 2000, International Business Machines Corporation and others.
4  * All Rights Reserved.
5  *
6  * This software has been released under the terms of the IBM Public
7  * License.  For details, see the LICENSE file in the top-level source
8  * directory or online at http://www.openafs.org/dl/license10.html
9  */
10
11 #include <afsconfig.h>
12 #include <afs/param.h>
13 #include <roken.h>
14
15 #include <afs/stds.h>
16
17 #include <windows.h>
18 #pragma warning(push)
19 #pragma warning(disable: 4005)
20 #include <ntstatus.h>
21 #define SECURITY_WIN32
22 #include <security.h>
23 #include <sddl.h>
24 #include <lmaccess.h>
25 #pragma warning(pop)
26 #include <stdlib.h>
27 #include <malloc.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <time.h>
31 #include <osi.h>
32
33 #include "afsd.h"
34 #include <WINNT\afsreg.h>
35
36 #include "smb.h"
37 #include "msrpc.h"
38 #include <strsafe.h>
39
40 extern osi_hyper_t hzero;
41
42 smb_packet_t *smb_Directory_Watches = NULL;
43 osi_mutex_t smb_Dir_Watch_Lock;
44
45 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
46
47 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
48
49 /* protected by the smb_globalLock */
50 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
51
52 const clientchar_t **smb_ExecutableExtensions = NULL;
53
54 /* retrieve a held reference to a user structure corresponding to an incoming
55  * request */
56 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
57 {
58     smb_user_t *uidp;
59     cm_user_t *up = NULL;
60
61     uidp = smb_FindUID(vcp, inp->uid, 0);
62     if (!uidp)
63         return NULL;
64
65     up = smb_GetUserFromUID(uidp);
66
67     smb_ReleaseUID(uidp);
68
69     return up;
70 }
71
72 /*
73  * Return boolean specifying if the path name is thought to be an
74  * executable file.  For now .exe or .dll.
75  */
76 afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
77 {
78     int i, j, len;
79
80     if ( smb_ExecutableExtensions == NULL || name == NULL)
81         return 0;
82
83     len = (int)cm_ClientStrLen(name);
84
85     for ( i=0; smb_ExecutableExtensions[i]; i++) {
86         j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
87         if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
88             return 1;
89     }
90
91     return 0;
92 }
93
94 /*
95  * Return extended attributes.
96  * Right now, we aren't using any of the "new" bits, so this looks exactly
97  * like smb_Attributes() (see smb.c).
98  */
99 unsigned long smb_ExtAttributes(cm_scache_t *scp)
100 {
101     unsigned long attrs;
102
103     if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
104         scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
105         scp->fileType == CM_SCACHETYPE_INVALID)
106     {
107         attrs = SMB_ATTR_DIRECTORY;
108 #ifdef SPECIAL_FOLDERS
109         attrs |= SMB_ATTR_SYSTEM;               /* FILE_ATTRIBUTE_SYSTEM */
110 #endif /* SPECIAL_FOLDERS */
111     } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
112         attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
113     } else if (scp->fid.vnode & 0x1)
114         attrs = SMB_ATTR_DIRECTORY;
115     else
116         attrs = 0;
117
118     /*
119      * We used to mark a file RO if it was in an RO volume, but that
120      * turns out to be impolitic in NT.  See defect 10007.
121      */
122 #ifdef notdef
123     if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
124         attrs |= SMB_ATTR_READONLY;             /* Read-only */
125 #else
126     if ((scp->unixModeBits & 0200) == 0)
127         attrs |= SMB_ATTR_READONLY;             /* Read-only */
128 #endif
129
130     if (attrs == 0)
131         attrs = SMB_ATTR_NORMAL;                /* FILE_ATTRIBUTE_NORMAL */
132
133     return attrs;
134 }
135
136 int smb_V3IsStarMask(clientchar_t *maskp)
137 {
138     clientchar_t tc;
139
140     while (tc = *maskp++)
141         if (tc == '?' || tc == '*' || tc == '<' || tc == '>')
142             return 1;
143     return 0;
144 }
145
146 void OutputDebugF(clientchar_t * format, ...) {
147     va_list args;
148     clientchar_t vbuffer[1024];
149
150     va_start( args, format );
151     cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
152     osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
153 }
154
155 void OutputDebugHexDump(unsigned char * buffer, int len) {
156     int i,j,k;
157     char buf[256];
158     static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
159
160     OutputDebugF(_C("Hexdump length [%d]"),len);
161
162     for (i=0;i<len;i++) {
163         if(!(i%16)) {
164             if(i) {
165                 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
166             }
167             StringCchPrintfA(buf, lengthof(buf), "%5x", i);
168             memset(buf+5,' ',80);
169             buf[85] = 0;
170         }
171
172         j = (i%16);
173         j = j*3 + 7 + ((j>7)?1:0);
174         k = buffer[i];
175
176         buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
177
178         j = (i%16);
179         j = j + 56 + ((j>7)?1:0);
180
181         buf[j] = (k>32 && k<127)?k:'.';
182     }
183     if(i) {
184         osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
185     }
186 }
187
188 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
189
190 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
191     SECURITY_STATUS status, istatus;
192     CredHandle creds = {0,0};
193     TimeStamp expiry;
194     SecBufferDesc secOut;
195     SecBuffer secTok;
196     CtxtHandle ctx;
197     ULONG flags;
198
199     *secBlob = NULL;
200     *secBlobLength = 0;
201
202     OutputDebugF(_C("Negotiating Extended Security"));
203
204     status = AcquireCredentialsHandle( NULL,
205                                        SMB_EXT_SEC_PACKAGE_NAME,
206                                        SECPKG_CRED_INBOUND,
207                                        NULL,
208                                        NULL,
209                                        NULL,
210                                        NULL,
211                                        &creds,
212                                        &expiry);
213
214     if (status != SEC_E_OK) {
215         /* Really bad. We return an empty security blob */
216         OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
217         goto nes_0;
218     }
219
220     secOut.cBuffers = 1;
221     secOut.pBuffers = &secTok;
222     secOut.ulVersion = SECBUFFER_VERSION;
223
224     secTok.BufferType = SECBUFFER_TOKEN;
225     secTok.cbBuffer = 0;
226     secTok.pvBuffer = NULL;
227
228     ctx.dwLower = ctx.dwUpper = 0;
229
230     status = AcceptSecurityContext( &creds,
231                                     NULL,
232                                     NULL,
233                                     ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
234                                     SECURITY_NETWORK_DREP,
235                                     &ctx,
236                                     &secOut,
237                                     &flags,
238                                     &expiry
239                                     );
240
241     if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
242         OutputDebugF(_C("Completing token..."));
243         istatus = CompleteAuthToken(&ctx, &secOut);
244         if ( istatus != SEC_E_OK )
245             OutputDebugF(_C("Token completion failed: %x"), istatus);
246     }
247
248     if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
249         if (secTok.pvBuffer) {
250             *secBlobLength = secTok.cbBuffer;
251             *secBlob = malloc( secTok.cbBuffer );
252             memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
253         }
254     } else {
255         if ( status != SEC_E_OK )
256             OutputDebugF(_C("AcceptSecurityContext status != CONTINUE  %lX"), status);
257     }
258
259     /* Discard partial security context */
260     DeleteSecurityContext(&ctx);
261
262     if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
263
264     /* Discard credentials handle.  We'll reacquire one when we get the session setup X */
265     FreeCredentialsHandle(&creds);
266
267   nes_0:
268     return;
269 }
270
271 afs_uint32
272 smb_GetLogonSID(HANDLE hToken, PSID *ppsid)
273 {
274     BOOL bSuccess = FALSE;
275     DWORD dwIndex;
276     DWORD dwLength = 0;
277     PTOKEN_GROUPS ptg = NULL;
278
279     // Verify the parameter passed in is not NULL.
280     if (NULL == ppsid)
281         goto Cleanup;
282
283     // Get required buffer size and allocate the TOKEN_GROUPS buffer.
284
285     if (!GetTokenInformation( hToken,         // handle to the access token
286                               TokenGroups,    // get information about the token's groups
287                               (LPVOID) ptg,   // pointer to TOKEN_GROUPS buffer
288                               0,              // size of buffer
289                               &dwLength       // receives required buffer size
290                               ))
291     {
292         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
293             goto Cleanup;
294
295         ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
296                                         HEAP_ZERO_MEMORY, dwLength);
297
298         if (ptg == NULL)
299             goto Cleanup;
300     }
301
302     // Get the token group information from the access token.
303
304     if (!GetTokenInformation( hToken,         // handle to the access token
305                               TokenGroups,    // get information about the token's groups
306                               (LPVOID) ptg,   // pointer to TOKEN_GROUPS buffer
307                               dwLength,       // size of buffer
308                               &dwLength       // receives required buffer size
309                               ))
310     {
311         goto Cleanup;
312     }
313
314     // Loop through the groups to find the logon SID.
315     for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++) {
316         if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) ==  SE_GROUP_LOGON_ID)
317         {
318             // Found the logon SID; make a copy of it.
319
320             dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
321             *ppsid = (PSID) HeapAlloc(GetProcessHeap(),
322                                        HEAP_ZERO_MEMORY, dwLength);
323             if (*ppsid == NULL)
324                 goto Cleanup;
325             if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
326             {
327                 HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
328                 goto Cleanup;
329             }
330             bSuccess = TRUE;
331             break;
332         }
333     }
334
335   Cleanup:
336
337     // Free the buffer for the token groups.
338     if (ptg != NULL)
339         HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
340
341     return bSuccess;
342 }
343
344 afs_uint32
345 smb_GetUserSID(HANDLE hToken, PSID *ppsid)
346 {
347     BOOL bSuccess = FALSE;
348     DWORD dwLength = 0;
349     PTOKEN_USER ptu = NULL;
350
351     // Verify the parameter passed in is not NULL.
352     if (NULL == ppsid)
353         goto Cleanup;
354
355     // Get required buffer size and allocate the TOKEN_USER buffer.
356
357     if (!GetTokenInformation( hToken,         // handle to the access token
358                               TokenUser,      // get information about the token's user
359                               (LPVOID) ptu,   // pointer to TOKEN_USER buffer
360                               0,              // size of buffer
361                               &dwLength       // receives required buffer size
362                               ))
363     {
364         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
365             goto Cleanup;
366
367         ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
368                                         HEAP_ZERO_MEMORY, dwLength);
369
370         if (ptu == NULL)
371             goto Cleanup;
372     }
373
374     // Get the token group information from the access token.
375
376     if (!GetTokenInformation( hToken,         // handle to the access token
377                               TokenUser,      // get information about the token's user
378                               (LPVOID) ptu,   // pointer to TOKEN_USER buffer
379                               dwLength,       // size of buffer
380                               &dwLength       // receives required buffer size
381                               ))
382     {
383         goto Cleanup;
384     }
385
386     // Found the user SID; make a copy of it.
387     dwLength = GetLengthSid(ptu->User.Sid);
388     *ppsid = (PSID) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
389     if (*ppsid == NULL)
390         goto Cleanup;
391     if (!CopySid(dwLength, *ppsid, ptu->User.Sid))
392     {
393         HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
394         goto Cleanup;
395     }
396     bSuccess = TRUE;
397
398   Cleanup:
399
400     // Free the buffer for the token groups.
401     if (ptu != NULL)
402         HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
403
404     return bSuccess;
405 }
406
407 void
408 smb_FreeSID (PSID psid)
409 {
410     HeapFree(GetProcessHeap(), 0, (LPVOID)psid);
411 }
412
413
414 struct smb_ext_context {
415     CredHandle creds;
416     CtxtHandle ctx;
417     int partialTokenLen;
418     void * partialToken;
419 };
420
421 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
422                              char * secBlobIn, int secBlobInLength,
423                              char ** secBlobOut, int * secBlobOutLength,
424                              wchar_t **secSidString) {
425     SECURITY_STATUS status, istatus;
426     CredHandle creds;
427     TimeStamp expiry;
428     long code = 0;
429     SecBufferDesc secBufIn;
430     SecBuffer secTokIn;
431     SecBufferDesc secBufOut;
432     SecBuffer secTokOut;
433     CtxtHandle ctx;
434     struct smb_ext_context * secCtx = NULL;
435     struct smb_ext_context * newSecCtx = NULL;
436     void * assembledBlob = NULL;
437     int assembledBlobLength = 0;
438     ULONG flags;
439
440     OutputDebugF(_C("In smb_AuthenticateUserExt"));
441
442     *secBlobOut = NULL;
443     *secBlobOutLength = 0;
444     *secSidString = NULL;
445
446     if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
447         secCtx = vcp->secCtx;
448         lock_ObtainMutex(&vcp->mx);
449         vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
450         vcp->secCtx = NULL;
451         lock_ReleaseMutex(&vcp->mx);
452     }
453
454     if (secBlobIn) {
455         OutputDebugF(_C("Received incoming token:"));
456         OutputDebugHexDump(secBlobIn,secBlobInLength);
457     }
458
459     if (secCtx) {
460         OutputDebugF(_C("Continuing with existing context."));
461         creds = secCtx->creds;
462         ctx = secCtx->ctx;
463
464         if (secCtx->partialToken) {
465             assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
466             assembledBlob = malloc(assembledBlobLength);
467             memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
468             memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
469         }
470     } else {
471         status = AcquireCredentialsHandle( NULL,
472                                            SMB_EXT_SEC_PACKAGE_NAME,
473                                            SECPKG_CRED_INBOUND,
474                                            NULL,
475                                            NULL,
476                                            NULL,
477                                            NULL,
478                                            &creds,
479                                            &expiry);
480
481         if (status != SEC_E_OK) {
482             OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
483             code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
484             goto aue_0;
485         }
486
487         ctx.dwLower = 0;
488         ctx.dwUpper = 0;
489     }
490
491     secBufIn.cBuffers = 1;
492     secBufIn.pBuffers = &secTokIn;
493     secBufIn.ulVersion = SECBUFFER_VERSION;
494
495     secTokIn.BufferType = SECBUFFER_TOKEN;
496     if (assembledBlob) {
497         secTokIn.cbBuffer = assembledBlobLength;
498         secTokIn.pvBuffer = assembledBlob;
499     } else {
500         secTokIn.cbBuffer = secBlobInLength;
501         secTokIn.pvBuffer = secBlobIn;
502     }
503
504     secBufOut.cBuffers = 1;
505     secBufOut.pBuffers = &secTokOut;
506     secBufOut.ulVersion = SECBUFFER_VERSION;
507
508     secTokOut.BufferType = SECBUFFER_TOKEN;
509     secTokOut.cbBuffer = 0;
510     secTokOut.pvBuffer = NULL;
511
512     status = AcceptSecurityContext( &creds,
513                                     ((secCtx)?&ctx:NULL),
514                                     &secBufIn,
515                                     ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
516                                     SECURITY_NETWORK_DREP,
517                                     &ctx,
518                                     &secBufOut,
519                                     &flags,
520                                     &expiry
521                                     );
522
523     if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
524         OutputDebugF(_C("Completing token..."));
525         istatus = CompleteAuthToken(&ctx, &secBufOut);
526         if ( istatus != SEC_E_OK )
527             OutputDebugF(_C("Token completion failed: %lX"), istatus);
528     }
529
530     if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
531         OutputDebugF(_C("Continue needed"));
532
533         newSecCtx = malloc(sizeof(*newSecCtx));
534
535         newSecCtx->creds = creds;
536         newSecCtx->ctx = ctx;
537         newSecCtx->partialToken = NULL;
538         newSecCtx->partialTokenLen = 0;
539
540         lock_ObtainMutex( &vcp->mx );
541         vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
542         vcp->secCtx = newSecCtx;
543         lock_ReleaseMutex( &vcp->mx );
544
545         code = CM_ERROR_GSSCONTINUE;
546     }
547
548     if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK ||
549           status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) &&
550          secTokOut.pvBuffer) {
551         OutputDebugF(_C("Need to send token back to client"));
552
553         *secBlobOutLength = secTokOut.cbBuffer;
554         *secBlobOut = malloc(secTokOut.cbBuffer);
555         memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
556
557         OutputDebugF(_C("Outgoing token:"));
558         OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
559     } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
560         OutputDebugF(_C("Incomplete message"));
561
562         newSecCtx = malloc(sizeof(*newSecCtx));
563
564         newSecCtx->creds = creds;
565         newSecCtx->ctx = ctx;
566         newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
567         memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
568         newSecCtx->partialTokenLen = secTokOut.cbBuffer;
569
570         lock_ObtainMutex( &vcp->mx );
571         vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
572         vcp->secCtx = newSecCtx;
573         lock_ReleaseMutex( &vcp->mx );
574
575         code = CM_ERROR_GSSCONTINUE;
576     }
577
578     if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
579         /* woo hoo! */
580         HANDLE hToken = 0;
581         SecPkgContext_NamesW names;
582
583         OutputDebugF(_C("Authentication completed"));
584         OutputDebugF(_C("Returned flags : [%lX]"), flags);
585
586         if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
587             OutputDebugF(_C("Received name [%s]"), names.sUserName);
588             cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
589             cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
590             FreeContextBuffer(names.sUserName);
591         } else {
592             /* Force the user to retry if the context is invalid */
593             OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
594             code = CM_ERROR_BADPASSWORD;
595         }
596
597         /* Obtain the user's SID */
598         if (code == 0 && !QuerySecurityContextToken(((secCtx)?&ctx:NULL), &hToken)) {
599             PSID pSid = 0;
600             OutputDebugF(_C("Received hToken"));
601
602             if (smb_GetUserSID(hToken, &pSid))
603                 ConvertSidToStringSidW(pSid, secSidString);
604
605             if (pSid)
606                 smb_FreeSID(pSid);
607             CloseHandle(hToken);
608         } else {
609             OutputDebugF(_C("QueryContextToken failed [%x]"), GetLastError());
610         }
611     } else if (!code) {
612         switch ( status ) {
613         case SEC_E_INVALID_TOKEN:
614             OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
615             break;
616         case SEC_E_INVALID_HANDLE:
617             OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
618             break;
619         case SEC_E_LOGON_DENIED:
620             OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
621             break;
622         case SEC_E_UNKNOWN_CREDENTIALS:
623             OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
624             break;
625         case SEC_E_NO_CREDENTIALS:
626             OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
627             break;
628         case SEC_E_CONTEXT_EXPIRED:
629             OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
630             break;
631         case SEC_E_INCOMPLETE_CREDENTIALS:
632             OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
633             break;
634         case SEC_E_WRONG_PRINCIPAL:
635             OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
636             break;
637         case SEC_E_TIME_SKEW:
638             OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
639             break;
640         default:
641             OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
642         }
643         code = CM_ERROR_BADPASSWORD;
644     }
645
646     if (secCtx) {
647         if (secCtx->partialToken) free(secCtx->partialToken);
648         free(secCtx);
649     }
650
651     if (assembledBlob) {
652         free(assembledBlob);
653     }
654
655     if (secTokOut.pvBuffer)
656         FreeContextBuffer(secTokOut.pvBuffer);
657
658     if (code != CM_ERROR_GSSCONTINUE) {
659         DeleteSecurityContext(&ctx);
660         FreeCredentialsHandle(&creds);
661     }
662
663   aue_0:
664     return code;
665 }
666
667 #define P_LEN 256
668 #define P_RESP_LEN 128
669
670 /* LsaLogonUser expects input parameters to be in a contiguous block of memory.
671    So put stuff in a struct. */
672 struct Lm20AuthBlob {
673     MSV1_0_LM20_LOGON lmlogon;
674     BYTE ciResponse[P_RESP_LEN];    /* Unicode representation */
675     BYTE csResponse[P_RESP_LEN];    /* ANSI representation */
676     WCHAR accountNameW[P_LEN];
677     WCHAR primaryDomainW[P_LEN];
678     WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
679     TOKEN_GROUPS tgroups;
680     TOKEN_SOURCE tsource;
681 };
682
683 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength)
684 {
685     NTSTATUS nts, ntsEx;
686     struct Lm20AuthBlob lmAuth;
687     PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
688     QUOTA_LIMITS quotaLimits;
689     DWORD size;
690     ULONG lmprofilepSize;
691     LUID lmSession;
692     HANDLE lmToken;
693
694     OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
695     OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
696
697     if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
698         OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
699         return CM_ERROR_BADPASSWORD;
700     }
701
702     memset(&lmAuth,0,sizeof(lmAuth));
703
704     lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
705
706     lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
707     cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
708     lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
709     lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
710
711     lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
712     cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
713     lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
714     lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
715
716     lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
717     lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
718     size = MAX_COMPUTERNAME_LENGTH + 1;
719     GetComputerNameW(lmAuth.workstationW, &size);
720     lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
721
722     memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
723
724     lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
725     lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
726     lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
727     memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
728
729     lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
730     lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
731     lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
732     memcpy(lmAuth.csResponse, csPwd, csPwdLength);
733
734     lmAuth.lmlogon.ParameterControl = 0;
735
736     lmAuth.tgroups.GroupCount = 0;
737     lmAuth.tgroups.Groups[0].Sid = NULL;
738     lmAuth.tgroups.Groups[0].Attributes = 0;
739
740 #ifdef _WIN64
741     lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
742 #else
743     lmAuth.tsource.SourceIdentifier.HighPart = 0;
744 #endif
745     lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
746     StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
747                    "OpenAFS"); /* 8 char limit */
748
749     nts = LsaLogonUser( smb_lsaHandle,
750                         &smb_lsaLogonOrigin,
751                         Network, /*3*/
752                         smb_lsaSecPackage,
753                         &lmAuth,
754                         sizeof(lmAuth),
755                         &lmAuth.tgroups,
756                         &lmAuth.tsource,
757                         &lmprofilep,
758                         &lmprofilepSize,
759                         &lmSession,
760                         &lmToken,
761                         &quotaLimits,
762                         &ntsEx);
763
764     if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
765         osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
766                   nts, ntsEx);
767
768     OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
769     OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
770
771     if (nts == ERROR_SUCCESS) {
772         /* free the token */
773         LsaFreeReturnBuffer(lmprofilep);
774         CloseHandle(lmToken);
775         return 0;
776     } else {
777         /* No AFS for you */
778         if (nts == 0xC000015BL)
779             return CM_ERROR_BADLOGONTYPE;
780         else /* our catchall is a bad password though we could be more specific */
781             return CM_ERROR_BADPASSWORD;
782     }
783 }
784
785 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
786 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName)
787 {
788     clientchar_t * atsign;
789     const clientchar_t * domain;
790
791     /* check if we have sane input */
792     if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
793         return 1;
794
795     /* we could get : [accountName][domainName]
796        [user][domain]
797        [user@domain][]
798        [user][]/[user][?]
799        [][]/[][?] */
800
801     atsign = cm_ClientStrChr(accountName, '@');
802
803     if (atsign) /* [user@domain][] -> [user@domain][domain] */
804         domain = atsign + 1;
805     else
806         domain = domainName;
807
808     /* if for some reason the client doesn't know what domain to use,
809        it will either return an empty string or a '?' */
810     if (!domain[0] || domain[0] == '?')
811         /* Empty domains and empty usernames are usually sent from tokenless contexts.
812            This way such logins will get an empty username (easy to check).  I don't know
813            when a non-empty username would be supplied with an anonymous domain, but *shrug* */
814         cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
815     else {
816         /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
817         cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
818         cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
819         if (atsign)
820             cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
821         else
822             cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
823     }
824
825     cm_ClientStrLwr(usern);
826
827     return 0;
828 }
829
830 /* When using SMB auth, all SMB sessions have to pass through here
831  * first to authenticate the user.
832  *
833  * Caveat: If not using SMB auth, the protocol does not require
834  * sending a session setup packet, which means that we can't rely on a
835  * UID in subsequent packets.  Though in practice we get one anyway.
836  */
837 /* SMB_COM_SESSION_SETUP_ANDX */
838 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
839 {
840     char *tp;
841     smb_user_t *uidp;
842     unsigned short newUid;
843     unsigned long caps = 0;
844     smb_username_t *unp;
845     clientchar_t *s1 = _C(" ");
846     long code = 0;
847     clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
848     int usernIsSID = 0;
849     char *secBlobOut = NULL;
850     int  secBlobOutLength = 0;
851     wchar_t *secSidString = 0;
852     int  maxBufferSize = 0;
853     int  maxMpxCount = 0;
854     int  vcNumber = 0;
855
856     /* Check for bad conns */
857     if (vcp->flags & SMB_VCFLAG_REMOTECONN)
858         return CM_ERROR_REMOTECONN;
859
860     /* maxBufferSize */
861     maxBufferSize = smb_GetSMBParm(inp, 2);
862     maxMpxCount = smb_GetSMBParm(inp, 3);
863     vcNumber = smb_GetSMBParm(inp, 4);
864
865     osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
866              maxBufferSize, maxMpxCount, vcNumber);
867
868     if (maxMpxCount > smb_maxMpxRequests) {
869         LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
870         osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
871                  maxMpxCount, smb_maxMpxRequests);
872     }
873
874     if (maxBufferSize < SMB_PACKETSIZE) {
875         LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
876         osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
877                  maxBufferSize, SMB_PACKETSIZE);
878     }
879
880     if (vcNumber == 0) {
881         osi_Log0(smb_logp, "Resetting all VCs");
882         smb_MarkAllVCsDead(vcp);
883     }
884
885     if (vcp->flags & SMB_VCFLAG_USENT) {
886         if (smb_authType == SMB_AUTH_EXTENDED) {
887             /* extended authentication */
888             char *secBlobIn;
889             int secBlobInLength;
890
891             OutputDebugF(_C("NT Session Setup: Extended"));
892
893             if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
894                 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
895             }
896
897             secBlobInLength = smb_GetSMBParm(inp, 7);
898             secBlobIn = smb_GetSMBData(inp, NULL);
899
900             code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength, &secSidString);
901
902             if (code == CM_ERROR_GSSCONTINUE) {
903                 size_t cb_data = 0;
904
905                 smb_SetSMBParm(outp, 2, 0);
906                 smb_SetSMBParm(outp, 3, secBlobOutLength);
907
908                 tp = smb_GetSMBData(outp, NULL);
909                 if (secBlobOutLength) {
910                     memcpy(tp, secBlobOut, secBlobOutLength);
911                     free(secBlobOut);
912                     tp += secBlobOutLength;
913                     cb_data += secBlobOutLength;
914                 }
915                 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
916                 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
917                 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
918
919                 smb_SetSMBDataLength(outp, cb_data);
920             }
921
922             /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
923         } else {
924             unsigned ciPwdLength, csPwdLength;
925             char *ciPwd, *csPwd;
926             clientchar_t *accountName;
927             clientchar_t *primaryDomain;
928             int  datalen;
929
930             if (smb_authType == SMB_AUTH_NTLM)
931                 OutputDebugF(_C("NT Session Setup: NTLM"));
932             else
933                 OutputDebugF(_C("NT Session Setup: None"));
934
935             /* TODO: parse for extended auth as well */
936             ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
937             csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
938
939             tp = smb_GetSMBData(inp, &datalen);
940
941             OutputDebugF(_C("Session packet data size [%d]"),datalen);
942
943             ciPwd = tp;
944             tp += ciPwdLength;
945             csPwd = tp;
946             tp += csPwdLength;
947
948             accountName = smb_ParseString(inp, tp, &tp, 0);
949             primaryDomain = smb_ParseString(inp, tp, NULL, 0);
950
951             OutputDebugF(_C("Account Name: %s"),accountName);
952             OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
953             OutputDebugF(_C("Case Sensitive Password: %s"),
954                          csPwd && csPwd[0] ? _C("yes") : _C("no"));
955             OutputDebugF(_C("Case Insensitive Password: %s"),
956                          ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
957
958             if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
959                 /* shouldn't happen */
960                 code = CM_ERROR_BADSMB;
961                 goto after_read_packet;
962             }
963
964             /* capabilities are only valid for first session packet */
965             if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
966                 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
967             }
968
969             if (smb_authType == SMB_AUTH_NTLM) {
970                 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
971                 if ( code )
972                     OutputDebugF(_C("LM authentication failed [%d]"), code);
973                 else
974                     OutputDebugF(_C("LM authentication succeeded"));
975             }
976         }
977     }  else { /* V3 */
978         unsigned ciPwdLength;
979         char *ciPwd;
980         clientchar_t *accountName;
981         clientchar_t *primaryDomain;
982
983         switch ( smb_authType ) {
984         case SMB_AUTH_EXTENDED:
985             OutputDebugF(_C("V3 Session Setup: Extended"));
986             break;
987         case SMB_AUTH_NTLM:
988             OutputDebugF(_C("V3 Session Setup: NTLM"));
989             break;
990         default:
991             OutputDebugF(_C("V3 Session Setup: None"));
992         }
993         ciPwdLength = smb_GetSMBParm(inp, 7);
994         tp = smb_GetSMBData(inp, NULL);
995         ciPwd = tp;
996         tp += ciPwdLength;
997
998         accountName = smb_ParseString(inp, tp, &tp, 0);
999         primaryDomain = smb_ParseString(inp, tp, NULL, 0);
1000
1001         OutputDebugF(_C("Account Name: %s"),accountName);
1002         OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
1003         OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
1004
1005         if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
1006             /* shouldn't happen */
1007             code = CM_ERROR_BADSMB;
1008             goto after_read_packet;
1009         }
1010
1011         /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
1012          * to NTLM.
1013          */
1014         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
1015             code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
1016             if ( code )
1017                 OutputDebugF(_C("LM authentication failed [%d]"), code);
1018             else
1019                 OutputDebugF(_C("LM authentication succeeded"));
1020         }
1021     }
1022
1023   after_read_packet:
1024     /* note down that we received a session setup X and set the capabilities flag */
1025     if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
1026         lock_ObtainMutex(&vcp->mx);
1027         vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
1028         /* for the moment we can only deal with NTSTATUS */
1029         if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
1030             vcp->flags |= SMB_VCFLAG_STATUS32;
1031         }
1032
1033 #ifdef SMB_UNICODE
1034         if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
1035             vcp->flags |= SMB_VCFLAG_USEUNICODE;
1036         }
1037 #endif
1038         lock_ReleaseMutex(&vcp->mx);
1039     }
1040
1041     /* code would be non-zero if there was an authentication failure.
1042        Ideally we would like to invalidate the uid for this session or break
1043        early to avoid accidently stealing someone else's tokens. */
1044
1045     if (code) {
1046         if (secSidString)
1047             LocalFree(secSidString);
1048         return code;
1049     }
1050
1051     /*
1052      * If the SidString for the user could be obtained, use that
1053      * for the user id
1054      */
1055     if (secSidString) {
1056         cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, secSidString);
1057         usernIsSID = 1;
1058     }
1059
1060     OutputDebugF(_C("Received username=[%s]"), usern);
1061
1062     /* On Windows 2000, this function appears to be called more often than
1063        it is expected to be called. This resulted in multiple smb_user_t
1064        records existing all for the same user session which results in all
1065        of the users tokens disappearing.
1066
1067        To avoid this problem, we look for an existing smb_user_t record
1068        based on the users name, and use that one if we find it.
1069     */
1070
1071     uidp = smb_FindUserByNameThisSession(vcp, usern);
1072     if (uidp) {   /* already there, so don't create a new one */
1073         unp = uidp->unp;
1074         newUid = uidp->userID;
1075         osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
1076                  vcp->lana,vcp->lsn,newUid);
1077         smb_ReleaseUID(uidp);
1078     }
1079     else {
1080         cm_user_t *userp;
1081
1082         /* do a global search for the username/machine name pair */
1083         unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
1084         lock_ObtainMutex(&unp->mx);
1085         if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
1086             /* clear the afslogon flag so that the tickets can now
1087              * be freed when the refCount returns to zero.
1088              */
1089             unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
1090         }
1091     if (usernIsSID)
1092         unp->flags |= SMB_USERNAMEFLAG_SID;
1093         lock_ReleaseMutex(&unp->mx);
1094
1095         /* Create a new UID and cm_user_t structure */
1096         userp = unp->userp;
1097         if (!userp)
1098             userp = cm_NewUser();
1099         cm_HoldUserVCRef(userp);
1100         lock_ObtainMutex(&vcp->mx);
1101         if (!vcp->uidCounter)
1102             vcp->uidCounter++; /* handle unlikely wraparounds */
1103         newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
1104         lock_ReleaseMutex(&vcp->mx);
1105
1106         /* Create a new smb_user_t structure and connect them up */
1107         lock_ObtainMutex(&unp->mx);
1108         unp->userp = userp;
1109         lock_ReleaseMutex(&unp->mx);
1110
1111         uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
1112         if (uidp) {
1113             lock_ObtainMutex(&uidp->mx);
1114             uidp->unp = unp;
1115             osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
1116             lock_ReleaseMutex(&uidp->mx);
1117             smb_ReleaseUID(uidp);
1118         }
1119     }
1120
1121     /* Return UID to the client */
1122     ((smb_t *)outp)->uid = newUid;
1123     /* Also to the next chained message */
1124     ((smb_t *)inp)->uid = newUid;
1125
1126     osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
1127              osi_LogSaveClientString(smb_logp, usern), newUid,
1128              osi_LogSaveClientString(smb_logp, s1));
1129
1130     smb_SetSMBParm(outp, 2, 0);
1131
1132     if (vcp->flags & SMB_VCFLAG_USENT) {
1133         if (smb_authType == SMB_AUTH_EXTENDED) {
1134             size_t cb_data = 0;
1135
1136             smb_SetSMBParm(outp, 3, secBlobOutLength);
1137
1138             tp = smb_GetSMBData(outp, NULL);
1139             if (secBlobOutLength) {
1140                 memcpy(tp, secBlobOut, secBlobOutLength);
1141                 free(secBlobOut);
1142                 tp += secBlobOutLength;
1143                 cb_data +=  secBlobOutLength;
1144             }
1145
1146             tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1147             tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1148             tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1149
1150             smb_SetSMBDataLength(outp, cb_data);
1151         } else {
1152             smb_SetSMBDataLength(outp, 0);
1153         }
1154     } else {
1155         if (smb_authType == SMB_AUTH_EXTENDED) {
1156             size_t cb_data = 0;
1157
1158             tp = smb_GetSMBData(outp, NULL);
1159
1160             tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1161             tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1162             tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1163
1164             smb_SetSMBDataLength(outp, cb_data);
1165         } else {
1166             smb_SetSMBDataLength(outp, 0);
1167         }
1168     }
1169
1170     if (secSidString)
1171         LocalFree(secSidString);
1172     return 0;
1173 }
1174
1175 /* SMB_COM_LOGOFF_ANDX */
1176 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1177 {
1178     smb_user_t *uidp;
1179
1180     /* find the tree and free it */
1181     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1182     if (uidp) {
1183         smb_username_t * unp;
1184
1185         osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1186                  osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1187
1188         lock_ObtainMutex(&uidp->mx);
1189         uidp->flags |= SMB_USERFLAG_DELETE;
1190         /*
1191          * it doesn't get deleted right away
1192          * because the vcp points to it
1193          */
1194         unp = uidp->unp;
1195         lock_ReleaseMutex(&uidp->mx);
1196
1197 #ifdef COMMENT
1198         /* we can't do this.  we get logoff messages prior to a session
1199          * disconnect even though it doesn't mean the user is logging out.
1200          * we need to create a new pioctl and EventLogoff handler to set
1201          * SMB_USERNAMEFLAG_LOGOFF.
1202          */
1203         if (unp && smb_LogoffTokenTransfer) {
1204             lock_ObtainMutex(&unp->mx);
1205             unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1206             unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1207             lock_ReleaseMutex(&unp->mx);
1208         }
1209 #endif
1210
1211         smb_ReleaseUID(uidp);
1212     }
1213     else
1214         osi_Log0(smb_logp, "SMB3 user logoffX");
1215
1216     smb_SetSMBDataLength(outp, 0);
1217     return 0;
1218 }
1219
1220 #define SMB_SUPPORT_SEARCH_BITS        0x0001
1221 #define SMB_SHARE_IS_IN_DFS            0x0002
1222
1223 /* SMB_COM_TREE_CONNECT_ANDX */
1224 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1225 {
1226     smb_tid_t *tidp;
1227     smb_user_t *uidp = NULL;
1228     unsigned short newTid;
1229     clientchar_t shareName[AFSPATHMAX];
1230     clientchar_t *sharePath;
1231     int shareFound;
1232     char *tp;
1233     clientchar_t *slashp;
1234     clientchar_t *pathp;
1235     clientchar_t *passwordp;
1236     clientchar_t *servicep;
1237     cm_user_t *userp = NULL;
1238     int ipc = 0;
1239
1240     osi_Log0(smb_logp, "SMB3 receive tree connect");
1241
1242     /* parse input parameters */
1243     tp = smb_GetSMBData(inp, NULL);
1244     passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1245     pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1246     servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1247
1248     slashp = cm_ClientStrRChr(pathp, '\\');
1249     if (!slashp) {
1250         return CM_ERROR_BADSMB;
1251     }
1252     cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1253
1254     osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1255              osi_LogSaveClientString(smb_logp, pathp),
1256              osi_LogSaveClientString(smb_logp, shareName),
1257              osi_LogSaveClientString(smb_logp, servicep));
1258
1259     if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1260         cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1261 #ifndef NO_IPC
1262         osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1263         ipc = 1;
1264 #else
1265         return CM_ERROR_NOIPC;
1266 #endif
1267     }
1268
1269     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1270     if (uidp)
1271         userp = smb_GetUserFromUID(uidp);
1272
1273     lock_ObtainMutex(&vcp->mx);
1274     newTid = vcp->tidCounter++;
1275     lock_ReleaseMutex(&vcp->mx);
1276
1277     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1278
1279     if (!ipc) {
1280         if (!cm_ClientStrCmp(shareName, _C("*.")))
1281             cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1282         shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1283         if (!shareFound) {
1284             if (uidp)
1285                 smb_ReleaseUID(uidp);
1286             smb_ReleaseTID(tidp, FALSE);
1287             return CM_ERROR_BADSHARENAME;
1288         }
1289
1290         if (vcp->flags & SMB_VCFLAG_USENT)
1291         {
1292             int policy = smb_FindShareCSCPolicy(shareName);
1293             HKEY parmKey;
1294             DWORD code;
1295             DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1296
1297             code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1298                                  0, KEY_QUERY_VALUE, &parmKey);
1299             if (code == ERROR_SUCCESS) {
1300                 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1301                                        (BYTE *)&dwAdvertiseDFS, &dwSize);
1302                 if (code != ERROR_SUCCESS)
1303                     dwAdvertiseDFS = 0;
1304                 RegCloseKey (parmKey);
1305             }
1306             smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1307                            (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1308                            (policy << 2));
1309         }
1310     } else {
1311         smb_SetSMBParm(outp, 2, 0);
1312         sharePath = NULL;
1313     }
1314     if (uidp)
1315         smb_ReleaseUID(uidp);
1316
1317     lock_ObtainMutex(&tidp->mx);
1318     tidp->userp = userp;
1319     tidp->pathname = sharePath;
1320     if (ipc)
1321         tidp->flags |= SMB_TIDFLAG_IPC;
1322     lock_ReleaseMutex(&tidp->mx);
1323     smb_ReleaseTID(tidp, FALSE);
1324
1325     ((smb_t *)outp)->tid = newTid;
1326     ((smb_t *)inp)->tid = newTid;
1327     tp = smb_GetSMBData(outp, NULL);
1328     if (!ipc) {
1329         size_t cb_data = 0;
1330
1331         tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1332         tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1333         smb_SetSMBDataLength(outp, cb_data);
1334     } else {
1335         size_t cb_data = 0;
1336
1337         tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1338         smb_SetSMBDataLength(outp, cb_data);
1339     }
1340
1341     osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1342     return 0;
1343 }
1344
1345 /* must be called with global tran lock held */
1346 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1347 {
1348     smb_tran2Packet_t *tp;
1349     smb_t *smbp;
1350
1351     smbp = (smb_t *) inp->data;
1352     for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1353         if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1354             return tp;
1355     }
1356     return NULL;
1357 }
1358
1359 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1360                                       int totalParms, int totalData)
1361 {
1362     smb_tran2Packet_t *tp;
1363     smb_t *smbp;
1364
1365     smbp = (smb_t *) inp->data;
1366     tp = malloc(sizeof(*tp));
1367     memset(tp, 0, sizeof(*tp));
1368     tp->vcp = vcp;
1369     smb_HoldVC(vcp);
1370     tp->curData = tp->curParms = 0;
1371     tp->totalData = totalData;
1372     tp->totalParms = totalParms;
1373     tp->tid = smbp->tid;
1374     tp->mid = smbp->mid;
1375     tp->uid = smbp->uid;
1376     tp->pid = smbp->pid;
1377     tp->res[0] = smbp->res[0];
1378     osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1379     if (totalParms != 0)
1380         tp->parmsp = malloc(totalParms);
1381     if (totalData != 0)
1382         tp->datap = malloc(totalData);
1383     if (smbp->com == 0x25 || smbp->com == 0x26)
1384         tp->com = 0x25;
1385     else {
1386         tp->opcode = smb_GetSMBParm(inp, 14);
1387         tp->com = 0x32;
1388     }
1389     tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1390 #ifdef SMB_UNICODE
1391     if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1392         tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1393 #endif
1394     return tp;
1395 }
1396
1397 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1398                                               smb_tran2Packet_t *inp, smb_packet_t *outp,
1399                                               int totalParms, int totalData)
1400 {
1401     smb_tran2Packet_t *tp;
1402     unsigned short parmOffset;
1403     unsigned short dataOffset;
1404     unsigned short dataAlign;
1405
1406     tp = malloc(sizeof(*tp));
1407     memset(tp, 0, sizeof(*tp));
1408     smb_HoldVC(vcp);
1409     tp->vcp = vcp;
1410     tp->curData = tp->curParms = 0;
1411     tp->totalData = totalData;
1412     tp->totalParms = totalParms;
1413     tp->oldTotalParms = totalParms;
1414     tp->tid = inp->tid;
1415     tp->mid = inp->mid;
1416     tp->uid = inp->uid;
1417     tp->pid = inp->pid;
1418     tp->res[0] = inp->res[0];
1419     tp->opcode = inp->opcode;
1420     tp->com = inp->com;
1421
1422     /*
1423      * We calculate where the parameters and data will start.
1424      * This calculation must parallel the calculation in
1425      * smb_SendTran2Packet.
1426      */
1427
1428     parmOffset = 10*2 + 35;
1429     parmOffset++;                       /* round to even */
1430     tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1431
1432     dataOffset = parmOffset + totalParms;
1433     dataAlign = dataOffset & 2; /* quad-align */
1434     dataOffset += dataAlign;
1435     tp->datap = outp->data + dataOffset;
1436
1437     return tp;
1438 }
1439
1440 /* free a tran2 packet */
1441 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1442 {
1443     if (t2p->vcp) {
1444         smb_ReleaseVC(t2p->vcp);
1445         t2p->vcp = NULL;
1446     }
1447     if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1448         if (t2p->parmsp)
1449             free(t2p->parmsp);
1450         if (t2p->datap)
1451             free(t2p->datap);
1452     }
1453     if (t2p->name) {
1454         free(t2p->name);
1455         t2p->name = NULL;
1456     }
1457     while (t2p->stringsp) {
1458         cm_space_t * ns;
1459
1460         ns = t2p->stringsp;
1461         t2p->stringsp = ns->nextp;
1462         cm_FreeSpace(ns);
1463     }
1464     free(t2p);
1465 }
1466
1467 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1468                                     char ** chainpp, int flags)
1469 {
1470     size_t cb;
1471
1472 #ifdef SMB_UNICODE
1473     if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1474         flags |= SMB_STRF_FORCEASCII;
1475 #endif
1476
1477     cb = p->totalParms - (inp - (char *)p->parmsp);
1478     if (inp < (char *) p->parmsp ||
1479         inp >= ((char *) p->parmsp) + p->totalParms) {
1480 #ifdef DEBUG_UNICODE
1481         DebugBreak();
1482 #endif
1483         cb = p->totalParms;
1484     }
1485
1486     return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1487                               inp, &cb, chainpp, flags);
1488 }
1489
1490 /* called with a VC, an input packet to respond to, and an error code.
1491  * sends an error response.
1492  */
1493 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1494                         smb_packet_t *tp, long code)
1495 {
1496     smb_t *smbp;
1497     unsigned short errCode;
1498     unsigned char errClass;
1499     unsigned long NTStatus;
1500
1501     if (vcp->flags & SMB_VCFLAG_STATUS32)
1502         smb_MapNTError(code, &NTStatus);
1503     else
1504         smb_MapCoreError(code, vcp, &errCode, &errClass);
1505
1506     smb_FormatResponsePacket(vcp, NULL, tp);
1507     smbp = (smb_t *) tp;
1508
1509     /* We can handle long names */
1510     if (vcp->flags & SMB_VCFLAG_USENT)
1511         smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1512
1513     /* now copy important fields from the tran 2 packet */
1514     smbp->com = t2p->com;
1515     smbp->tid = t2p->tid;
1516     smbp->mid = t2p->mid;
1517     smbp->pid = t2p->pid;
1518     smbp->uid = t2p->uid;
1519     smbp->res[0] = t2p->res[0];
1520     if (vcp->flags & SMB_VCFLAG_STATUS32) {
1521         smbp->rcls = (unsigned char) (NTStatus & 0xff);
1522         smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1523         smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1524         smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1525         smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1526     }
1527     else {
1528         smbp->rcls = errClass;
1529         smbp->errLow = (unsigned char) (errCode & 0xff);
1530         smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1531     }
1532
1533     /* send packet */
1534     smb_SendPacket(vcp, tp);
1535 }
1536
1537 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1538 {
1539     smb_t *smbp;
1540     unsigned short parmOffset;
1541     unsigned short dataOffset;
1542     unsigned short totalLength;
1543     unsigned short dataAlign;
1544     char *datap;
1545
1546     smb_FormatResponsePacket(vcp, NULL, tp);
1547     smbp = (smb_t *) tp;
1548
1549     /* We can handle long names */
1550     if (vcp->flags & SMB_VCFLAG_USENT)
1551         smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1552
1553     /* now copy important fields from the tran 2 packet */
1554     smbp->com = t2p->com;
1555     smbp->tid = t2p->tid;
1556     smbp->mid = t2p->mid;
1557     smbp->pid = t2p->pid;
1558     smbp->uid = t2p->uid;
1559     smbp->res[0] = t2p->res[0];
1560
1561     if (t2p->error_code) {
1562         if (vcp->flags & SMB_VCFLAG_STATUS32) {
1563             unsigned long NTStatus;
1564
1565             smb_MapNTError(t2p->error_code, &NTStatus);
1566
1567             smbp->rcls = (unsigned char) (NTStatus & 0xff);
1568             smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1569             smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1570             smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1571             smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1572         }
1573         else {
1574             unsigned short errCode;
1575             unsigned char errClass;
1576
1577             smb_MapCoreError(t2p->error_code, vcp, &errCode, &errClass);
1578
1579             smbp->rcls = errClass;
1580             smbp->errLow = (unsigned char) (errCode & 0xff);
1581             smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1582         }
1583     }
1584
1585     totalLength = 1 + t2p->totalData + t2p->totalParms;
1586
1587     /* now add the core parameters (tran2 info) to the packet */
1588     smb_SetSMBParm(tp, 0, t2p->totalParms);     /* parm bytes */
1589     smb_SetSMBParm(tp, 1, t2p->totalData);      /* data bytes */
1590     smb_SetSMBParm(tp, 2, 0);           /* reserved */
1591     smb_SetSMBParm(tp, 3, t2p->totalParms);     /* parm bytes in this packet */
1592     parmOffset = 10*2 + 35;                     /* parm offset in packet */
1593     parmOffset++;                               /* round to even */
1594     smb_SetSMBParm(tp, 4, parmOffset);  /* 11 parm words plus *
1595     * hdr, bcc and wct */
1596     smb_SetSMBParm(tp, 5, 0);           /* parm displacement */
1597     smb_SetSMBParm(tp, 6, t2p->totalData);      /* data in this packet */
1598     dataOffset = parmOffset + t2p->oldTotalParms;
1599     dataAlign = dataOffset & 2;         /* quad-align */
1600     dataOffset += dataAlign;
1601     smb_SetSMBParm(tp, 7, dataOffset);  /* offset of data */
1602     smb_SetSMBParm(tp, 8, 0);           /* data displacement */
1603     smb_SetSMBParm(tp, 9, 0);           /* low: setup word count *
1604                                          * high: resvd */
1605
1606     datap = smb_GetSMBData(tp, NULL);
1607     *datap++ = 0;                               /* we rounded to even */
1608
1609     totalLength += dataAlign;
1610     smb_SetSMBDataLength(tp, totalLength);
1611
1612     /* next, send the datagram */
1613     smb_SendPacket(vcp, tp);
1614 }
1615
1616 /* TRANS_SET_NMPIPE_STATE */
1617 long smb_nmpipeSetState(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1618 {
1619     smb_fid_t *fidp;
1620     int fd;
1621     int pipeState = 0x0100;     /* default */
1622     smb_tran2Packet_t *outp = NULL;
1623
1624     fd = p->pipeParam;
1625     if (p->totalParms > 0)
1626         pipeState = p->parmsp[0];
1627
1628     osi_Log2(smb_logp, "smb_nmpipeSetState for fd[%d] with state[0x%x]", fd, pipeState);
1629
1630     fidp = smb_FindFID(vcp, fd, 0);
1631     if (!fidp) {
1632         osi_Log2(smb_logp, "smb_nmpipeSetState Unknown SMB Fid vcp 0x%p fid %d",
1633                  vcp, fd);
1634         return CM_ERROR_BADFD;
1635     }
1636     lock_ObtainMutex(&fidp->mx);
1637     if (pipeState & 0x8000)
1638         fidp->flags |= SMB_FID_BLOCKINGPIPE;
1639     if (pipeState & 0x0100)
1640         fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
1641     lock_ReleaseMutex(&fidp->mx);
1642
1643     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
1644     smb_SendTran2Packet(vcp, outp, op);
1645     smb_FreeTran2Packet(outp);
1646
1647     smb_ReleaseFID(fidp);
1648
1649     return 0;
1650 }
1651
1652 long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1653 {
1654     smb_fid_t *fidp;
1655     int fd;
1656     int is_rpc = 0;
1657
1658     long code = 0;
1659
1660     fd = p->pipeParam;
1661
1662     osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
1663              fd, p->totalData, p->maxReturnData);
1664
1665     fidp = smb_FindFID(vcp, fd, 0);
1666     if (!fidp) {
1667         osi_Log2(smb_logp, "smb_nmpipeTransact Unknown SMB Fid vcp 0x%p fid %d",
1668                  vcp, fd);
1669         return CM_ERROR_BADFD;
1670     }
1671     lock_ObtainMutex(&fidp->mx);
1672     if (fidp->flags & SMB_FID_RPC) {
1673         is_rpc = 1;
1674     }
1675     lock_ReleaseMutex(&fidp->mx);
1676
1677     if (is_rpc) {
1678         code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
1679         smb_ReleaseFID(fidp);
1680     } else {
1681         /* We only deal with RPC pipes */
1682         osi_Log2(smb_logp, "smb_nmpipeTransact Not a RPC vcp 0x%p fid %d",
1683                  vcp, fd);
1684         code = CM_ERROR_BADFD;
1685     }
1686
1687     return code;
1688 }
1689
1690
1691 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1692 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1693 {
1694     smb_tran2Packet_t *asp;
1695     int totalParms;
1696     int totalData;
1697     int parmDisp;
1698     int dataDisp;
1699     int parmOffset;
1700     int dataOffset;
1701     int parmCount;
1702     int dataCount;
1703     int firstPacket;
1704     int rapOp;
1705     long code = 0;
1706
1707     /* We sometimes see 0 word count.  What to do? */
1708     if (*inp->wctp == 0) {
1709         osi_Log0(smb_logp, "Transaction2 word count = 0");
1710         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1711
1712         smb_SetSMBDataLength(outp, 0);
1713         smb_SendPacket(vcp, outp);
1714         return 0;
1715     }
1716
1717     totalParms = smb_GetSMBParm(inp, 0);
1718     totalData = smb_GetSMBParm(inp, 1);
1719
1720     firstPacket = (inp->inCom == 0x25);
1721
1722     /* find the packet we're reassembling */
1723     lock_ObtainWrite(&smb_globalLock);
1724     asp = smb_FindTran2Packet(vcp, inp);
1725     if (!asp) {
1726         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1727     }
1728     lock_ReleaseWrite(&smb_globalLock);
1729
1730     /* now merge in this latest packet; start by looking up offsets */
1731     if (firstPacket) {
1732         parmDisp = dataDisp = 0;
1733         parmOffset = smb_GetSMBParm(inp, 10);
1734         dataOffset = smb_GetSMBParm(inp, 12);
1735         parmCount = smb_GetSMBParm(inp, 9);
1736         dataCount = smb_GetSMBParm(inp, 11);
1737         asp->setupCount = smb_GetSMBParmByte(inp, 13);
1738         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1739         asp->maxReturnData = smb_GetSMBParm(inp, 3);
1740
1741         osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1742                   totalData, dataCount, asp->maxReturnData);
1743
1744         if (asp->setupCount == 2) {
1745             clientchar_t * pname;
1746
1747             asp->pipeCommand = smb_GetSMBParm(inp, 14);
1748             asp->pipeParam = smb_GetSMBParm(inp, 15);
1749             pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
1750             if (pname) {
1751                 asp->name = cm_ClientStrDup(pname);
1752             }
1753
1754             osi_Log2(smb_logp, "  Named Pipe command id [%d] with name [%S]",
1755                      asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
1756         }
1757     }
1758     else {
1759         parmDisp = smb_GetSMBParm(inp, 4);
1760         parmOffset = smb_GetSMBParm(inp, 3);
1761         dataDisp = smb_GetSMBParm(inp, 7);
1762         dataOffset = smb_GetSMBParm(inp, 6);
1763         parmCount = smb_GetSMBParm(inp, 2);
1764         dataCount = smb_GetSMBParm(inp, 5);
1765
1766         osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1767                  parmCount, dataCount);
1768     }
1769
1770     /* now copy the parms and data */
1771     if ( asp->totalParms > 0 && parmCount != 0 )
1772     {
1773         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1774     }
1775     if ( asp->totalData > 0 && dataCount != 0 ) {
1776         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1777     }
1778
1779     /* account for new bytes */
1780     asp->curData += dataCount;
1781     asp->curParms += parmCount;
1782
1783     /* finally, if we're done, remove the packet from the queue and dispatch it */
1784     if (((asp->totalParms > 0 && asp->curParms > 0)
1785          || asp->setupCount == 2) &&
1786         asp->totalData <= asp->curData &&
1787         asp->totalParms <= asp->curParms) {
1788
1789         /* we've received it all */
1790         lock_ObtainWrite(&smb_globalLock);
1791         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1792         lock_ReleaseWrite(&smb_globalLock);
1793
1794         switch(asp->setupCount) {
1795         case 0:
1796             {                   /* RAP */
1797                 rapOp = asp->parmsp[0];
1798
1799                 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
1800                      smb_rapDispatchTable[rapOp].procp) {
1801
1802                     osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
1803                              myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1804
1805                     code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1806
1807                     osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return  code 0x%x vcp[%x] lana[%d] lsn[%d]",
1808                              code,vcp,vcp->lana,vcp->lsn);
1809                 }
1810                 else {
1811                     osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
1812                              rapOp, vcp, vcp->lana, vcp->lsn);
1813
1814                     code = CM_ERROR_BADOP;
1815                 }
1816             }
1817             break;
1818
1819         case 2:
1820             {                   /* Named pipe operation */
1821                 osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
1822                          myCrt_NmpipeDispatch(asp->pipeCommand),
1823                          osi_LogSaveClientString(smb_logp, asp->name));
1824
1825                 code = CM_ERROR_BADOP;
1826
1827                 switch (asp->pipeCommand) {
1828                 case SMB_TRANS_SET_NMPIPE_STATE:
1829                     code = smb_nmpipeSetState(vcp, asp, outp);
1830                     break;
1831
1832                 case SMB_TRANS_RAW_READ_NMPIPE:
1833                     break;
1834
1835                 case SMB_TRANS_QUERY_NMPIPE_STATE:
1836                     break;
1837
1838                 case SMB_TRANS_QUERY_NMPIPE_INFO:
1839                     break;
1840
1841                 case SMB_TRANS_PEEK_NMPIPE:
1842                     break;
1843
1844                 case SMB_TRANS_TRANSACT_NMPIPE:
1845                     code = smb_nmpipeTransact(vcp, asp, outp);
1846                     break;
1847
1848                 case SMB_TRANS_RAW_WRITE_NMPIPE:
1849                     break;
1850
1851                 case SMB_TRANS_READ_NMPIPE:
1852                     break;
1853
1854                 case SMB_TRANS_WRITE_NMPIPE:
1855                     break;
1856
1857                 case SMB_TRANS_WAIT_NMPIPE:
1858                     break;
1859
1860                 case SMB_TRANS_CALL_NMPIPE:
1861                     break;
1862                 }
1863             }
1864             break;
1865
1866         default:
1867             code = CM_ERROR_BADOP;
1868         }
1869
1870         /* if an error is returned, we're supposed to send an error packet,
1871          * otherwise the dispatched function already did the data sending.
1872          * We give dispatched proc the responsibility since it knows how much
1873          * space to allocate.
1874          */
1875         if (code != 0) {
1876             smb_SendTran2Error(vcp, asp, outp, code);
1877         }
1878
1879         /* free the input tran 2 packet */
1880         smb_FreeTran2Packet(asp);
1881     }
1882     else if (firstPacket) {
1883         /* the first packet in a multi-packet request, we need to send an
1884          * ack to get more data.
1885          */
1886         smb_SetSMBDataLength(outp, 0);
1887         smb_SendPacket(vcp, outp);
1888     }
1889
1890     return 0;
1891 }
1892
1893 /* ANSI versions. */
1894
1895 #pragma pack(push, 1)
1896
1897 typedef struct smb_rap_share_info_0 {
1898     BYTE                shi0_netname[13];
1899 } smb_rap_share_info_0_t;
1900
1901 typedef struct smb_rap_share_info_1 {
1902     BYTE                shi1_netname[13];
1903     BYTE                shi1_pad;
1904     WORD                        shi1_type;
1905     DWORD                       shi1_remark; /* char *shi1_remark; data offset */
1906 } smb_rap_share_info_1_t;
1907
1908 typedef struct smb_rap_share_info_2 {
1909     BYTE                shi2_netname[13];
1910     BYTE                shi2_pad;
1911     WORD                shi2_type;
1912     DWORD                       shi2_remark; /* char *shi2_remark; data offset */
1913     WORD                shi2_permissions;
1914     WORD                shi2_max_uses;
1915     WORD                shi2_current_uses;
1916     DWORD                       shi2_path;  /* char *shi2_path; data offset */
1917     WORD                shi2_passwd[9];
1918     WORD                shi2_pad2;
1919 } smb_rap_share_info_2_t;
1920
1921 #define SMB_RAP_MAX_SHARES 512
1922
1923 typedef struct smb_rap_share_list {
1924     int cShare;
1925     int maxShares;
1926     smb_rap_share_info_0_t * shares;
1927 } smb_rap_share_list_t;
1928
1929 #pragma pack(pop)
1930
1931 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1932     smb_rap_share_list_t * sp;
1933
1934     if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1935         return 0; /* skip over '.' and '..' */
1936
1937     sp = (smb_rap_share_list_t *) vrockp;
1938
1939     strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1940     sp->shares[sp->cShare].shi0_netname[12] = 0;
1941
1942     sp->cShare++;
1943
1944     if (sp->cShare >= sp->maxShares)
1945         return CM_ERROR_STOPNOW;
1946     else
1947         return 0;
1948 }
1949
1950 /* RAP NetShareEnumRequest */
1951 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1952 {
1953     smb_tran2Packet_t *outp;
1954     unsigned short * tp;
1955     int len;
1956     int infoLevel;
1957     int bufsize;
1958     int outParmsTotal;  /* total parameter bytes */
1959     int outDataTotal;   /* total data bytes */
1960     int code = 0;
1961     DWORD rv;
1962     DWORD allSubmount = 0;
1963     USHORT nShares = 0;
1964     DWORD nRegShares = 0;
1965     DWORD nSharesRet = 0;
1966     HKEY hkParam;
1967     HKEY hkSubmount = NULL;
1968     smb_rap_share_info_1_t * shares;
1969     USHORT cshare = 0;
1970     char * cstrp;
1971     clientchar_t thisShare[AFSPATHMAX];
1972     int i,j;
1973     DWORD dw;
1974     int nonrootShares;
1975     smb_rap_share_list_t rootShares;
1976     cm_req_t req;
1977     cm_user_t * userp;
1978     osi_hyper_t thyper;
1979     cm_scache_t *rootScp;
1980
1981     tp = p->parmsp + 1; /* skip over function number (always 0) */
1982
1983     {
1984         clientchar_t * cdescp;
1985
1986         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1987         if (cm_ClientStrCmp(cdescp,  _C("WrLeh")))
1988             return CM_ERROR_INVAL;
1989         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1990         if (cm_ClientStrCmp(cdescp,  _C("B13BWz")))
1991             return CM_ERROR_INVAL;
1992     }
1993
1994     infoLevel = tp[0];
1995     bufsize = tp[1];
1996
1997     if (infoLevel != 1) {
1998         return CM_ERROR_INVAL;
1999     }
2000
2001     /* We are supposed to use the same ASCII data structure even if
2002        Unicode is negotiated, which ultimately means that the share
2003        names that we return must be at most 13 characters in length,
2004        including the NULL terminator.
2005
2006        The RAP specification states that shares with names longer than
2007        12 characters should not be included in the enumeration.
2008        However, since we support prefix cell references and since many
2009        cell names are going to exceed 12 characters, we lie and send
2010        the first 12 characters.
2011     */
2012
2013     /* first figure out how many shares there are */
2014     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2015                       KEY_QUERY_VALUE, &hkParam);
2016     if (rv == ERROR_SUCCESS) {
2017         len = sizeof(allSubmount);
2018         rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2019                              (BYTE *) &allSubmount, &len);
2020         if (rv != ERROR_SUCCESS || allSubmount != 0) {
2021             allSubmount = 1;
2022         }
2023         RegCloseKey (hkParam);
2024     }
2025
2026     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2027                       0, KEY_QUERY_VALUE, &hkSubmount);
2028     if (rv == ERROR_SUCCESS) {
2029         rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
2030                              NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
2031         if (rv != ERROR_SUCCESS)
2032             nRegShares = 0;
2033     } else {
2034         hkSubmount = NULL;
2035     }
2036
2037     /* fetch the root shares */
2038     rootShares.maxShares = SMB_RAP_MAX_SHARES;
2039     rootShares.cShare = 0;
2040     rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
2041
2042     smb_InitReq(&req);
2043
2044     userp = smb_GetTran2User(vcp,p);
2045
2046     thyper.HighPart = 0;
2047     thyper.LowPart = 0;
2048
2049     rootScp = cm_RootSCachep(userp, &req);
2050     cm_HoldSCache(rootScp);
2051     cm_ApplyDir(rootScp, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
2052     cm_ReleaseSCache(rootScp);
2053
2054     cm_ReleaseUser(userp);
2055
2056     nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
2057
2058 #define REMARK_LEN 1
2059     outParmsTotal = 8; /* 4 dwords */
2060     outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
2061     if(outDataTotal > bufsize) {
2062         nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
2063         outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
2064     }
2065     else {
2066         nSharesRet = nShares;
2067     }
2068
2069     outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
2070
2071     /* now for the submounts */
2072     shares = (smb_rap_share_info_1_t *) outp->datap;
2073     cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
2074
2075     memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
2076
2077     if (allSubmount) {
2078         StringCchCopyA(shares[cshare].shi1_netname,
2079                        lengthof(shares[cshare].shi1_netname), "all" );
2080         shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2081         /* type and pad are zero already */
2082         cshare++;
2083         cstrp+=REMARK_LEN;
2084     }
2085
2086     if (hkSubmount) {
2087         for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
2088             len = sizeof(thisShare);
2089             rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
2090             if (rv == ERROR_SUCCESS &&
2091                 cm_ClientStrLen(thisShare) &&
2092                 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
2093                 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
2094                                       lengthof( shares[cshare].shi1_netname ));
2095                 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
2096                 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2097                 cshare++;
2098                 cstrp+=REMARK_LEN;
2099             }
2100             else
2101                 nShares--; /* uncount key */
2102         }
2103
2104         RegCloseKey(hkSubmount);
2105     }
2106
2107     nonrootShares = cshare;
2108
2109     for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
2110         /* in case there are collisions with submounts, submounts have
2111            higher priority */
2112         for (j=0; j < nonrootShares; j++)
2113             if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
2114                 break;
2115
2116         if (j < nonrootShares) {
2117             nShares--; /* uncount */
2118             continue;
2119         }
2120
2121         StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
2122                        rootShares.shares[i].shi0_netname);
2123         shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2124         cshare++;
2125         cstrp+=REMARK_LEN;
2126     }
2127
2128     outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
2129     outp->parmsp[1] = 0;
2130     outp->parmsp[2] = cshare;
2131     outp->parmsp[3] = nShares;
2132
2133     outp->totalData = (int)(cstrp - outp->datap);
2134     outp->totalParms = outParmsTotal;
2135
2136     smb_SendTran2Packet(vcp, outp, op);
2137     smb_FreeTran2Packet(outp);
2138
2139     free(rootShares.shares);
2140
2141     return code;
2142 }
2143
2144 /* RAP NetShareGetInfo */
2145 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2146 {
2147     smb_tran2Packet_t *outp;
2148     unsigned short * tp;
2149     clientchar_t * shareName;
2150     BOOL shareFound = FALSE;
2151     unsigned short infoLevel;
2152     unsigned short bufsize;
2153     int totalData;
2154     int totalParam;
2155     DWORD len;
2156     HKEY hkParam;
2157     HKEY hkSubmount;
2158     DWORD allSubmount;
2159     LONG rv;
2160     long code = 0;
2161     cm_scache_t *scp = NULL;
2162     cm_user_t   *userp;
2163     cm_req_t    req;
2164
2165     smb_InitReq(&req);
2166
2167     tp = p->parmsp + 1; /* skip over function number (always 1) */
2168
2169     {
2170         clientchar_t * cdescp;
2171
2172         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2173         if (cm_ClientStrCmp(cdescp,  _C("zWrLh")))
2174
2175             return CM_ERROR_INVAL;
2176
2177         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2178         if (cm_ClientStrCmp(cdescp,  _C("B13")) &&
2179             cm_ClientStrCmp(cdescp,  _C("B13BWz")) &&
2180             cm_ClientStrCmp(cdescp,  _C("B13BWzWWWzB9B")))
2181
2182             return CM_ERROR_INVAL;
2183     }
2184     shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2185
2186     infoLevel = *tp++;
2187     bufsize = *tp++;
2188
2189     totalParam = 6;
2190
2191     if (infoLevel == 0)
2192         totalData = sizeof(smb_rap_share_info_0_t);
2193     else if(infoLevel == SMB_INFO_STANDARD)
2194         totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
2195     else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
2196         totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
2197     else
2198         return CM_ERROR_INVAL;
2199
2200     if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
2201         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2202                           KEY_QUERY_VALUE, &hkParam);
2203         if (rv == ERROR_SUCCESS) {
2204             len = sizeof(allSubmount);
2205             rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2206                                   (BYTE *) &allSubmount, &len);
2207             if (rv != ERROR_SUCCESS || allSubmount != 0) {
2208                 allSubmount = 1;
2209             }
2210             RegCloseKey (hkParam);
2211         }
2212
2213         if (allSubmount)
2214             shareFound = TRUE;
2215
2216     } else {
2217         userp = smb_GetTran2User(vcp, p);
2218         if (!userp) {
2219             osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
2220             return CM_ERROR_BADSMB;
2221         }
2222         code = cm_NameI(cm_RootSCachep(userp, &req), shareName,
2223                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
2224                          userp, NULL, &req, &scp);
2225         if (code == 0) {
2226             cm_ReleaseSCache(scp);
2227             shareFound = TRUE;
2228         } else {
2229             rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
2230                               KEY_QUERY_VALUE, &hkSubmount);
2231             if (rv == ERROR_SUCCESS) {
2232                 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
2233                 if (rv == ERROR_SUCCESS) {
2234                     shareFound = TRUE;
2235                 }
2236                 RegCloseKey(hkSubmount);
2237             }
2238         }
2239     }
2240
2241     if (!shareFound)
2242         return CM_ERROR_BADSHARENAME;
2243
2244     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
2245     memset(outp->datap, 0, totalData);
2246
2247     outp->parmsp[0] = 0;
2248     outp->parmsp[1] = 0;
2249     outp->parmsp[2] = totalData;
2250
2251     if (infoLevel == 0) {
2252         smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
2253         cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
2254                               lengthof(info->shi0_netname));
2255     } else if(infoLevel == SMB_INFO_STANDARD) {
2256         smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
2257         cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
2258         info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
2259         info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2260         /* type and pad are already zero */
2261     } else { /* infoLevel==2 */
2262         smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
2263         cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
2264         info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2265         info->shi2_permissions = ACCESS_ALL;
2266         info->shi2_max_uses = (unsigned short) -1;
2267         info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
2268     }
2269
2270     outp->totalData = totalData;
2271     outp->totalParms = totalParam;
2272
2273     smb_SendTran2Packet(vcp, outp, op);
2274     smb_FreeTran2Packet(outp);
2275
2276     return code;
2277 }
2278
2279 #pragma pack(push, 1)
2280
2281 typedef struct smb_rap_wksta_info_10 {
2282     DWORD       wki10_computername;     /*char *wki10_computername;*/
2283     DWORD       wki10_username; /* char *wki10_username; */
2284     DWORD       wki10_langroup; /* char *wki10_langroup;*/
2285     BYTE        wki10_ver_major;
2286     BYTE        wki10_ver_minor;
2287     DWORD       wki10_logon_domain;     /*char *wki10_logon_domain;*/
2288     DWORD       wki10_oth_domains; /* char *wki10_oth_domains;*/
2289 } smb_rap_wksta_info_10_t;
2290
2291 #pragma pack(pop)
2292
2293 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2294 {
2295     smb_tran2Packet_t *outp;
2296     long code = 0;
2297     int infoLevel;
2298     int bufsize;
2299     unsigned short * tp;
2300     int totalData;
2301     int totalParams;
2302     smb_rap_wksta_info_10_t * info;
2303     char * cstrp;
2304     smb_user_t *uidp;
2305
2306     tp = p->parmsp + 1; /* Skip over function number */
2307
2308     {
2309         clientchar_t * cdescp;
2310
2311         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2312                                        SMB_STRF_FORCEASCII);
2313         if (cm_ClientStrCmp(cdescp,  _C("WrLh")))
2314             return CM_ERROR_INVAL;
2315
2316         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2317                                        SMB_STRF_FORCEASCII);
2318         if (cm_ClientStrCmp(cdescp,  _C("zzzBBzz")))
2319             return CM_ERROR_INVAL;
2320     }
2321
2322     infoLevel = *tp++;
2323     bufsize = *tp++;
2324
2325     if (infoLevel != 10) {
2326         return CM_ERROR_INVAL;
2327     }
2328
2329     totalParams = 6;
2330
2331     /* infolevel 10 */
2332     totalData = sizeof(*info) +         /* info */
2333         MAX_COMPUTERNAME_LENGTH +       /* wki10_computername */
2334         SMB_MAX_USERNAME_LENGTH +       /* wki10_username */
2335         MAX_COMPUTERNAME_LENGTH +       /* wki10_langroup */
2336         MAX_COMPUTERNAME_LENGTH +       /* wki10_logon_domain */
2337         1;                              /* wki10_oth_domains (null)*/
2338
2339     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2340
2341     memset(outp->parmsp,0,totalParams);
2342     memset(outp->datap,0,totalData);
2343
2344     info = (smb_rap_wksta_info_10_t *) outp->datap;
2345     cstrp = (char *) (info + 1);
2346
2347     info->wki10_computername = (DWORD) (cstrp - outp->datap);
2348     StringCbCopyA(cstrp, totalData, smb_localNamep);
2349     cstrp += strlen(cstrp) + 1;
2350
2351     info->wki10_username = (DWORD) (cstrp - outp->datap);
2352     uidp = smb_FindUID(vcp, p->uid, 0);
2353     if (uidp) {
2354         lock_ObtainMutex(&uidp->mx);
2355         if(uidp->unp && uidp->unp->name)
2356             cm_ClientStringToUtf8(uidp->unp->name, -1,
2357                                   cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2358         lock_ReleaseMutex(&uidp->mx);
2359         smb_ReleaseUID(uidp);
2360     }
2361     cstrp += strlen(cstrp) + 1;
2362
2363     info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2364     StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2365     cstrp += strlen(cstrp) + 1;
2366
2367     /* TODO: Not sure what values these should take, but these work */
2368     info->wki10_ver_major = 5;
2369     info->wki10_ver_minor = 1;
2370
2371     info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2372     cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2373                           cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2374     cstrp += strlen(cstrp) + 1;
2375
2376     info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2377     cstrp ++; /* no other domains */
2378
2379     outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2380     outp->parmsp[2] = outp->totalData;
2381     outp->totalParms = totalParams;
2382
2383     smb_SendTran2Packet(vcp,outp,op);
2384     smb_FreeTran2Packet(outp);
2385
2386     return code;
2387 }
2388
2389 #pragma pack(push, 1)
2390
2391 typedef struct smb_rap_server_info_0 {
2392     BYTE    sv0_name[16];
2393 } smb_rap_server_info_0_t;
2394
2395 typedef struct smb_rap_server_info_1 {
2396     BYTE            sv1_name[16];
2397     BYTE            sv1_version_major;
2398     BYTE            sv1_version_minor;
2399     DWORD           sv1_type;
2400     DWORD           sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2401 } smb_rap_server_info_1_t;
2402
2403 #pragma pack(pop)
2404
2405 char smb_ServerComment[] = "OpenAFS Client";
2406 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2407
2408 #define SMB_SV_TYPE_SERVER              0x00000002L
2409 #define SMB_SV_TYPE_NT              0x00001000L
2410 #define SMB_SV_TYPE_SERVER_NT       0x00008000L
2411
2412 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2413 {
2414     smb_tran2Packet_t *outp;
2415     long code = 0;
2416     int infoLevel;
2417     int bufsize;
2418     unsigned short * tp;
2419     int totalData;
2420     int totalParams;
2421     smb_rap_server_info_0_t * info0;
2422     smb_rap_server_info_1_t * info1;
2423     char * cstrp;
2424
2425     tp = p->parmsp + 1; /* Skip over function number */
2426
2427     {
2428         clientchar_t * cdescp;
2429
2430         cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2431                                        SMB_STRF_FORCEASCII);
2432         if (cm_ClientStrCmp(cdescp,  _C("WrLh")))
2433             return CM_ERROR_INVAL;
2434         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2435                                        SMB_STRF_FORCEASCII);
2436         if (cm_ClientStrCmp(cdescp,  _C("B16")) ||
2437             cm_ClientStrCmp(cdescp,  _C("B16BBDz")))
2438             return CM_ERROR_INVAL;
2439     }
2440
2441     infoLevel = *tp++;
2442     bufsize = *tp++;
2443
2444     if (infoLevel != 0 && infoLevel != 1) {
2445         return CM_ERROR_INVAL;
2446     }
2447
2448     totalParams = 6;
2449
2450     totalData =
2451         (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2452         : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2453
2454     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2455
2456     memset(outp->parmsp,0,totalParams);
2457     memset(outp->datap,0,totalData);
2458
2459     if (infoLevel == 0) {
2460         info0 = (smb_rap_server_info_0_t *) outp->datap;
2461         cstrp = (char *) (info0 + 1);
2462         StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2463     } else { /* infoLevel == SMB_INFO_STANDARD */
2464         info1 = (smb_rap_server_info_1_t *) outp->datap;
2465         cstrp = (char *) (info1 + 1);
2466         StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2467
2468         info1->sv1_type =
2469             SMB_SV_TYPE_SERVER |
2470             SMB_SV_TYPE_NT |
2471             SMB_SV_TYPE_SERVER_NT;
2472
2473         info1->sv1_version_major = 5;
2474         info1->sv1_version_minor = 1;
2475         info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2476
2477         StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2478
2479         cstrp += smb_ServerCommentLen / sizeof(char);
2480     }
2481
2482     totalData = (DWORD)(cstrp - outp->datap);
2483     outp->totalData = min(bufsize,totalData); /* actual data size */
2484     outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2485     outp->parmsp[2] = totalData;
2486     outp->totalParms = totalParams;
2487
2488     smb_SendTran2Packet(vcp,outp,op);
2489     smb_FreeTran2Packet(outp);
2490
2491     return code;
2492 }
2493
2494 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2495 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2496 {
2497     smb_tran2Packet_t *asp;
2498     int totalParms;
2499     int totalData;
2500     int parmDisp;
2501     int dataDisp;
2502     int parmOffset;
2503     int dataOffset;
2504     int parmCount;
2505     int dataCount;
2506     int firstPacket;
2507     long code = 0;
2508     DWORD oldTime, newTime;
2509
2510     /* We sometimes see 0 word count.  What to do? */
2511     if (*inp->wctp == 0) {
2512         osi_Log0(smb_logp, "Transaction2 word count = 0");
2513         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2514
2515         smb_SetSMBDataLength(outp, 0);
2516         smb_SendPacket(vcp, outp);
2517         return 0;
2518     }
2519
2520     totalParms = smb_GetSMBParm(inp, 0);
2521     totalData = smb_GetSMBParm(inp, 1);
2522
2523     firstPacket = (inp->inCom == 0x32);
2524
2525     /* find the packet we're reassembling */
2526     lock_ObtainWrite(&smb_globalLock);
2527     asp = smb_FindTran2Packet(vcp, inp);
2528     if (!asp) {
2529         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2530     }
2531     lock_ReleaseWrite(&smb_globalLock);
2532
2533     /* now merge in this latest packet; start by looking up offsets */
2534     if (firstPacket) {
2535         parmDisp = dataDisp = 0;
2536         parmOffset = smb_GetSMBParm(inp, 10);
2537         dataOffset = smb_GetSMBParm(inp, 12);
2538         parmCount = smb_GetSMBParm(inp, 9);
2539         dataCount = smb_GetSMBParm(inp, 11);
2540         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2541         asp->maxReturnData = smb_GetSMBParm(inp, 3);
2542
2543         osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2544                  totalData, dataCount, asp->maxReturnData);
2545     }
2546     else {
2547         parmDisp = smb_GetSMBParm(inp, 4);
2548         parmOffset = smb_GetSMBParm(inp, 3);
2549         dataDisp = smb_GetSMBParm(inp, 7);
2550         dataOffset = smb_GetSMBParm(inp, 6);
2551         parmCount = smb_GetSMBParm(inp, 2);
2552         dataCount = smb_GetSMBParm(inp, 5);
2553
2554         osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2555                  parmCount, dataCount);
2556     }
2557
2558     /* now copy the parms and data */
2559     if ( asp->totalParms > 0 && parmCount != 0 )
2560     {
2561         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2562     }
2563     if ( asp->totalData > 0 && dataCount != 0 ) {
2564         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2565     }
2566
2567     /* account for new bytes */
2568     asp->curData += dataCount;
2569     asp->curParms += parmCount;
2570
2571     /* finally, if we're done, remove the packet from the queue and dispatch it */
2572     if (asp->totalParms > 0 &&
2573         asp->curParms > 0 &&
2574         asp->totalData <= asp->curData &&
2575         asp->totalParms <= asp->curParms) {
2576         /* we've received it all */
2577         lock_ObtainWrite(&smb_globalLock);
2578         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2579         lock_ReleaseWrite(&smb_globalLock);
2580
2581         oldTime = GetTickCount();
2582
2583         /* now dispatch it */
2584         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2585             osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2586             code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2587         }
2588         else {
2589             osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2590             code = CM_ERROR_BADOP;
2591         }
2592
2593         /* if an error is returned, we're supposed to send an error packet,
2594          * otherwise the dispatched function already did the data sending.
2595          * We give dispatched proc the responsibility since it knows how much
2596          * space to allocate.
2597          */
2598         if (code != 0) {
2599             smb_SendTran2Error(vcp, asp, outp, code);
2600         }
2601
2602         newTime = GetTickCount();
2603         if (newTime - oldTime > 45000) {
2604             smb_user_t *uidp;
2605             smb_fid_t *fidp;
2606             clientchar_t *treepath = NULL;  /* do not free */
2607             clientchar_t *pathname = NULL;
2608             cm_fid_t afid = {0,0,0,0,0};
2609
2610             uidp = smb_FindUID(vcp, asp->uid, 0);
2611             smb_LookupTIDPath(vcp, asp->tid, &treepath);
2612             fidp = smb_FindFID(vcp, inp->fid, 0);
2613
2614             if (fidp) {
2615                 lock_ObtainMutex(&fidp->mx);
2616                 if (fidp->NTopen_pathp)
2617                     pathname = fidp->NTopen_pathp;
2618                 if (fidp->scp)
2619                     afid = fidp->scp->fid;
2620             } else {
2621                 if (inp->stringsp->wdata)
2622                     pathname = inp->stringsp->wdata;
2623             }
2624
2625             afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
2626                       myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2627                       asp->uid, uidp ? uidp->unp->name : NULL,
2628                       asp->pid, asp->mid, asp->tid,
2629                       treepath,
2630                       pathname,
2631                       afid.cell, afid.volume, afid.vnode, afid.unique);
2632
2633             if (fidp)
2634                 lock_ReleaseMutex(&fidp->mx);
2635
2636             if (uidp)
2637                 smb_ReleaseUID(uidp);
2638             if (fidp)
2639                 smb_ReleaseFID(fidp);
2640         }
2641
2642         /* free the input tran 2 packet */
2643         smb_FreeTran2Packet(asp);
2644     }
2645     else if (firstPacket) {
2646         /* the first packet in a multi-packet request, we need to send an
2647          * ack to get more data.
2648          */
2649         smb_SetSMBDataLength(outp, 0);
2650         smb_SendPacket(vcp, outp);
2651     }
2652
2653     return 0;
2654 }
2655
2656 /* TRANS2_OPEN2 */
2657 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2658 {
2659     clientchar_t *pathp;
2660     smb_tran2Packet_t *outp;
2661     long code = 0;
2662     cm_space_t *spacep;
2663     int excl;
2664     cm_user_t *userp;
2665     cm_scache_t *dscp;          /* dir we're dealing with */
2666     cm_scache_t *scp;           /* file we're creating */
2667     cm_attr_t setAttr;
2668     smb_fid_t *fidp;
2669     int attributes;
2670     clientchar_t *lastNamep;
2671     afs_uint32 dosTime;
2672     int openFun;
2673     int trunc;
2674     int openMode;
2675     int extraInfo;
2676     int openAction;
2677     int parmSlot;                       /* which parm we're dealing with */
2678     long returnEALength;
2679     clientchar_t *tidPathp;
2680     cm_req_t req;
2681     int created = 0;
2682     BOOL is_rpc = FALSE;
2683     BOOL is_ipc = FALSE;
2684
2685     smb_InitReq(&req);
2686
2687     scp = NULL;
2688
2689     extraInfo = (p->parmsp[0] & 1);     /* return extra info */
2690     returnEALength = (p->parmsp[0] & 8);        /* return extended attr length */
2691
2692     openFun = p->parmsp[6];             /* open function */
2693     excl = ((openFun & 3) == 0);
2694     trunc = ((openFun & 3) == 2);       /* truncate it */
2695     openMode = (p->parmsp[1] & 0x7);
2696     openAction = 0;                     /* tracks what we did */
2697
2698     attributes = p->parmsp[3];
2699     dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2700
2701     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2702                                   SMB_STRF_ANSIPATH);
2703
2704     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2705
2706     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2707     if (code == CM_ERROR_TIDIPC) {
2708         is_ipc = TRUE;
2709         osi_Log0(smb_logp, "Tran2Open received IPC TID");
2710     }
2711
2712     spacep = cm_GetSpace();
2713     /* smb_StripLastComponent will strip "::$DATA" if present */
2714     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2715
2716     if (lastNamep &&
2717
2718         /* special case magic file name for receiving IOCTL requests
2719          * (since IOCTL calls themselves aren't getting through).
2720          */
2721         (cm_ClientStrCmpI(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
2722
2723          /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
2724          (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
2725
2726         unsigned short file_type = 0;
2727         unsigned short device_state = 0;
2728
2729         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2730
2731         if (is_rpc) {
2732             code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2733             osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2734                      fidp->fid, code);
2735             if (code) {
2736                 smb_ReleaseFID(fidp);
2737                 smb_FreeTran2Packet(outp);
2738                 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
2739                 return code;
2740             }
2741         } else {
2742             smb_SetupIoctlFid(fidp, spacep);
2743             osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2744         }
2745
2746         /* copy out remainder of the parms */
2747         parmSlot = 0;
2748         outp->parmsp[parmSlot++] = fidp->fid;
2749         if (extraInfo) {
2750             outp->parmsp[parmSlot++] = 0;       /* attrs */
2751             outp->parmsp[parmSlot++] = 0;       /* mod time */
2752             outp->parmsp[parmSlot++] = 0;
2753             outp->parmsp[parmSlot++] = 0;       /* len */
2754             outp->parmsp[parmSlot++] = 0x7fff;
2755             outp->parmsp[parmSlot++] = openMode;
2756             outp->parmsp[parmSlot++] = file_type;
2757             outp->parmsp[parmSlot++] = device_state;
2758         }
2759         /* and the final "always present" stuff */
2760         outp->parmsp[parmSlot++] = 1;           /* openAction found existing file */
2761         /* next write out the "unique" ID */
2762         outp->parmsp[parmSlot++] = 0x1234;
2763         outp->parmsp[parmSlot++] = 0x5678;
2764         outp->parmsp[parmSlot++] = 0;
2765         if (returnEALength) {
2766             outp->parmsp[parmSlot++] = 0;
2767             outp->parmsp[parmSlot++] = 0;
2768         }
2769
2770         outp->totalData = 0;
2771         outp->totalParms = parmSlot * 2;
2772
2773         smb_SendTran2Packet(vcp, outp, op);
2774
2775         smb_FreeTran2Packet(outp);
2776
2777         /* and clean up fid reference */
2778         smb_ReleaseFID(fidp);
2779         return 0;
2780     }
2781
2782 #ifndef DFS_SUPPORT
2783     if (is_ipc) {
2784         osi_Log1(smb_logp, "Tran2Open rejecting IPC TID vcp %p", vcp);
2785         smb_FreeTran2Packet(outp);
2786         return CM_ERROR_BADFD;
2787     }
2788 #endif
2789
2790     if (!cm_IsValidClientString(pathp)) {
2791 #ifdef DEBUG
2792         clientchar_t * hexp;
2793
2794         hexp = cm_GetRawCharsAlloc(pathp, -1);
2795         osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2796                  osi_LogSaveClientString(smb_logp, hexp));
2797         if (hexp)
2798             free(hexp);
2799 #else
2800         osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2801 #endif
2802         smb_FreeTran2Packet(outp);
2803         return CM_ERROR_BADNTFILENAME;
2804     }
2805
2806 #ifdef DEBUG_VERBOSE
2807     {
2808         char *hexp, *asciip;
2809         asciip = (lastNamep ? lastNamep : pathp);
2810         hexp = osi_HexifyString( asciip );
2811         DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2812         free(hexp);
2813     }
2814 #endif
2815
2816     userp = smb_GetTran2User(vcp, p);
2817     /* In the off chance that userp is NULL, we log and abandon */
2818     if (!userp) {
2819         osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2820         smb_FreeTran2Packet(outp);
2821         return CM_ERROR_BADSMB;
2822     }
2823
2824     dscp = NULL;
2825     code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
2826                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2827                      userp, tidPathp, &req, &scp);
2828     if (code != 0) {
2829         if (code == CM_ERROR_NOSUCHFILE ||
2830             code == CM_ERROR_NOSUCHPATH ||
2831             code == CM_ERROR_BPLUS_NOMATCH)
2832             code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
2833                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2834                             userp, tidPathp, &req, &dscp);
2835         cm_FreeSpace(spacep);
2836
2837         if (code) {
2838             cm_ReleaseUser(userp);
2839             smb_FreeTran2Packet(outp);
2840             return code;
2841         }
2842
2843 #ifdef DFS_SUPPORT
2844         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2845             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2846                                                       (clientchar_t*) spacep->data);
2847             cm_ReleaseSCache(dscp);
2848             cm_ReleaseUser(userp);
2849             smb_FreeTran2Packet(outp);
2850             if ( WANTS_DFS_PATHNAMES(p) || pnc )
2851                 return CM_ERROR_PATH_NOT_COVERED;
2852             else
2853                 return CM_ERROR_NOSUCHPATH;
2854         }
2855 #endif /* DFS_SUPPORT */
2856
2857         /* otherwise, scp points to the parent directory.  Do a lookup,
2858          * and truncate the file if we find it, otherwise we create the
2859          * file.
2860          */
2861         if (!lastNamep)
2862             lastNamep = pathp;
2863         else
2864             lastNamep++;
2865         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2866                          &req, &scp);
2867         if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2868             cm_ReleaseSCache(dscp);
2869             cm_ReleaseUser(userp);
2870             smb_FreeTran2Packet(outp);
2871             return code;
2872         }
2873     } else {
2874         /* macintosh is expensive to program for it */
2875         cm_FreeSpace(spacep);
2876
2877 #ifdef DFS_SUPPORT
2878         if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2879             int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2880             cm_ReleaseSCache(scp);
2881             cm_ReleaseUser(userp);
2882             smb_FreeTran2Packet(outp);
2883             if ( WANTS_DFS_PATHNAMES(p) || pnc )
2884                 return CM_ERROR_PATH_NOT_COVERED;
2885             else
2886                 return CM_ERROR_NOSUCHPATH;
2887         }
2888 #endif /* DFS_SUPPORT */
2889     }
2890
2891     /* if we get here, if code is 0, the file exists and is represented by
2892      * scp.  Otherwise, we have to create it.
2893      */
2894     if (code == 0) {
2895         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2896         if (code) {
2897             if (dscp)
2898                 cm_ReleaseSCache(dscp);
2899             cm_ReleaseSCache(scp);
2900             cm_ReleaseUser(userp);
2901             smb_FreeTran2Packet(outp);
2902             return code;
2903         }
2904
2905         if (excl) {
2906             /* oops, file shouldn't be there */
2907             if (dscp)
2908                 cm_ReleaseSCache(dscp);
2909             cm_ReleaseSCache(scp);
2910             cm_ReleaseUser(userp);
2911             smb_FreeTran2Packet(outp);
2912             return CM_ERROR_EXISTS;
2913         }
2914
2915         if (trunc) {
2916             setAttr.mask = CM_ATTRMASK_LENGTH;
2917             setAttr.length.LowPart = 0;
2918             setAttr.length.HighPart = 0;
2919             code = cm_SetAttr(scp, &setAttr, userp, &req);
2920             openAction = 3;     /* truncated existing file */
2921         }
2922         else
2923             openAction = 1;     /* found existing file */
2924     }
2925     else if (!(openFun & 0x10)) {
2926         /* don't create if not found */
2927         if (dscp)
2928             cm_ReleaseSCache(dscp);
2929         osi_assertx(scp == NULL, "null cm_scache_t");
2930         cm_ReleaseUser(userp);
2931         smb_FreeTran2Packet(outp);
2932         return CM_ERROR_NOSUCHFILE;
2933     }
2934     else {
2935         osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2936         openAction = 2; /* created file */
2937         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2938         cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2939         smb_SetInitialModeBitsForFile(attributes, &setAttr);
2940
2941         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2942                           &req);
2943         if (code == 0) {
2944             created = 1;
2945             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2946                 smb_NotifyChange(FILE_ACTION_ADDED,
2947                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2948                                   dscp, lastNamep, NULL, TRUE);
2949         } else if (!excl && code == CM_ERROR_EXISTS) {
2950             /* not an exclusive create, and someone else tried
2951              * creating it already, then we open it anyway.  We
2952              * don't bother retrying after this, since if this next
2953              * fails, that means that the file was deleted after we
2954              * started this call.
2955              */
2956             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2957                               userp, &req, &scp);
2958             if (code == 0) {
2959                 if (trunc) {
2960                     setAttr.mask = CM_ATTRMASK_LENGTH;
2961                     setAttr.length.LowPart = 0;
2962                     setAttr.length.HighPart = 0;
2963                     code = cm_SetAttr(scp, &setAttr, userp,
2964                                        &req);
2965                 }
2966             }   /* lookup succeeded */
2967         }
2968     }
2969
2970     /* we don't need this any longer */
2971     if (dscp)
2972         cm_ReleaseSCache(dscp);
2973
2974     if (code) {
2975         /* something went wrong creating or truncating the file */
2976         if (scp)
2977             cm_ReleaseSCache(scp);
2978         cm_ReleaseUser(userp);
2979         smb_FreeTran2Packet(outp);
2980         return code;
2981     }
2982
2983     /* make sure we're about to open a file */
2984     if (scp->fileType != CM_SCACHETYPE_FILE) {
2985         code = 0;
2986         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2987             cm_scache_t * targetScp = 0;
2988             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2989             if (code == 0) {
2990                 /* we have a more accurate file to use (the
2991                  * target of the symbolic link).  Otherwise,
2992                  * we'll just use the symlink anyway.
2993                  */
2994                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2995                           scp, targetScp);
2996                 cm_ReleaseSCache(scp);
2997                 scp = targetScp;
2998             }
2999         }
3000         if (scp->fileType != CM_SCACHETYPE_FILE) {
3001             cm_ReleaseSCache(scp);
3002             cm_ReleaseUser(userp);
3003             smb_FreeTran2Packet(outp);
3004             return CM_ERROR_ISDIR;
3005         }
3006     }
3007
3008     /* now all we have to do is open the file itself */
3009     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3010     osi_assertx(fidp, "null smb_fid_t");
3011
3012     cm_HoldUser(userp);
3013     lock_ObtainMutex(&fidp->mx);
3014     /* save a pointer to the vnode */
3015     osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
3016     fidp->scp = scp;
3017     lock_ObtainWrite(&scp->rw);
3018     scp->flags |= CM_SCACHEFLAG_SMB_FID;
3019     lock_ReleaseWrite(&scp->rw);
3020
3021     /* and the user */
3022     fidp->userp = userp;
3023
3024     /* compute open mode */
3025     if (openMode != 1)
3026         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
3027     if (openMode == 1 || openMode == 2)
3028         fidp->flags |= SMB_FID_OPENWRITE;
3029
3030     /* remember that the file was newly created */
3031     if (created)
3032         fidp->flags |= SMB_FID_CREATED;
3033
3034     lock_ReleaseMutex(&fidp->mx);
3035
3036     smb_ReleaseFID(fidp);
3037
3038     cm_Open(scp, 0, userp);
3039
3040     /* copy out remainder of the parms */
3041     parmSlot = 0;
3042     outp->parmsp[parmSlot++] = fidp->fid;
3043     lock_ObtainRead(&scp->rw);
3044     if (extraInfo) {
3045         outp->parmsp[parmSlot++] = smb_Attributes(scp);
3046         cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3047         outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
3048         outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
3049         outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
3050         outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
3051         outp->parmsp[parmSlot++] = openMode;
3052         outp->parmsp[parmSlot++] = 0;   /* file type 0 ==> normal file or dir */
3053         outp->parmsp[parmSlot++] = 0;   /* IPC junk */
3054     }
3055     /* and the final "always present" stuff */
3056     outp->parmsp[parmSlot++] = openAction;
3057     /* next write out the "unique" ID */
3058     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
3059     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
3060     outp->parmsp[parmSlot++] = 0;
3061     if (returnEALength) {
3062         outp->parmsp[parmSlot++] = 0;
3063         outp->parmsp[parmSlot++] = 0;
3064     }
3065     lock_ReleaseRead(&scp->rw);
3066     outp->totalData = 0;                /* total # of data bytes */
3067     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
3068
3069     smb_SendTran2Packet(vcp, outp, op);
3070
3071     smb_FreeTran2Packet(outp);
3072
3073     cm_ReleaseUser(userp);
3074     /* leave scp held since we put it in fidp->scp */
3075     return 0;
3076 }
3077
3078 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3079 {
3080     unsigned short fid;
3081     unsigned short infolevel;
3082
3083     infolevel = p->parmsp[0];
3084     fid = p->parmsp[1];
3085     osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
3086
3087     return CM_ERROR_BAD_LEVEL;
3088 }
3089
3090 /* TRANS2_QUERY_FS_INFORMATION */
3091 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3092 {
3093     smb_tran2Packet_t *outp;
3094     smb_tran2QFSInfo_t qi;
3095     int responseSize;
3096     size_t sz = 0;
3097
3098     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
3099
3100     switch (p->parmsp[0]) {
3101     case SMB_INFO_ALLOCATION:
3102         /* alloc info */
3103         responseSize = sizeof(qi.u.allocInfo);
3104
3105         qi.u.allocInfo.FSID = 0;
3106         qi.u.allocInfo.sectorsPerAllocUnit = 1;
3107         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
3108         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
3109         qi.u.allocInfo.bytesPerSector = 1024;
3110         break;
3111
3112     case SMB_INFO_VOLUME:
3113         /* volume info */
3114         qi.u.volumeInfo.vsn = 1234;  /* Volume serial number */
3115         qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
3116
3117         /* we're supposed to pad it out with zeroes to the end */
3118         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
3119         smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
3120
3121         responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
3122         break;
3123
3124     case SMB_QUERY_FS_VOLUME_INFO:
3125         /* FS volume info */
3126         responseSize = sizeof(qi.u.FSvolumeInfo);
3127
3128         {
3129             FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
3130             memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
3131         }
3132
3133         qi.u.FSvolumeInfo.vsn = 1234;
3134         qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
3135         memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
3136         memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
3137         break;
3138
3139     case SMB_QUERY_FS_SIZE_INFO:
3140         /* FS size info */
3141         responseSize = sizeof(qi.u.FSsizeInfo);
3142
3143         qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
3144         qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
3145         qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
3146         qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
3147         qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
3148         qi.u.FSsizeInfo.bytesPerSector = 1024;
3149         break;
3150
3151     case SMB_QUERY_FS_DEVICE_INFO:
3152         /* FS device info */
3153         responseSize = sizeof(qi.u.FSdeviceInfo);
3154
3155         qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
3156         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
3157         break;
3158
3159     case SMB_QUERY_FS_ATTRIBUTE_INFO:
3160         /* FS attribute info */
3161
3162         /* attributes, defined in WINNT.H:
3163          *      FILE_CASE_SENSITIVE_SEARCH      0x1
3164          *      FILE_CASE_PRESERVED_NAMES       0x2
3165          *      FILE_UNICODE_ON_DISK            0x4
3166          *      FILE_VOLUME_QUOTAS              0x10
3167          *      <no name defined>               0x4000
3168          *         If bit 0x4000 is not set, Windows 95 thinks
3169          *         we can't handle long (non-8.3) names,
3170          *         despite our protestations to the contrary.
3171          */
3172         qi.u.FSattributeInfo.attributes = 0x4003;
3173         /* The maxCompLength is supposed to be in bytes */
3174 #ifdef SMB_UNICODE
3175         qi.u.FSattributeInfo.attributes |= 0x04;
3176 #endif
3177         qi.u.FSattributeInfo.maxCompLength = 255;
3178         smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
3179         qi.u.FSattributeInfo.FSnameLength = sz;
3180
3181         responseSize =
3182             sizeof(qi.u.FSattributeInfo.attributes) +
3183             sizeof(qi.u.FSattributeInfo.maxCompLength) +
3184             sizeof(qi.u.FSattributeInfo.FSnameLength) +
3185             sz;
3186
3187         break;
3188
3189     case SMB_INFO_UNIX:         /* CIFS Unix Info */
3190     case SMB_INFO_MACOS:        /* Mac FS Info */
3191     default:
3192         return CM_ERROR_BADOP;
3193     }
3194
3195     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3196
3197     /* copy out return data, and set corresponding sizes */
3198     outp->totalParms = 0;
3199     outp->totalData = responseSize;
3200     memcpy(outp->datap, &qi, responseSize);
3201
3202     /* send and free the packets */
3203     smb_SendTran2Packet(vcp, outp, op);
3204     smb_FreeTran2Packet(outp);
3205
3206     return 0;
3207 }
3208
3209 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3210 {
3211     osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3212     return CM_ERROR_BADOP;
3213 }
3214
3215 struct smb_ShortNameRock {
3216     clientchar_t *maskp;
3217     unsigned int vnode;
3218     clientchar_t *shortName;
3219     size_t shortNameLen;
3220 };
3221
3222 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3223                          osi_hyper_t *offp)
3224 {
3225     struct smb_ShortNameRock *rockp;
3226     normchar_t normName[MAX_PATH];
3227     clientchar_t *shortNameEnd;
3228
3229     rockp = vrockp;
3230
3231     if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3232         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3233                  osi_LogSaveString(smb_logp, dep->name));
3234         return 0;
3235     }
3236
3237     /* compare both names and vnodes, though probably just comparing vnodes
3238      * would be safe enough.
3239      */
3240     if (cm_NormStrCmpI(normName,  rockp->maskp) != 0)
3241         return 0;
3242     if (ntohl(dep->fid.vnode) != rockp->vnode)
3243         return 0;
3244
3245     /* This is the entry */
3246     cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3247     rockp->shortNameLen = shortNameEnd - rockp->shortName;
3248
3249     return CM_ERROR_STOPNOW;
3250 }
3251
3252 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3253         clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3254 {
3255     struct smb_ShortNameRock rock;
3256     clientchar_t *lastNamep;
3257     cm_space_t *spacep;
3258     cm_scache_t *dscp;
3259     int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3260     long code = 0;
3261     osi_hyper_t thyper;
3262
3263     spacep = cm_GetSpace();
3264     /* smb_StripLastComponent will strip "::$DATA" if present */
3265     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3266
3267     code = cm_NameI(cm_RootSCachep(userp, reqp), spacep->wdata,
3268                     caseFold, userp, tidPathp,
3269                     reqp, &dscp);
3270     cm_FreeSpace(spacep);
3271     if (code)
3272         return code;
3273
3274 #ifdef DFS_SUPPORT
3275     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3276         cm_ReleaseSCache(dscp);
3277         cm_ReleaseUser(userp);
3278 #ifdef DEBUG
3279         DebugBreak();
3280 #endif
3281         return CM_ERROR_PATH_NOT_COVERED;
3282     }
3283 #endif /* DFS_SUPPORT */
3284
3285     if (!lastNamep) lastNamep = pathp;
3286     else lastNamep++;
3287     thyper.LowPart = 0;
3288     thyper.HighPart = 0;
3289     rock.shortName = shortName;
3290     rock.vnode = vnode;
3291     rock.maskp = lastNamep;
3292     code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3293
3294     cm_ReleaseSCache(dscp);
3295
3296     if (code == 0)
3297         return CM_ERROR_NOSUCHFILE;
3298     if (code == CM_ERROR_STOPNOW) {
3299         *shortNameLenp = rock.shortNameLen;
3300         return 0;
3301     }
3302     return code;
3303 }
3304
3305 /* TRANS2_QUERY_PATH_INFORMATION */
3306 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3307 {
3308     smb_tran2Packet_t *outp;
3309     afs_uint32 dosTime;
3310     FILETIME ft;
3311     unsigned short infoLevel;
3312     smb_tran2QPathInfo_t qpi;
3313     int responseSize;
3314     unsigned short attributes;
3315     unsigned long extAttributes;
3316     clientchar_t shortName[13];
3317     size_t len;
3318     cm_user_t *userp;
3319     cm_space_t *spacep;
3320     cm_scache_t *scp, *dscp;
3321     int scp_rw_held = 0;
3322     int delonclose = 0;
3323     long code = 0;
3324     clientchar_t *pathp;
3325     clientchar_t *tidPathp;
3326     clientchar_t *lastComp;
3327     cm_req_t req;
3328
3329     smb_InitReq(&req);
3330
3331     infoLevel = p->parmsp[0];
3332     if (infoLevel == SMB_INFO_IS_NAME_VALID)
3333         responseSize = 0;
3334     else if (infoLevel == SMB_INFO_STANDARD)
3335         responseSize = sizeof(qpi.u.QPstandardInfo);
3336     else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3337         responseSize = sizeof(qpi.u.QPeaSizeInfo);
3338     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3339         responseSize = sizeof(qpi.u.QPfileBasicInfo);
3340     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3341         responseSize = sizeof(qpi.u.QPfileStandardInfo);
3342     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3343         responseSize = sizeof(qpi.u.QPfileEaInfo);
3344     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3345         responseSize = sizeof(qpi.u.QPfileNameInfo);
3346     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3347         responseSize = sizeof(qpi.u.QPfileAllInfo);
3348     else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3349         responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3350     else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3351         responseSize = sizeof(qpi.u.QPfileStreamInfo);
3352     else {
3353         osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
3354                   p->opcode, infoLevel);
3355         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3356         return 0;
3357     }
3358     memset(&qpi, 0, sizeof(qpi));
3359
3360     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3361     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
3362               osi_LogSaveClientString(smb_logp, pathp));
3363
3364     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3365
3366     if (infoLevel > 0x100)
3367         outp->totalParms = 2;
3368     else
3369         outp->totalParms = 0;
3370
3371     /* now, if we're at infoLevel 6, we're only being asked to check
3372      * the syntax, so we just OK things now.  In particular, we're *not*
3373      * being asked to verify anything about the state of any parent dirs.
3374      */
3375     if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3376         smb_SendTran2Packet(vcp, outp, opx);
3377         smb_FreeTran2Packet(outp);
3378         return 0;
3379     }
3380
3381     userp = smb_GetTran2User(vcp, p);
3382     if (!userp) {
3383         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3384         smb_FreeTran2Packet(outp);
3385         return CM_ERROR_BADSMB;
3386     }
3387
3388     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3389     if(code) {
3390         osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
3391         cm_ReleaseUser(userp);
3392         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3393         smb_FreeTran2Packet(outp);
3394         return 0;
3395     }
3396
3397     osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
3398               osi_LogSaveClientString(smb_logp, tidPathp));
3399
3400     /*
3401      * XXX Strange hack XXX
3402      *
3403      * As of Patch 7 (13 January 98), we are having the following problem:
3404      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3405      * requests to look up "desktop.ini" in all the subdirectories.
3406      * This can cause zillions of timeouts looking up non-existent cells
3407      * and volumes, especially in the top-level directory.
3408      *
3409      * We have not found any way to avoid this or work around it except
3410      * to explicitly ignore the requests for mount points that haven't
3411      * yet been evaluated and for directories that haven't yet been
3412      * fetched.
3413      */
3414     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3415         spacep = cm_GetSpace();
3416         /* smb_StripLastComponent will strip "::$DATA" if present */
3417         smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3418 #ifndef SPECIAL_FOLDERS
3419         /* Make sure that lastComp is not NULL */
3420         if (lastComp) {
3421             if (cm_ClientStrCmpIA(lastComp,  _C("\\desktop.ini")) == 0) {
3422                 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3423                                  CM_FLAG_CASEFOLD
3424                                  | CM_FLAG_DIRSEARCH
3425                                  | CM_FLAG_FOLLOW,
3426                                  userp, tidPathp, &req, &dscp);
3427                 if (code == 0) {
3428 #ifdef DFS_SUPPORT
3429                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3430                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3431                                                                   spacep->wdata);
3432                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3433                             code = CM_ERROR_PATH_NOT_COVERED;
3434                         else
3435                             code = CM_ERROR_NOSUCHPATH;
3436                     } else
3437 #endif /* DFS_SUPPORT */
3438                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3439                         code = CM_ERROR_NOSUCHFILE;
3440                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3441                         cm_buf_t *bp = buf_Find(dscp, &hzero);
3442                         if (bp) {
3443                             buf_Release(bp);
3444                             bp = NULL;
3445                         }
3446                         else
3447                             code = CM_ERROR_NOSUCHFILE;
3448                     }
3449                     cm_ReleaseSCache(dscp);
3450                     if (code) {
3451                         cm_FreeSpace(spacep);
3452                         cm_ReleaseUser(userp);
3453                         smb_SendTran2Error(vcp, p, opx, code);
3454                         smb_FreeTran2Packet(outp);
3455                         return 0;
3456                     }
3457                 }
3458             }
3459         }
3460 #endif /* SPECIAL_FOLDERS */
3461
3462         cm_FreeSpace(spacep);
3463     }
3464
3465     if (code == 0 ||
3466         code == CM_ERROR_NOSUCHFILE ||
3467         code == CM_ERROR_NOSUCHPATH ||
3468         code == CM_ERROR_BPLUS_NOMATCH) {
3469         /* now do namei and stat, and copy out the info */
3470         code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3471                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3472     }
3473
3474     if (code) {
3475         cm_ReleaseUser(userp);
3476         smb_SendTran2Error(vcp, p, opx, code);
3477         smb_FreeTran2Packet(outp);
3478         return 0;
3479     }
3480
3481 #ifdef DFS_SUPPORT
3482     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3483         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3484         cm_ReleaseSCache(scp);
3485         cm_ReleaseUser(userp);
3486         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3487             code = CM_ERROR_PATH_NOT_COVERED;
3488         else
3489             code = CM_ERROR_NOSUCHPATH;
3490         smb_SendTran2Error(vcp, p, opx, code);
3491         smb_FreeTran2Packet(outp);
3492         return 0;
3493     }
3494 #endif /* DFS_SUPPORT */
3495
3496     lock_ObtainWrite(&scp->rw);
3497     scp_rw_held = 2;
3498     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3499                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3500     if (code)
3501         goto done;
3502
3503     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3504
3505     lock_ConvertWToR(&scp->rw);
3506     scp_rw_held = 1;
3507
3508     len = 0;
3509
3510     /* now we have the status in the cache entry, and everything is locked.
3511      * Marshall the output data.
3512      */
3513     /* for info level 108, figure out short name */
3514     if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3515         code = cm_GetShortName(pathp, userp, &req,
3516                                 tidPathp, scp->fid.vnode, shortName,
3517                                &len);
3518         if (code) {
3519             goto done;
3520         }
3521
3522         smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3523         qpi.u.QPfileAltNameInfo.fileNameLength = len;
3524         responseSize = sizeof(unsigned long) + len;
3525     }
3526     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3527         smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3528         qpi.u.QPfileNameInfo.fileNameLength = len;
3529         responseSize = sizeof(unsigned long) + len;
3530     }
3531     else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3532         cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3533         qpi.u.QPstandardInfo.creationDateTime = dosTime;
3534         qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3535         qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3536         qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3537         qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3538         attributes = smb_Attributes(scp);
3539         qpi.u.QPstandardInfo.attributes = attributes;
3540         qpi.u.QPstandardInfo.eaSize = 0;
3541     }
3542     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3543         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3544         qpi.u.QPfileBasicInfo.creationTime = ft;
3545         qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3546         qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3547         qpi.u.QPfileBasicInfo.changeTime = ft;
3548         extAttributes = smb_ExtAttributes(scp);
3549         qpi.u.QPfileBasicInfo.attributes = extAttributes;
3550         qpi.u.QPfileBasicInfo.reserved = 0;
3551     }
3552     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3553         smb_fid_t * fidp;
3554
3555         lock_ReleaseRead(&scp->rw);
3556         scp_rw_held = 0;
3557         fidp = smb_FindFIDByScache(vcp, scp);
3558
3559         qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3560         qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3561         qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3562         qpi.u.QPfileStandardInfo.directory =
3563             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3564               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3565               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3566         qpi.u.QPfileStandardInfo.reserved = 0;
3567
3568         if (fidp) {
3569             lock_ObtainMutex(&fidp->mx);
3570             delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3571             lock_ReleaseMutex(&fidp->mx);
3572             smb_ReleaseFID(fidp);
3573         }
3574         qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3575     }
3576     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3577         qpi.u.QPfileEaInfo.eaSize = 0;
3578     }
3579     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3580         smb_fid_t * fidp;
3581
3582         lock_ReleaseRead(&scp->rw);
3583         scp_rw_held = 0;
3584         fidp = smb_FindFIDByScache(vcp, scp);
3585
3586         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3587         qpi.u.QPfileAllInfo.creationTime = ft;
3588         qpi.u.QPfileAllInfo.lastAccessTime = ft;
3589         qpi.u.QPfileAllInfo.lastWriteTime = ft;
3590         qpi.u.QPfileAllInfo.changeTime = ft;
3591         extAttributes = smb_ExtAttributes(scp);
3592         qpi.u.QPfileAllInfo.attributes = extAttributes;
3593         qpi.u.QPfileAllInfo.allocationSize = scp->length;
3594         qpi.u.QPfileAllInfo.endOfFile = scp->length;
3595         qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3596         qpi.u.QPfileAllInfo.deletePending = 0;
3597         qpi.u.QPfileAllInfo.directory =
3598             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3599               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3600               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3601         qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
3602         qpi.u.QPfileAllInfo.indexNumber.LowPart  = scp->fid.unique;
3603         qpi.u.QPfileAllInfo.eaSize = 0;
3604         qpi.u.QPfileAllInfo.accessFlags = 0;
3605         if (fidp) {
3606             lock_ObtainMutex(&fidp->mx);
3607             if (fidp->flags & SMB_FID_OPENDELETE)
3608                 qpi.u.QPfileAllInfo.accessFlags |= DELETE;
3609             if (fidp->flags & SMB_FID_OPENREAD_LISTDIR)
3610                 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_READ|AFS_ACCESS_EXECUTE;
3611             if (fidp->flags & SMB_FID_OPENWRITE)
3612                 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_WRITE;
3613             if (fidp->flags & SMB_FID_DELONCLOSE)
3614                 qpi.u.QPfileAllInfo.deletePending = 1;
3615             lock_ReleaseMutex(&fidp->mx);
3616             smb_ReleaseFID(fidp);
3617         }
3618         qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.cell;
3619         qpi.u.QPfileAllInfo.indexNumber2.LowPart  = scp->fid.volume;
3620         qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3621         qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3622         qpi.u.QPfileAllInfo.mode = 0;
3623         qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3624
3625         smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3626         qpi.u.QPfileAllInfo.fileNameLength = len;
3627         responseSize -= (sizeof(qpi.u.QPfileAllInfo.fileName) - len);
3628     }
3629     else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3630         size_t len = 0;
3631         /* For now we have no streams */
3632         qpi.u.QPfileStreamInfo.nextEntryOffset = 0;
3633         if (scp->fileType == CM_SCACHETYPE_FILE) {
3634             qpi.u.QPfileStreamInfo.streamSize = scp->length;
3635             qpi.u.QPfileStreamInfo.streamAllocationSize = scp->length;
3636             smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3637             qpi.u.QPfileStreamInfo.streamNameLength = len;
3638             responseSize -= (sizeof(qpi.u.QPfileStreamInfo.fileName) - len);
3639         } else {
3640             qpi.u.QPfileStreamInfo.streamSize.QuadPart = 0;
3641             qpi.u.QPfileStreamInfo.streamAllocationSize.QuadPart = 0;
3642             smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"", &len, SMB_STRF_IGNORENUL);
3643             qpi.u.QPfileStreamInfo.streamNameLength = 0;
3644             responseSize = 0;
3645         }
3646     }
3647     outp->totalData = responseSize;
3648
3649     /* send and free the packets */
3650   done:
3651     switch (scp_rw_held) {
3652     case 1:
3653         lock_ReleaseRead(&scp->rw);
3654         break;
3655     case 2:
3656         lock_ReleaseWrite(&scp->rw);
3657         break;
3658     }
3659     scp_rw_held = 0;
3660     cm_ReleaseSCache(scp);
3661     cm_ReleaseUser(userp);
3662     if (code == 0) {
3663         memcpy(outp->datap, &qpi, responseSize);
3664         smb_SendTran2Packet(vcp, outp, opx);
3665     } else {
3666         smb_SendTran2Error(vcp, p, opx, code);
3667     }
3668     smb_FreeTran2Packet(outp);
3669
3670     return 0;
3671 }
3672
3673 /* TRANS2_SET_PATH_INFORMATION */
3674 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3675 {
3676 #if 0
3677     osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3678     return CM_ERROR_BADOP;
3679 #else
3680     long code = 0;
3681     unsigned short infoLevel;
3682     clientchar_t * pathp;
3683     smb_tran2Packet_t *outp;
3684     smb_tran2QPathInfo_t *spi;
3685     cm_user_t *userp;
3686     cm_scache_t *scp, *dscp;
3687     cm_req_t req;
3688     cm_space_t *spacep;
3689     clientchar_t *tidPathp;
3690     clientchar_t *lastComp;
3691
3692     smb_InitReq(&req);
3693
3694     infoLevel = p->parmsp[0];
3695     osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3696     if (infoLevel != SMB_INFO_STANDARD &&
3697         infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3698         infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3699         osi_Log2(smb_logp, "Bad Tran2SetPathInfo op 0x%x infolevel 0x%x",
3700                   p->opcode, infoLevel);
3701         smb_SendTran2Error(vcp, p, opx,
3702                            infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3703         return 0;
3704     }
3705
3706     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3707
3708     osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3709               osi_LogSaveClientString(smb_logp, pathp));
3710
3711     userp = smb_GetTran2User(vcp, p);
3712     if (!userp) {
3713         osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3714         code = CM_ERROR_BADSMB;
3715         goto done;
3716     }
3717
3718     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3719     if (code == CM_ERROR_TIDIPC) {
3720         /* Attempt to use a TID allocated for IPC.  The client
3721          * is probably looking for DCE RPC end points which we
3722          * don't support OR it could be looking to make a DFS
3723          * referral request.
3724          */
3725         osi_Log0(smb_logp, "Tran2Open received IPC TID");
3726         cm_ReleaseUser(userp);
3727         return CM_ERROR_NOSUCHPATH;
3728     }
3729
3730     /*
3731     * XXX Strange hack XXX
3732     *
3733     * As of Patch 7 (13 January 98), we are having the following problem:
3734     * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3735     * requests to look up "desktop.ini" in all the subdirectories.
3736     * This can cause zillions of timeouts looking up non-existent cells
3737     * and volumes, especially in the top-level directory.
3738     *
3739     * We have not found any way to avoid this or work around it except
3740     * to explicitly ignore the requests for mount points that haven't
3741     * yet been evaluated and for directories that haven't yet been
3742     * fetched.
3743     */
3744     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3745         spacep = cm_GetSpace();
3746         /* smb_StripLastComponent will strip "::$DATA" if present */
3747         smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3748 #ifndef SPECIAL_FOLDERS
3749         /* Make sure that lastComp is not NULL */
3750         if (lastComp) {
3751             if (cm_ClientStrCmpI(lastComp,  _C("\\desktop.ini")) == 0) {
3752                 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3753                                  CM_FLAG_CASEFOLD
3754                                  | CM_FLAG_DIRSEARCH
3755                                  | CM_FLAG_FOLLOW,
3756                                  userp, tidPathp, &req, &dscp);
3757                 if (code == 0) {
3758 #ifdef DFS_SUPPORT
3759                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3760                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3761                                                                   spacep->wdata);
3762                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3763                             code = CM_ERROR_PATH_NOT_COVERED;
3764                         else
3765                             code = CM_ERROR_NOSUCHPATH;
3766                     } else
3767 #endif /* DFS_SUPPORT */
3768                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3769                         code = CM_ERROR_NOSUCHFILE;
3770                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3771                         cm_buf_t *bp = buf_Find(dscp, &hzero);
3772                         if (bp) {
3773                             buf_Release(bp);
3774                             bp = NULL;
3775                         }
3776                         else
3777                             code = CM_ERROR_NOSUCHFILE;
3778                     }
3779                     cm_ReleaseSCache(dscp);
3780                     if (code) {
3781                         cm_FreeSpace(spacep);
3782                         cm_ReleaseUser(userp);
3783                         smb_SendTran2Error(vcp, p, opx, code);
3784                         return 0;
3785                     }
3786                 }
3787             }
3788         }
3789 #endif /* SPECIAL_FOLDERS */
3790
3791         cm_FreeSpace(spacep);
3792     }
3793
3794     if (code == 0 ||
3795         code == CM_ERROR_NOSUCHFILE ||
3796         code == CM_ERROR_NOSUCHPATH ||
3797         code == CM_ERROR_BPLUS_NOMATCH) {
3798         /* now do namei and stat, and copy out the info */
3799         code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3800                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3801     }
3802
3803     if (code) {
3804         cm_ReleaseUser(userp);
3805         smb_SendTran2Error(vcp, p, opx, code);
3806         return 0;
3807     }
3808
3809     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3810
3811     outp->totalParms = 2;
3812     outp->totalData = 0;
3813
3814     spi = (smb_tran2QPathInfo_t *)p->datap;
3815     if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3816         cm_attr_t attr;
3817
3818         /* lock the vnode with a callback; we need the current status
3819          * to determine what the new status is, in some cases.
3820          */
3821         lock_ObtainWrite(&scp->rw);
3822         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3823                           CM_SCACHESYNC_GETSTATUS
3824                          | CM_SCACHESYNC_NEEDCALLBACK);
3825         if (code) {
3826             lock_ReleaseWrite(&scp->rw);
3827             goto done;
3828         }
3829         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3830
3831         /* prepare for setattr call */
3832         attr.mask = CM_ATTRMASK_LENGTH;
3833         attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3834         attr.length.HighPart = 0;
3835
3836         if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3837             cm_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3838             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3839         }
3840
3841         if (spi->u.QPstandardInfo.attributes != 0) {
3842             if ((scp->unixModeBits & 0200)
3843                  && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3844                 /* make a writable file read-only */
3845                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3846                 attr.unixModeBits = scp->unixModeBits & ~0222;
3847             }
3848             else if ((scp->unixModeBits & 0200) == 0
3849                       && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3850                 /* make a read-only file writable */
3851                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3852                 attr.unixModeBits = scp->unixModeBits | 0222;
3853             }
3854         }
3855         lock_ReleaseRead(&scp->rw);
3856
3857         /* call setattr */
3858         if (attr.mask)
3859             code = cm_SetAttr(scp, &attr, userp, &req);
3860         else
3861             code = 0;
3862     }
3863     else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3864         /* we don't support EAs */
3865         code = CM_ERROR_EAS_NOT_SUPPORTED;
3866     }
3867
3868   done:
3869     cm_ReleaseSCache(scp);
3870     cm_ReleaseUser(userp);
3871     if (code == 0)
3872         smb_SendTran2Packet(vcp, outp, opx);
3873     else
3874         smb_SendTran2Error(vcp, p, opx, code);
3875     smb_FreeTran2Packet(outp);
3876
3877     return 0;
3878 #endif
3879 }
3880
3881 /* TRANS2_QUERY_FILE_INFORMATION */
3882 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3883 {
3884     smb_tran2Packet_t *outp;
3885     FILETIME ft;
3886     unsigned long attributes;
3887     unsigned short infoLevel;
3888     int responseSize;
3889     unsigned short fid;
3890     int delonclose = 0;
3891     cm_user_t *userp;
3892     smb_fid_t *fidp;
3893     cm_scache_t *scp;
3894     smb_tran2QFileInfo_t qfi;
3895     long code = 0;
3896     int  readlock = 0;
3897     cm_req_t req;
3898
3899     smb_InitReq(&req);
3900
3901     fid = p->parmsp[0];
3902     fidp = smb_FindFID(vcp, fid, 0);
3903
3904     if (fidp == NULL) {
3905         osi_Log2(smb_logp, "Tran2QFileInfo Unknown SMB Fid vcp 0x%p fid %d",
3906                  vcp, fid);
3907         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3908         return 0;
3909     }
3910
3911     lock_ObtainMutex(&fidp->mx);
3912     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3913         lock_ReleaseMutex(&fidp->mx);
3914         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3915         smb_CloseFID(vcp, fidp, NULL, 0);
3916         smb_ReleaseFID(fidp);
3917         return 0;
3918     }
3919     lock_ReleaseMutex(&fidp->mx);
3920
3921     infoLevel = p->parmsp[1];
3922     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3923         responseSize = sizeof(qfi.u.QFbasicInfo);
3924     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3925         responseSize = sizeof(qfi.u.QFstandardInfo);
3926     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3927         responseSize = sizeof(qfi.u.QFeaInfo);
3928     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3929         responseSize = sizeof(qfi.u.QFfileNameInfo);
3930     else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3931         responseSize = sizeof(qfi.u.QFfileStreamInfo);
3932     else {
3933         osi_Log2(smb_logp, "Bad Tran2QFileInfo op 0x%x infolevel 0x%x",
3934                   p->opcode, infoLevel);
3935         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3936         smb_ReleaseFID(fidp);
3937         return 0;
3938     }
3939     osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3940     memset(&qfi, 0, sizeof(qfi));
3941
3942     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3943
3944     if (infoLevel > 0x100)
3945         outp->totalParms = 2;
3946     else
3947         outp->totalParms = 0;
3948
3949     userp = smb_GetTran2User(vcp, p);
3950     if (!userp) {
3951         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3952         code = CM_ERROR_BADSMB;
3953         goto done;
3954     }
3955
3956     lock_ObtainMutex(&fidp->mx);
3957     delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3958     scp = fidp->scp;
3959     osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3960     cm_HoldSCache(scp);
3961     lock_ReleaseMutex(&fidp->mx);
3962     lock_ObtainWrite(&scp->rw);
3963     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3964                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3965     if (code)
3966         goto done;
3967
3968     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3969
3970     lock_ConvertWToR(&scp->rw);
3971     readlock = 1;
3972
3973     /* now we have the status in the cache entry, and everything is locked.
3974      * Marshall the output data.
3975      */
3976     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3977         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3978         qfi.u.QFbasicInfo.creationTime = ft;
3979         qfi.u.QFbasicInfo.lastAccessTime = ft;
3980         qfi.u.QFbasicInfo.lastWriteTime = ft;
3981         qfi.u.QFbasicInfo.lastChangeTime = ft;
3982         attributes = smb_ExtAttributes(scp);
3983         qfi.u.QFbasicInfo.attributes = attributes;
3984     }
3985     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3986         qfi.u.QFstandardInfo.allocationSize = scp->length;
3987         qfi.u.QFstandardInfo.endOfFile = scp->length;
3988         qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3989         qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3990         qfi.u.QFstandardInfo.directory =
3991             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3992               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3993               scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3994     }
3995     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3996         qfi.u.QFeaInfo.eaSize = 0;
3997     }
3998     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3999         size_t len = 0;
4000         clientchar_t *name;
4001
4002         lock_ReleaseRead(&scp->rw);
4003         lock_ObtainMutex(&fidp->mx);
4004         lock_ObtainRead(&scp->rw);
4005         if (fidp->NTopen_wholepathp)
4006             name = fidp->NTopen_wholepathp;
4007         else
4008             name = _C("\\");    /* probably can't happen */
4009         lock_ReleaseMutex(&fidp->mx);
4010
4011         smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
4012         responseSize = len + 4; /* this is actually what we want to return */
4013         qfi.u.QFfileNameInfo.fileNameLength = len;
4014     }
4015     else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
4016         size_t len = 0;
4017
4018         if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
4019             scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4020             scp->fileType == CM_SCACHETYPE_INVALID) {
4021             /* Do not return the alternate streams for directories */
4022             responseSize = 0;
4023         } else {
4024             /* For now we have no alternate streams */
4025             qfi.u.QFfileStreamInfo.nextEntryOffset = 0;
4026             qfi.u.QFfileStreamInfo.streamSize = scp->length;
4027             qfi.u.QFfileStreamInfo.streamAllocationSize = scp->length;
4028             smb_UnparseString(opx, qfi.u.QFfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
4029             qfi.u.QFfileStreamInfo.streamNameLength = len;
4030             responseSize -= (sizeof(qfi.u.QFfileStreamInfo.fileName) - len);
4031         }
4032     }
4033     outp->totalData = responseSize;
4034
4035     /* send and free the packets */
4036   done:
4037     if (readlock)
4038         lock_ReleaseRead(&scp->rw);
4039     else
4040         lock_ReleaseWrite(&scp->rw);
4041     cm_ReleaseSCache(scp);
4042     cm_ReleaseUser(userp);
4043     smb_ReleaseFID(fidp);
4044     if (code == 0) {
4045         memcpy(outp->datap, &qfi, responseSize);
4046         smb_SendTran2Packet(vcp, outp, opx);
4047     } else {
4048         smb_SendTran2Error(vcp, p, opx, code);
4049     }
4050     smb_FreeTran2Packet(outp);
4051
4052     return 0;
4053 }
4054
4055
4056 /* TRANS2_SET_FILE_INFORMATION */
4057 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4058 {
4059     long code = 0;
4060     unsigned short fid;
4061     smb_fid_t *fidp;
4062     unsigned short infoLevel;
4063     smb_tran2Packet_t *outp;
4064     cm_user_t *userp = NULL;
4065     cm_scache_t *scp = NULL;
4066     cm_req_t req;
4067
4068     smb_InitReq(&req);
4069
4070     fid = p->parmsp[0];
4071     fidp = smb_FindFID(vcp, fid, 0);
4072
4073     if (fidp == NULL) {
4074         osi_Log2(smb_logp, "Tran2SetFileInfo Unknown SMB Fid vcp 0x%p fid %d",
4075                  vcp, fid);
4076         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
4077         return 0;
4078     }
4079
4080     infoLevel = p->parmsp[1];
4081     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
4082     if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
4083         osi_Log2(smb_logp, "Bad Tran2SetFileInfo op 0x%x infolevel 0x%x",
4084                   p->opcode, infoLevel);
4085         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
4086         smb_ReleaseFID(fidp);
4087         return 0;
4088     }
4089
4090     lock_ObtainMutex(&fidp->mx);
4091     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
4092         lock_ReleaseMutex(&fidp->mx);
4093         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
4094         smb_CloseFID(vcp, fidp, NULL, 0);
4095         smb_ReleaseFID(fidp);
4096         return 0;
4097     }
4098
4099     if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
4100         !(fidp->flags & SMB_FID_OPENDELETE)) {
4101         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
4102                   fidp, fidp->scp, fidp->flags);
4103         lock_ReleaseMutex(&fidp->mx);
4104         smb_ReleaseFID(fidp);
4105         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
4106         return 0;
4107     }
4108     if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4109          infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
4110          && !(fidp->flags & SMB_FID_OPENWRITE)) {
4111         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
4112                   fidp, fidp->scp, fidp->flags);
4113         lock_ReleaseMutex(&fidp->mx);
4114         smb_ReleaseFID(fidp);
4115         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
4116         return 0;
4117     }
4118
4119     scp = fidp->scp;
4120     osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
4121     cm_HoldSCache(scp);
4122     lock_ReleaseMutex(&fidp->mx);
4123
4124     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
4125
4126     outp->totalParms = 2;
4127     outp->totalData = 0;
4128
4129     userp = smb_GetTran2User(vcp, p);
4130     if (!userp) {
4131         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
4132         code = CM_ERROR_BADSMB;
4133         goto done;
4134     }
4135
4136     if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
4137         FILETIME lastMod;
4138         unsigned int attribute;
4139         cm_attr_t attr;
4140         smb_tran2QFileInfo_t *sfi;
4141
4142         sfi = (smb_tran2QFileInfo_t *)p->datap;
4143
4144         /* lock the vnode with a callback; we need the current status
4145          * to determine what the new status is, in some cases.
4146          */
4147         lock_ObtainWrite(&scp->rw);
4148         code = cm_SyncOp(scp, NULL, userp, &req, 0,
4149                           CM_SCACHESYNC_GETSTATUS
4150                          | CM_SCACHESYNC_NEEDCALLBACK);
4151         if (code) {
4152             lock_ReleaseWrite(&scp->rw);
4153             goto done;
4154         }
4155
4156         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4157
4158         lock_ReleaseWrite(&scp->rw);
4159         lock_ObtainMutex(&fidp->mx);
4160         lock_ObtainRead(&scp->rw);
4161
4162         /* prepare for setattr call */
4163         attr.mask = 0;
4164
4165         lastMod = sfi->u.QFbasicInfo.lastWriteTime;
4166         /* when called as result of move a b, lastMod is (-1, -1).
4167          * If the check for -1 is not present, timestamp
4168          * of the resulting file will be 1969 (-1)
4169          */
4170         if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
4171              lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
4172             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4173             cm_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
4174             fidp->flags |= SMB_FID_MTIMESETDONE;
4175         }
4176
4177         attribute = sfi->u.QFbasicInfo.attributes;
4178         if (attribute != 0) {
4179             if ((scp->unixModeBits & 0200)
4180                  && (attribute & SMB_ATTR_READONLY) != 0) {
4181                 /* make a writable file read-only */
4182                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4183                 attr.unixModeBits = scp->unixModeBits & ~0222;
4184             }
4185             else if ((scp->unixModeBits & 0200) == 0
4186                       && (attribute & SMB_ATTR_READONLY) == 0) {
4187                 /* make a read-only file writable */
4188                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4189                 attr.unixModeBits = scp->unixModeBits | 0222;
4190             }
4191         }
4192         lock_ReleaseRead(&scp->rw);
4193         lock_ReleaseMutex(&fidp->mx);
4194
4195         /* call setattr */
4196         if (attr.mask)
4197             code = cm_SetAttr(scp, &attr, userp, &req);
4198         else
4199             code = 0;
4200     }
4201     else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
4202         int delflag = *((char *)(p->datap));
4203         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
4204                  delflag, fidp, scp);
4205         if (*((char *)(p->datap))) {    /* File is Deleted */
4206             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
4207                                      &req);
4208             if (code == 0) {
4209                 lock_ObtainMutex(&fidp->mx);
4210                 fidp->flags |= SMB_FID_DELONCLOSE;
4211                 lock_ReleaseMutex(&fidp->mx);
4212             } else {
4213                 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
4214                          fidp, scp, code);
4215             }
4216         }
4217         else {
4218             code = 0;
4219             lock_ObtainMutex(&fidp->mx);
4220             fidp->flags &= ~SMB_FID_DELONCLOSE;
4221             lock_ReleaseMutex(&fidp->mx);
4222         }
4223     }
4224     else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4225              infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
4226         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
4227         cm_attr_t attr;
4228
4229         attr.mask = CM_ATTRMASK_LENGTH;
4230         attr.length.LowPart = size.LowPart;
4231         attr.length.HighPart = size.HighPart;
4232         code = cm_SetAttr(scp, &attr, userp, &req);
4233     }
4234
4235   done:
4236     cm_ReleaseSCache(scp);
4237     cm_ReleaseUser(userp);
4238     smb_ReleaseFID(fidp);
4239     if (code == 0)
4240         smb_SendTran2Packet(vcp, outp, opx);
4241     else
4242         smb_SendTran2Error(vcp, p, opx, code);
4243     smb_FreeTran2Packet(outp);
4244
4245     return 0;
4246 }
4247
4248 /* TRANS2_FSCTL */
4249 long
4250 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4251 {
4252     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
4253     return CM_ERROR_BADOP;
4254 }
4255
4256 /* TRANS2_IOCTL2 */
4257 long
4258 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4259 {
4260     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
4261     return CM_ERROR_BADOP;
4262 }
4263
4264 /* TRANS2_FIND_NOTIFY_FIRST */
4265 long
4266 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4267 {
4268     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
4269     return CM_ERROR_BADOP;
4270 }
4271
4272 /* TRANS2_FIND_NOTIFY_NEXT */
4273 long
4274 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4275 {
4276     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
4277     return CM_ERROR_BADOP;
4278 }
4279
4280 /* TRANS2_CREATE_DIRECTORY */
4281 long
4282 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4283 {
4284     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
4285     return CM_ERROR_BADOP;
4286 }
4287
4288 /* TRANS2_SESSION_SETUP */
4289 long
4290 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4291 {
4292     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
4293     return CM_ERROR_BADOP;
4294 }
4295
4296 struct smb_v2_referral {
4297     USHORT ServerType;
4298     USHORT ReferralFlags;
4299     ULONG  Proximity;
4300     ULONG  TimeToLive;
4301     USHORT DfsPathOffset;
4302     USHORT DfsAlternativePathOffset;
4303     USHORT NetworkAddressOffset;
4304 };
4305
4306 /* TRANS2_GET_DFS_REFERRAL */
4307 long
4308 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
4309 {
4310     /* This is a UNICODE only request (bit15 of Flags2) */
4311     /* The TID must be IPC$ */
4312
4313     /* The documentation for the Flags response field is contradictory */
4314
4315     /* Use Version 1 Referral Element Format */
4316     /* ServerType = 0; indicates the next server should be queried for the file */
4317     /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
4318     /* Node = UnicodeString of UNC path of the next share name */
4319 #ifdef DFS_SUPPORT
4320     long code = 0;
4321     int maxReferralLevel = 0;
4322     clientchar_t requestFileName[1024] = _C("");
4323     clientchar_t referralPath[1024] = _C("");
4324     smb_tran2Packet_t *outp = 0;
4325     cm_user_t *userp = 0;
4326     cm_scache_t *scp = 0;
4327     cm_scache_t *dscp = 0;
4328     cm_req_t req;
4329     CPINFO CodePageInfo;
4330     int i, nbnLen, reqLen, refLen;
4331     int idx;
4332
4333     smb_InitReq(&req);
4334
4335     maxReferralLevel = p->parmsp[0];
4336
4337     GetCPInfo(CP_ACP, &CodePageInfo);
4338     cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
4339
4340     osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
4341              maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
4342
4343     nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
4344     reqLen = (int)cm_ClientStrLen(requestFileName);
4345
4346     if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
4347         !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
4348         requestFileName[nbnLen+1] == '\\')
4349     {
4350         int found = 0;
4351
4352         if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
4353             !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
4354             found = 1;
4355             cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4356             refLen = reqLen;
4357         } else {
4358             userp = smb_GetTran2User(vcp, p);
4359             if (!userp) {
4360                 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
4361                 code = CM_ERROR_BADSMB;
4362                 goto done;
4363             }
4364
4365             /*
4366              * We have a requested path.  Check to see if it is something
4367              * we know about.
4368              *
4369              * But be careful because the name that we might be searching
4370              * for might be a known name with the final character stripped
4371              * off.
4372              */
4373             code = cm_NameI(cm_RootSCachep(userp, &req), &requestFileName[nbnLen+2],
4374                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
4375                             userp, NULL, &req, &scp);
4376             if (code == 0 ||
4377                 code == CM_ERROR_ALLDOWN ||
4378                 code == CM_ERROR_ALLBUSY ||
4379                 code == CM_ERROR_ALLOFFLINE ||
4380                 code == CM_ERROR_NOSUCHCELL ||
4381                 code == CM_ERROR_NOSUCHVOLUME ||
4382                 code == CM_ERROR_NOACCESS) {
4383                 /* Yes it is. */
4384                 found = 1;
4385                 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4386                 refLen = reqLen;
4387             } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
4388                 clientchar_t temp[1024];
4389                 clientchar_t pathName[1024];
4390                 clientchar_t *lastComponent;
4391                 /*
4392                  * we have a msdfs link somewhere in the path
4393                  * we should figure out where in the path the link is.
4394                  * and return it.
4395                  */
4396                 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
4397
4398                 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
4399
4400                 do {
4401                     if (dscp) {
4402                         cm_ReleaseSCache(dscp);
4403                         dscp = 0;
4404                     }
4405                     if (scp) {
4406                         cm_ReleaseSCache(scp);
4407                         scp = 0;
4408                     }
4409                     /* smb_StripLastComponent will strip "::$DATA" if present */
4410                     smb_StripLastComponent(pathName, &lastComponent, temp);
4411
4412                     code = cm_NameI(cm_RootSCachep(userp, &req), pathName,
4413                                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4414                                     userp, NULL, &req, &dscp);
4415                     if (code == 0) {
4416                         code = cm_NameI(dscp, ++lastComponent,
4417                                         CM_FLAG_CASEFOLD,
4418                                         userp, NULL, &req, &scp);
4419                         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
4420                             break;
4421                     }
4422                 } while (code == CM_ERROR_PATH_NOT_COVERED);
4423
4424                 /* scp should now be the DfsLink we are looking for */
4425                 if (scp) {
4426                     /* figure out how much of the input path was used */
4427                     reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
4428
4429                     cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
4430                                               referralPath, lengthof(referralPath));
4431                     refLen = (int)cm_ClientStrLen(referralPath);
4432                     found = 1;
4433                 }
4434             } else {
4435                 clientchar_t shareName[MAX_PATH + 1];
4436                 clientchar_t *p, *q;
4437                 /* we may have a sharename that is a volume reference */
4438
4439                 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
4440                 {
4441                     *q = *p;
4442                 }
4443                 *q = '\0';
4444
4445                 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
4446                     code = cm_NameI(cm_RootSCachep(userp, &req), _C(""),
4447                                     CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
4448                                     userp, p, &req, &scp);
4449                     free(p);
4450
4451                     if (code == 0) {
4452                         found = 1;
4453                         cm_ClientStrCpy(referralPath, lengthof(referralPath),
4454                                         requestFileName);
4455                         refLen = reqLen;
4456                     }
4457                 }
4458             }
4459         }
4460
4461         if (found)
4462         {
4463             USHORT * sp;
4464             struct smb_v2_referral * v2ref;
4465             outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
4466
4467             sp = (USHORT *)outp->datap;
4468             idx = 0;
4469             sp[idx++] = reqLen;   /* path consumed */
4470             sp[idx++] = 1;        /* number of referrals */
4471             sp[idx++] = 0x03;     /* flags */
4472 #ifdef DFS_VERSION_1
4473             sp[idx++] = 1;        /* Version Number */
4474             sp[idx++] = refLen + 4;  /* Referral Size */
4475             sp[idx++] = 1;        /* Type = SMB Server */
4476             sp[idx++] = 0;        /* Do not strip path consumed */
4477             for ( i=0;i<=refLen; i++ )
4478                 sp[i+idx] = referralPath[i];
4479 #else /* DFS_VERSION_2 */
4480             sp[idx++] = 2;      /* Version Number */
4481             sp[idx++] = sizeof(struct smb_v2_referral);     /* Referral Size */
4482             idx += (sizeof(struct smb_v2_referral) / 2);
4483             v2ref = (struct smb_v2_referral *) &sp[5];
4484             v2ref->ServerType = 1;  /* SMB Server */
4485             v2ref->ReferralFlags = 0x03;
4486             v2ref->Proximity = 0;   /* closest */
4487             v2ref->TimeToLive = 3600; /* seconds */
4488             v2ref->DfsPathOffset = idx * 2;
4489             v2ref->DfsAlternativePathOffset = idx * 2;
4490             v2ref->NetworkAddressOffset = 0;
4491             for ( i=0;i<=refLen; i++ )
4492                 sp[i+idx] = referralPath[i];
4493 #endif
4494         } else {
4495             code = CM_ERROR_NOSUCHPATH;
4496         }
4497     } else {
4498         code = CM_ERROR_NOSUCHPATH;
4499     }
4500
4501   done:
4502     if (dscp)
4503         cm_ReleaseSCache(dscp);
4504     if (scp)
4505         cm_ReleaseSCache(scp);
4506     if (userp)
4507         cm_ReleaseUser(userp);
4508     if (code == 0)
4509         smb_SendTran2Packet(vcp, outp, op);
4510     else
4511         smb_SendTran2Error(vcp, p, op, code);
4512     if (outp)
4513         smb_FreeTran2Packet(outp);
4514
4515     return 0;
4516 #else /* DFS_SUPPORT */
4517     osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4518     return CM_ERROR_NOSUCHDEVICE;
4519 #endif /* DFS_SUPPORT */
4520 }
4521
4522 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4523 long
4524 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4525 {
4526     /* This is a UNICODE only request (bit15 of Flags2) */
4527
4528     /* There is nothing we can do about this operation.  The client is going to
4529      * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4530      * Unfortunately, there is really nothing we can do about it other then log it
4531      * somewhere.  Even then I don't think there is anything for us to do.
4532      * So let's return an error value.
4533      */
4534
4535     osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4536     return CM_ERROR_BADOP;
4537 }
4538
4539 static long
4540 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4541                           clientchar_t * tidPathp, clientchar_t * relPathp,
4542                           int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4543 {
4544     long code = 0;
4545     cm_scache_t *scp;
4546     cm_scache_t *targetScp;                     /* target if scp is a symlink */
4547     afs_uint32 dosTime;
4548     FILETIME ft;
4549     unsigned short attr;
4550     unsigned long lattr;
4551     smb_dirListPatch_t *patchp;
4552     smb_dirListPatch_t *npatchp;
4553     afs_uint32 rights;
4554     afs_int32 mustFake = 0;
4555     clientchar_t path[AFSPATHMAX];
4556
4557     code = cm_FindACLCache(dscp, userp, &rights);
4558     if (code == -1) {
4559         lock_ObtainWrite(&dscp->rw);
4560         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4561                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4562         if (code == 0)
4563             cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4564         lock_ReleaseWrite(&dscp->rw);
4565         if (code == CM_ERROR_NOACCESS) {
4566             mustFake = 1;
4567             code = 0;
4568         }
4569     }
4570     if (code)
4571         goto cleanup;
4572
4573     if (!mustFake) {    /* Bulk Stat */
4574         afs_uint32 count;
4575         cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4576
4577         memset(bsp, 0, sizeof(cm_bulkStat_t));
4578
4579         for (patchp = *dirPatchespp, count=0;
4580              patchp;
4581              patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4582             cm_scache_t *tscp = NULL;
4583             int i;
4584
4585             /* Do not look for a cm_scache_t or bulkstat an ioctl entry */
4586             if (patchp->flags & SMB_DIRLISTPATCH_IOCTL)
4587                 continue;
4588
4589             code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4590             if (code == 0) {
4591                 if (lock_TryWrite(&tscp->rw)) {
4592                     /* we have an entry that we can look at */
4593 #ifdef AFS_FREELANCE_CLIENT
4594                     if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4595                         code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4596                                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4597                         if (code == 0)
4598                             cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4599
4600                         lock_ReleaseWrite(&tscp->rw);
4601                         cm_ReleaseSCache(tscp);
4602                         continue;
4603                     }
4604 #endif /* AFS_FREELANCE_CLIENT */
4605                     if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4606                         /* we have a callback on it.  Don't bother
4607                         * fetching this stat entry, since we're happy
4608                         * with the info we have.
4609                         */
4610                         lock_ReleaseWrite(&tscp->rw);
4611                         cm_ReleaseSCache(tscp);
4612                         continue;
4613                     }
4614                     lock_ReleaseWrite(&tscp->rw);
4615                 } /* got lock */
4616                 cm_ReleaseSCache(tscp);
4617             }   /* found entry */
4618
4619             i = bsp->counter++;
4620             bsp->fids[i].Volume = patchp->fid.volume;
4621             bsp->fids[i].Vnode = patchp->fid.vnode;
4622             bsp->fids[i].Unique = patchp->fid.unique;
4623
4624             if (bsp->counter == AFSCBMAX) {
4625                 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4626                 memset(bsp, 0, sizeof(cm_bulkStat_t));
4627             }
4628         }
4629
4630         if (bsp->counter > 0)
4631             code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4632
4633         free(bsp);
4634     }
4635
4636     for( patchp = *dirPatchespp;
4637          patchp;
4638          patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4639         cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4640                             relPathp ? relPathp : _C(""), patchp->dep->name);
4641         reqp->relPathp = path;
4642         reqp->tidPathp = tidPathp;
4643
4644         if (patchp->flags & SMB_DIRLISTPATCH_IOCTL) {
4645             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4646                errors in the client. */
4647             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4648                 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4649
4650                 /* 1969-12-31 23:59:59 +00 */
4651                 ft.dwHighDateTime = 0x19DB200;
4652                 ft.dwLowDateTime = 0x5BB78980;
4653
4654                 /* copy to Creation Time */
4655                 fa->creationTime = ft;
4656                 fa->lastAccessTime = ft;
4657                 fa->lastWriteTime = ft;
4658                 fa->lastChangeTime = ft;
4659                 fa->extFileAttributes = SMB_ATTR_SYSTEM | SMB_ATTR_HIDDEN;
4660             } else {
4661                 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4662
4663                 /* 1969-12-31 23:59:58 +00*/
4664                 dosTime = 0xEBBFBF7D;
4665
4666                 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4667                 fa->lastAccessDateTime = fa->creationDateTime;
4668                 fa->lastWriteDateTime = fa->creationDateTime;
4669                 fa->attributes = SMB_ATTR_SYSTEM|SMB_ATTR_HIDDEN;
4670             }
4671             continue;
4672         }
4673
4674         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4675         reqp->relPathp = reqp->tidPathp = NULL;
4676         if (code)
4677             continue;
4678
4679         lock_ObtainWrite(&scp->rw);
4680         if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4681             lock_ReleaseWrite(&scp->rw);
4682
4683             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4684                errors in the client. */
4685             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4686                 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4687
4688                 /* 1969-12-31 23:59:59 +00 */
4689                 ft.dwHighDateTime = 0x19DB200;
4690                 ft.dwLowDateTime = 0x5BB78980;
4691
4692                 /* copy to Creation Time */
4693                 fa->creationTime = ft;
4694                 fa->lastAccessTime = ft;
4695                 fa->lastWriteTime = ft;
4696                 fa->lastChangeTime = ft;
4697
4698                 switch (scp->fileType) {
4699                 case CM_SCACHETYPE_DIRECTORY:
4700                 case CM_SCACHETYPE_MOUNTPOINT:
4701                 case CM_SCACHETYPE_INVALID:
4702                     fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4703                     break;
4704                 case CM_SCACHETYPE_SYMLINK:
4705                     if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4706                         fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4707                     else
4708                         fa->extFileAttributes = SMB_ATTR_NORMAL;
4709                     break;
4710                 default:
4711                     /* if we get here we either have a normal file
4712                      * or we have a file for which we have never
4713                      * received status info.  In this case, we can
4714                      * check the even/odd value of the entry's vnode.
4715                      * odd means it is to be treated as a directory
4716                      * and even means it is to be treated as a file.
4717                      */
4718                     if (mustFake && (scp->fid.vnode & 0x1))
4719                         fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4720                     else
4721                         fa->extFileAttributes = SMB_ATTR_NORMAL;
4722                 }
4723                 /* merge in hidden attribute */
4724                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4725                     fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4726                 }
4727             } else {
4728                 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4729
4730                 /* 1969-12-31 23:59:58 +00*/
4731                 dosTime = 0xEBBFBF7D;
4732
4733                 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4734                 fa->lastAccessDateTime = fa->creationDateTime;
4735                 fa->lastWriteDateTime = fa->creationDateTime;
4736
4737                 /* set the attribute */
4738                 switch (scp->fileType) {
4739                 case CM_SCACHETYPE_DIRECTORY:
4740                 case CM_SCACHETYPE_MOUNTPOINT:
4741                 case CM_SCACHETYPE_INVALID:
4742                     fa->attributes = SMB_ATTR_DIRECTORY;
4743                     break;
4744                 case CM_SCACHETYPE_SYMLINK:
4745                     if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4746                         fa->attributes = SMB_ATTR_DIRECTORY;
4747                     else
4748                         fa->attributes = SMB_ATTR_NORMAL;
4749                     break;
4750                 default:
4751                     /* if we get here we either have a normal file
4752                      * or we have a file for which we have never
4753                      * received status info.  In this case, we can
4754                      * check the even/odd value of the entry's vnode.
4755                      * even means it is to be treated as a directory
4756                      * and odd means it is to be treated as a file.
4757                      */
4758                     if (mustFake && (scp->fid.vnode & 0x1))
4759                         fa->attributes = SMB_ATTR_DIRECTORY;
4760                     else
4761                         fa->attributes = SMB_ATTR_NORMAL;
4762                 }
4763
4764                 /* merge in hidden (dot file) attribute */
4765                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4766                     fa->attributes |= SMB_ATTR_HIDDEN;
4767                 }
4768             }
4769
4770             cm_ReleaseSCache(scp);
4771             continue;
4772         }
4773
4774         /* now watch for a symlink */
4775         code = 0;
4776         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4777             lock_ReleaseWrite(&scp->rw);
4778             cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4779                                 relPathp ? relPathp : _C(""), patchp->dep->name);
4780             reqp->relPathp = path;
4781             reqp->tidPathp = tidPathp;
4782             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4783             reqp->relPathp = reqp->tidPathp = NULL;
4784             if (code == 0) {
4785                 /* we have a more accurate file to use (the
4786                  * target of the symbolic link).  Otherwise,
4787                  * we'll just use the symlink anyway.
4788                  */
4789                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4790                           scp, targetScp);
4791                 cm_ReleaseSCache(scp);
4792                 scp = targetScp;
4793             }
4794             lock_ObtainWrite(&scp->rw);
4795         }
4796
4797         lock_ConvertWToR(&scp->rw);
4798
4799         if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4800             smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4801
4802             /* get filetime */
4803             cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4804
4805             fa->creationTime = ft;
4806             fa->lastAccessTime = ft;
4807             fa->lastWriteTime = ft;
4808             fa->lastChangeTime = ft;
4809
4810             /* Use length for both file length and alloc length */
4811             fa->endOfFile = scp->length;
4812             fa->allocationSize = scp->length;
4813
4814             /* Copy attributes */
4815             lattr = smb_ExtAttributes(scp);
4816             if ((code == CM_ERROR_NOSUCHPATH &&
4817                 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4818                 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4819                 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4820                 if (lattr == SMB_ATTR_NORMAL)
4821                     lattr = SMB_ATTR_DIRECTORY;
4822                 else
4823                     lattr |= SMB_ATTR_DIRECTORY;
4824             }
4825             /* merge in hidden (dot file) attribute */
4826             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4827                 if (lattr == SMB_ATTR_NORMAL)
4828                     lattr = SMB_ATTR_HIDDEN;
4829                 else
4830                     lattr |= SMB_ATTR_HIDDEN;
4831             }
4832
4833             fa->extFileAttributes = lattr;
4834         } else {
4835             smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4836
4837             /* get dos time */
4838             cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4839
4840             fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4841             fa->lastAccessDateTime = fa->creationDateTime;
4842             fa->lastWriteDateTime = fa->creationDateTime;
4843
4844             /* copy out file length and alloc length,
4845              * using the same for both
4846              */
4847             fa->dataSize = scp->length.LowPart;
4848             fa->allocationSize = scp->length.LowPart;
4849
4850             /* finally copy out attributes as short */
4851             attr = smb_Attributes(scp);
4852             /* merge in hidden (dot file) attribute */
4853             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4854                 if (lattr == SMB_ATTR_NORMAL)
4855                     lattr = SMB_ATTR_HIDDEN;
4856                 else
4857                     lattr |= SMB_ATTR_HIDDEN;
4858             }
4859             fa->attributes = attr;
4860         }
4861
4862         lock_ReleaseRead(&scp->rw);
4863         cm_ReleaseSCache(scp);
4864     }
4865
4866     /* now free the patches */
4867     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4868         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4869         free(patchp);
4870     }
4871
4872     /* and mark the list as empty */
4873     *dirPatchespp = NULL;
4874
4875   cleanup:
4876     return code;
4877 }
4878
4879 /* smb_ReceiveTran2SearchDir implements both
4880  * Tran2_Find_First and Tran2_Find_Next
4881  */
4882 #define TRAN2_FIND_FLAG_CLOSE_SEARCH            0x01
4883 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END     0x02
4884 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS      0x04
4885 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH         0x08
4886 #define TRAN2_FIND_FLAG_BACKUP_INTENT           0x10
4887
4888 /* this is an optimized handler for T2SearchDir that handles the case
4889    where there are no wildcards in the search path.  I.e. an
4890    application is using FindFirst(Ex) to get information about a
4891    single file or directory.  It will attempt to do a single lookup.
4892    If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4893    the usual mechanism.
4894
4895    This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4896
4897    TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4898    */
4899 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4900 {
4901     int attribute;
4902     long nextCookie;
4903     long code = 0, code2 = 0;
4904     clientchar_t *pathp = 0;
4905     int maxCount;
4906     smb_dirListPatch_t *dirListPatchesp;
4907     smb_dirListPatch_t *curPatchp;
4908     size_t orbytes;                     /* # of bytes in this output record */
4909     size_t ohbytes;                     /* # of bytes, except file name */
4910     size_t onbytes;                     /* # of bytes in name, incl. term. null */
4911     cm_scache_t *scp = NULL;
4912     cm_scache_t *targetScp = NULL;
4913     cm_user_t *userp = NULL;
4914     char *op;                           /* output data ptr */
4915     char *origOp;                       /* original value of op */
4916     cm_space_t *spacep;                 /* for pathname buffer */
4917     unsigned long maxReturnData;        /* max # of return data */
4918     long maxReturnParms;                /* max # of return parms */
4919     long bytesInBuffer;                 /* # data bytes in the output buffer */
4920     clientchar_t *maskp;                        /* mask part of path */
4921     int infoLevel;
4922     int searchFlags;
4923     int eos;
4924     smb_tran2Packet_t *outp;            /* response packet */
4925     clientchar_t *tidPathp = 0;
4926     int align;
4927     clientchar_t shortName[13];         /* 8.3 name if needed */
4928     int NeedShortName;
4929     clientchar_t *shortNameEnd;
4930     cm_dirEntry_t * dep = NULL;
4931     cm_req_t req;
4932     char * s;
4933     void * attrp = NULL;
4934     smb_tran2Find_t * fp;
4935     int afs_ioctl = 0;                  /* is this query for _._AFS_IOCTL_._? */
4936     cm_dirFid_t dfid;
4937
4938     smb_InitReq(&req);
4939
4940     eos = 0;
4941     osi_assertx(p->opcode == 1, "invalid opcode");
4942
4943     /* find first; obtain basic parameters from request */
4944
4945     /* note that since we are going to failover to regular
4946      * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4947      * modify any of the input parameters here. */
4948     attribute = p->parmsp[0];
4949     maxCount = p->parmsp[1];
4950     infoLevel = p->parmsp[3];
4951     searchFlags = p->parmsp[2];
4952     pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4953     nextCookie = 0;
4954     maskp = cm_ClientStrRChr(pathp,  '\\');
4955     if (maskp == NULL)
4956         maskp = pathp;
4957     else
4958         maskp++;        /* skip over backslash */
4959     /* track if this is likely to match a lot of entries */
4960
4961     osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4962              osi_LogSaveClientString(smb_logp, pathp),
4963              osi_LogSaveClientString(smb_logp, maskp));
4964
4965     switch ( infoLevel ) {
4966     case SMB_INFO_STANDARD:
4967         s = "InfoStandard";
4968         ohbytes = sizeof(fp->u.FstandardInfo);
4969         break;
4970
4971     case SMB_INFO_QUERY_EA_SIZE:
4972         ohbytes = sizeof(fp->u.FeaSizeInfo);
4973         s = "InfoQueryEaSize";
4974         break;
4975
4976     case SMB_INFO_QUERY_EAS_FROM_LIST:
4977         ohbytes = sizeof(fp->u.FeasFromListInfo);
4978         s = "InfoQueryEasFromList";
4979         break;
4980
4981     case SMB_FIND_FILE_DIRECTORY_INFO:
4982         s = "FindFileDirectoryInfo";
4983         ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4984         break;
4985
4986     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4987         s = "FindFileFullDirectoryInfo";
4988         ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4989         break;
4990
4991     case SMB_FIND_FILE_NAMES_INFO:
4992         s = "FindFileNamesInfo";
4993         ohbytes = sizeof(fp->u.FfileNamesInfo);
4994         break;
4995
4996     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4997         s = "FindFileBothDirectoryInfo";
4998         ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4999         break;
5000
5001     default:
5002         s = "unknownInfoLevel";
5003         ohbytes = 0;
5004     }
5005
5006     osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
5007
5008     osi_Log4(smb_logp,
5009              "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5010              attribute, infoLevel, maxCount, searchFlags);
5011
5012     if (ohbytes == 0) {
5013         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5014         return CM_ERROR_INVAL;
5015     }
5016
5017     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5018         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;     /* no resume keys */
5019
5020     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5021         ohbytes += 4;
5022
5023     dirListPatchesp = NULL;
5024
5025     maxReturnData = p->maxReturnData;
5026     maxReturnParms = 10;        /* return params for findfirst, which
5027                                    is the only one we handle.*/
5028
5029     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5030                                       maxReturnData);
5031
5032     osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
5033              maxCount, osi_LogSaveClientString(smb_logp, pathp));
5034
5035     /* bail out if request looks bad */
5036     if (!pathp) {
5037         smb_FreeTran2Packet(outp);
5038         return CM_ERROR_BADSMB;
5039     }
5040
5041     userp = smb_GetTran2User(vcp, p);
5042     if (!userp) {
5043         osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
5044         smb_FreeTran2Packet(outp);
5045         return CM_ERROR_BADSMB;
5046     }
5047
5048     /* try to get the vnode for the path name next */
5049     spacep = cm_GetSpace();
5050     /* smb_StripLastComponent will strip "::$DATA" if present */
5051     smb_StripLastComponent(spacep->wdata, NULL, pathp);
5052     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5053     if (code) {
5054         cm_ReleaseUser(userp);
5055         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5056         smb_FreeTran2Packet(outp);
5057         return 0;
5058     }
5059
5060     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
5061                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5062                     userp, tidPathp, &req, &scp);
5063     cm_FreeSpace(spacep);
5064
5065     if (code) {
5066         cm_ReleaseUser(userp);
5067         smb_SendTran2Error(vcp, p, opx, code);
5068         smb_FreeTran2Packet(outp);
5069         return 0;
5070     }
5071
5072 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5073     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5074         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5075         cm_ReleaseSCache(scp);
5076         cm_ReleaseUser(userp);
5077         if ( WANTS_DFS_PATHNAMES(p) || pnc )
5078             code = CM_ERROR_PATH_NOT_COVERED;
5079         else
5080             code = CM_ERROR_NOSUCHPATH;
5081         smb_SendTran2Error(vcp, p, opx, code);
5082         smb_FreeTran2Packet(outp);
5083         return 0;
5084     }
5085 #endif /* DFS_SUPPORT */
5086     osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
5087
5088     afs_ioctl = (cm_ClientStrCmpI(maskp, CM_IOCTL_FILENAME_NOSLASH_W) == 0);
5089
5090     /*
5091      * If we are not searching for _._AFS_IOCTL_._, then we need to obtain
5092      * the target scp.
5093      */
5094     if (!afs_ioctl) {
5095         /* now do a single case sensitive lookup for the file in question */
5096         code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetScp);
5097
5098         /*
5099          * if a case sensitive match failed, we try a case insensitive
5100          * one next.
5101          */
5102         if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)
5103             code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetScp);
5104
5105         if (code == 0 && targetScp->fid.vnode == 0) {
5106             cm_ReleaseSCache(targetScp);
5107             code = CM_ERROR_NOSUCHFILE;
5108         }
5109
5110         if (code) {
5111             /*
5112              * if we can't find the directory entry, this block will
5113              * return CM_ERROR_NOSUCHFILE, which we will pass on to
5114              * smb_ReceiveTran2SearchDir().
5115              */
5116             cm_ReleaseSCache(scp);
5117             cm_ReleaseUser(userp);
5118             if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5119                 smb_SendTran2Error(vcp, p, opx, code);
5120                 code = 0;
5121             }
5122             smb_FreeTran2Packet(outp);
5123             return code;
5124         }
5125     }
5126
5127     /* now that we have the target in sight, we proceed with filling
5128        up the return data. */
5129
5130     op = origOp = outp->datap;
5131     bytesInBuffer = 0;
5132
5133     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5134         /* skip over resume key */
5135         op += 4;
5136     }
5137
5138     fp = (smb_tran2Find_t *) op;
5139
5140     if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
5141         && !cm_Is8Dot3(maskp)) {
5142
5143         /*
5144          * Since the _._AFS_IOCTL_._ file does not actually exist
5145          * we will make up a per directory FID equivalent to the
5146          * directory vnode and the uniqifier 0.
5147          */
5148         if (afs_ioctl) {
5149             dfid.vnode = htonl(scp->fid.vnode);
5150             dfid.unique = htonl(0);
5151         } else {
5152             dfid.vnode = htonl(targetScp->fid.vnode);
5153             dfid.unique = htonl(targetScp->fid.unique);
5154         }
5155
5156         cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
5157         NeedShortName = 1;
5158     } else {
5159         NeedShortName = 0;
5160     }
5161
5162     osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
5163              ntohl(dfid.vnode),
5164              ntohl(dfid.unique),
5165              osi_LogSaveClientString(smb_logp, pathp),
5166              (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5167
5168     /* Eliminate entries that don't match requested attributes */
5169     if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
5170         smb_IsDotFile(maskp)) {
5171
5172         code = CM_ERROR_NOSUCHFILE;
5173         osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
5174         goto skip_file;
5175
5176     }
5177
5178     if (!(attribute & SMB_ATTR_DIRECTORY) &&
5179         !afs_ioctl &&
5180         (targetScp->fileType == CM_SCACHETYPE_DIRECTORY ||
5181          targetScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
5182          targetScp->fileType == CM_SCACHETYPE_DFSLINK ||
5183          targetScp->fileType == CM_SCACHETYPE_INVALID)) {
5184
5185         code = CM_ERROR_NOSUCHFILE;
5186         osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
5187         goto skip_file;
5188
5189     }
5190
5191     /* add header to name & term. null */
5192     onbytes = 0;
5193     smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5194     orbytes = ohbytes + onbytes;
5195
5196     /* now, we round up the record to a 4 byte alignment, and we make
5197      * sure that we have enough room here for even the aligned version
5198      * (so we don't have to worry about an * overflow when we pad
5199      * things out below).  That's the reason for the alignment
5200      * arithmetic below.
5201      */
5202     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5203         align = (4 - (orbytes & 3)) & 3;
5204     else
5205         align = 0;
5206
5207     if (orbytes + align > maxReturnData) {
5208
5209         /* even though this request is unlikely to succeed with a
5210            failover, we do it anyway. */
5211         code = CM_ERROR_NOSUCHFILE;
5212         osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5213                  maxReturnData);
5214         goto skip_file;
5215     }
5216
5217     /* this is one of the entries to use: it is not deleted and it
5218      * matches the star pattern we're looking for.  Put out the name,
5219      * preceded by its length.
5220      */
5221     /* First zero everything else */
5222     memset(origOp, 0, orbytes);
5223
5224     onbytes = 0;
5225     smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5226
5227     switch (infoLevel) {
5228     case SMB_INFO_STANDARD:
5229         fp->u.FstandardInfo.fileNameLength = onbytes;
5230         attrp = &fp->u.FstandardInfo.fileAttrs;
5231         break;
5232
5233     case SMB_INFO_QUERY_EA_SIZE:
5234         fp->u.FeaSizeInfo.fileNameLength = onbytes;
5235         attrp = &fp->u.FeaSizeInfo.fileAttrs;
5236         fp->u.FeaSizeInfo.eaSize = 0;
5237         break;
5238
5239     case SMB_INFO_QUERY_EAS_FROM_LIST:
5240         fp->u.FeasFromListInfo.fileNameLength = onbytes;
5241         attrp = &fp->u.FeasFromListInfo.fileAttrs;
5242         fp->u.FeasFromListInfo.eaSize = 0;
5243         break;
5244
5245     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5246         if (NeedShortName) {
5247 #ifdef SMB_UNICODE
5248             int nchars;
5249
5250             nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5251                                             fp->u.FfileBothDirectoryInfo.shortName,
5252                                             sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5253             if (nchars > 0)
5254                 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5255             else
5256                 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5257             fp->u.FfileBothDirectoryInfo.reserved = 0;
5258 #else
5259             strcpy(fp->u.FfileBothDirectoryInfo.shortName,
5260                    shortName);
5261             fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5262 #endif
5263     }
5264         /* Fallthrough */
5265
5266     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5267         fp->u.FfileFullDirectoryInfo.eaSize = 0;
5268         /* Fallthrough */
5269
5270     case SMB_FIND_FILE_DIRECTORY_INFO:
5271         fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
5272         fp->u.FfileDirectoryInfo.fileIndex = 0;
5273         attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5274         fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5275         break;
5276
5277     case SMB_FIND_FILE_NAMES_INFO:
5278         fp->u.FfileNamesInfo.nextEntryOffset = 0;
5279         fp->u.FfileNamesInfo.fileIndex = 0;
5280         fp->u.FfileNamesInfo.fileNameLength = onbytes;
5281         break;
5282
5283     default:
5284         /* we shouldn't hit this case */
5285         osi_assertx(FALSE, "Unknown query type");
5286     }
5287
5288     if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5289         osi_assert(attrp != NULL);
5290
5291         curPatchp = malloc(sizeof(*curPatchp));
5292         osi_QAdd((osi_queue_t **) &dirListPatchesp,
5293                  &curPatchp->q);
5294         curPatchp->dptr = attrp;
5295
5296         if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
5297             curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5298         } else {
5299             curPatchp->flags = 0;
5300         }
5301
5302         /* temp */
5303         {
5304             int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
5305             dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
5306             cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
5307         }
5308
5309         if (afs_ioctl) {
5310             cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, scp->fid.vnode, 0);
5311             dep->fid.vnode = scp->fid.vnode;
5312             dep->fid.unique = 0;
5313             curPatchp->flags |= SMB_DIRLISTPATCH_IOCTL;
5314         } else {
5315             cm_SetFid(&curPatchp->fid, targetScp->fid.cell, targetScp->fid.volume, targetScp->fid.vnode, targetScp->fid.unique);
5316             dep->fid.vnode = targetScp->fid.vnode;
5317             dep->fid.unique = targetScp->fid.unique;
5318         }
5319
5320         curPatchp->dep = dep;
5321     }
5322
5323     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5324         /* put out resume key */
5325         *((u_long *)origOp) = 0;
5326     }
5327
5328     /* Adjust byte ptr and count */
5329     origOp += orbytes;  /* skip entire record */
5330     bytesInBuffer += orbytes;
5331
5332     /* and pad the record out */
5333     while (--align >= 0) {
5334         *origOp++ = 0;
5335         bytesInBuffer++;
5336     }
5337
5338     /* apply the patches */
5339     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
5340
5341     outp->parmsp[0] = 0;
5342     outp->parmsp[1] = 1;        /* number of names returned */
5343     outp->parmsp[2] = 1;        /* end of search */
5344     outp->parmsp[3] = 0;        /* nothing wrong with EAS */
5345     outp->parmsp[4] = 0;
5346
5347     outp->totalParms = 10;      /* in bytes */
5348
5349     outp->totalData = bytesInBuffer;
5350
5351     osi_Log0(smb_logp, "T2SDSingle done.");
5352
5353     if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5354         if (code)
5355             smb_SendTran2Error(vcp, p, opx, code);
5356         else
5357             smb_SendTran2Packet(vcp, outp, opx);
5358         code = 0;
5359     }
5360
5361  skip_file:
5362     smb_FreeTran2Packet(outp);
5363     if (dep)
5364         free(dep);
5365     if (scp)
5366         cm_ReleaseSCache(scp);
5367     if (targetScp)
5368         cm_ReleaseSCache(targetScp);
5369     cm_ReleaseUser(userp);
5370
5371     return code;
5372 }
5373
5374
5375 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
5376 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
5377 {
5378     int attribute;
5379     long nextCookie;
5380     char *tp;
5381     long code = 0, code2 = 0;
5382     clientchar_t *pathp;
5383     cm_dirEntry_t *dep = 0;
5384     int maxCount;
5385     smb_dirListPatch_t *dirListPatchesp = 0;
5386     smb_dirListPatch_t *curPatchp = 0;
5387     cm_buf_t *bufferp;
5388     long temp;
5389     size_t orbytes;                     /* # of bytes in this output record */
5390     size_t ohbytes;                     /* # of bytes, except file name */
5391     size_t onbytes;                     /* # of bytes in name, incl. term. null */
5392     osi_hyper_t dirLength;
5393     osi_hyper_t bufferOffset;
5394     osi_hyper_t curOffset;
5395     osi_hyper_t thyper;
5396     smb_dirSearch_t *dsp;
5397     cm_scache_t *scp;
5398     long entryInDir;
5399     long entryInBuffer;
5400     cm_pageHeader_t *pageHeaderp;
5401     cm_user_t *userp = NULL;
5402     int slotInPage;
5403     int returnedNames;
5404     long nextEntryCookie;
5405     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
5406     char *op;                   /* output data ptr */
5407     char *origOp;                       /* original value of op */
5408     cm_space_t *spacep;         /* for pathname buffer */
5409     unsigned long maxReturnData;                /* max # of return data */
5410     unsigned long maxReturnParms;               /* max # of return parms */
5411     long bytesInBuffer;         /* # data bytes in the output buffer */
5412     int starPattern;
5413     clientchar_t *maskp;                        /* mask part of path */
5414     int infoLevel;
5415     int searchFlags;
5416     int eos;
5417     smb_tran2Packet_t *outp;    /* response packet */
5418     clientchar_t *tidPathp;
5419     unsigned int align;
5420     clientchar_t shortName[13];         /* 8.3 name if needed */
5421     int NeedShortName;
5422     int foundInexact;
5423     clientchar_t *shortNameEnd;
5424     int fileType;
5425     cm_fid_t fid;
5426     cm_req_t req;
5427     void * attrp;
5428     char * s;
5429     smb_tran2Find_t * fp;
5430
5431     smb_InitReq(&req);
5432
5433     eos = 0;
5434     if (p->opcode == 1) {
5435         /* find first; obtain basic parameters from request */
5436         attribute = p->parmsp[0];
5437         maxCount = p->parmsp[1];
5438         infoLevel = p->parmsp[3];
5439         searchFlags = p->parmsp[2];
5440         pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
5441         nextCookie = 0;
5442         maskp = cm_ClientStrRChr(pathp,  '\\');
5443         if (maskp == NULL)
5444             maskp = pathp;
5445         else
5446             maskp++;    /* skip over backslash */
5447
5448         /* track if this is likely to match a lot of entries */
5449         starPattern = smb_V3IsStarMask(maskp);
5450
5451 #ifndef NOFINDFIRSTOPTIMIZE
5452         if (!starPattern) {
5453             /* if this is for a single directory or file, we let the
5454                optimized routine handle it.  The only error it
5455                returns is CM_ERROR_NOSUCHFILE.  The  */
5456             code = smb_T2SearchDirSingle(vcp, p, opx);
5457
5458             /* we only failover if we see a CM_ERROR_NOSUCHFILE */
5459             if (code != CM_ERROR_NOSUCHFILE) {
5460 #ifdef USE_BPLUS
5461                 /* unless we are using the BPlusTree */
5462                 if (code == CM_ERROR_BPLUS_NOMATCH)
5463                     code = CM_ERROR_NOSUCHFILE;
5464 #endif /* USE_BPLUS */
5465                 return code;
5466             }
5467         }
5468 #endif  /* NOFINDFIRSTOPTIMIZE */
5469         dir_enums++;
5470
5471         dsp = smb_NewDirSearch(1);
5472         dsp->attribute = attribute;
5473         cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask),  maskp);        /* and save mask */
5474     }
5475     else {
5476         osi_assertx(p->opcode == 2, "invalid opcode");
5477         /* find next; obtain basic parameters from request or open dir file */
5478         dsp = smb_FindDirSearch(p->parmsp[0]);
5479         maxCount = p->parmsp[1];
5480         infoLevel = p->parmsp[2];
5481         nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
5482         searchFlags = p->parmsp[5];
5483         if (!dsp) {
5484             osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
5485                      p->parmsp[0], nextCookie);
5486             return CM_ERROR_BADFD;
5487         }
5488         attribute = dsp->attribute;
5489         pathp = NULL;
5490         maskp = dsp->mask;
5491         starPattern = 1;        /* assume, since required a Find Next */
5492     }
5493
5494     switch ( infoLevel ) {
5495     case SMB_INFO_STANDARD:
5496         s = "InfoStandard";
5497         ohbytes = sizeof(fp->u.FstandardInfo);
5498         break;
5499
5500     case SMB_INFO_QUERY_EA_SIZE:
5501         ohbytes = sizeof(fp->u.FeaSizeInfo);
5502         s = "InfoQueryEaSize";
5503         break;
5504
5505     case SMB_INFO_QUERY_EAS_FROM_LIST:
5506         ohbytes = sizeof(fp->u.FeasFromListInfo);
5507         s = "InfoQueryEasFromList";
5508         break;
5509
5510     case SMB_FIND_FILE_DIRECTORY_INFO:
5511         s = "FindFileDirectoryInfo";
5512         ohbytes = sizeof(fp->u.FfileDirectoryInfo);
5513         break;
5514
5515     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5516         s = "FindFileFullDirectoryInfo";
5517         ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
5518         break;
5519
5520     case SMB_FIND_FILE_NAMES_INFO:
5521         s = "FindFileNamesInfo";
5522         ohbytes = sizeof(fp->u.FfileNamesInfo);
5523         break;
5524
5525     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5526         s = "FindFileBothDirectoryInfo";
5527         ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5528         break;
5529
5530     default:
5531         s = "unknownInfoLevel";
5532         ohbytes = 0;
5533     }
5534
5535     osi_Log1(smb_logp, "T2 search dir info level: %s", s);
5536
5537     osi_Log4(smb_logp,
5538               "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5539               attribute, infoLevel, maxCount, searchFlags);
5540
5541     osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
5542               p->opcode, dsp->cookie, nextCookie);
5543
5544     if (ohbytes == 0) {
5545         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5546         smb_ReleaseDirSearch(dsp);
5547         return CM_ERROR_INVAL;
5548     }
5549
5550     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5551         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;     /* no resume keys */
5552
5553     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5554         ohbytes += 4;
5555
5556     dirListPatchesp = NULL;
5557
5558     maxReturnData = p->maxReturnData;
5559     if (p->opcode == 1) /* find first */
5560         maxReturnParms = 10;    /* bytes */
5561     else
5562         maxReturnParms = 8;     /* bytes */
5563
5564     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5565                                       maxReturnData);
5566
5567     if (maxCount > 500)
5568         maxCount = 500;
5569
5570     osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5571              maxCount, osi_LogSaveClientString(smb_logp, pathp));
5572
5573     /* bail out if request looks bad */
5574     if (p->opcode == 1 && !pathp) {
5575         smb_ReleaseDirSearch(dsp);
5576         smb_FreeTran2Packet(outp);
5577         return CM_ERROR_BADSMB;
5578     }
5579
5580     osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5581              dsp->cookie, nextCookie, attribute);
5582
5583     userp = smb_GetTran2User(vcp, p);
5584     if (!userp) {
5585         osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5586         smb_ReleaseDirSearch(dsp);
5587         smb_FreeTran2Packet(outp);
5588         return CM_ERROR_BADSMB;
5589     }
5590
5591     /* try to get the vnode for the path name next */
5592     lock_ObtainMutex(&dsp->mx);
5593     if (dsp->scp) {
5594         scp = dsp->scp;
5595         osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5596         cm_HoldSCache(scp);
5597         code = 0;
5598     } else {
5599         spacep = cm_GetSpace();
5600         /* smb_StripLastComponent will strip "::$DATA" if present */
5601         smb_StripLastComponent(spacep->wdata, NULL, pathp);
5602         code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5603         if (code) {
5604             cm_ReleaseUser(userp);
5605             smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5606             smb_FreeTran2Packet(outp);
5607             lock_ReleaseMutex(&dsp->mx);
5608             smb_DeleteDirSearch(dsp);
5609             smb_ReleaseDirSearch(dsp);
5610             return 0;
5611         }
5612
5613         cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5614         cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5615
5616         code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
5617                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5618                         userp, tidPathp, &req, &scp);
5619         cm_FreeSpace(spacep);
5620
5621         if (code == 0) {
5622 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5623             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5624                 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5625                 cm_ReleaseSCache(scp);
5626                 cm_ReleaseUser(userp);
5627                 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5628                     code = CM_ERROR_PATH_NOT_COVERED;
5629                 else
5630                     code = CM_ERROR_NOSUCHPATH;
5631                 smb_SendTran2Error(vcp, p, opx, code);
5632                 smb_FreeTran2Packet(outp);
5633                 lock_ReleaseMutex(&dsp->mx);
5634                 smb_DeleteDirSearch(dsp);
5635                 smb_ReleaseDirSearch(dsp);
5636                 return 0;
5637             }
5638 #endif /* DFS_SUPPORT */
5639             dsp->scp = scp;
5640             osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5641             /* we need one hold for the entry we just stored into,
5642              * and one for our own processing.  When we're done
5643              * with this function, we'll drop the one for our own
5644              * processing.  We held it once from the namei call,
5645              * and so we do another hold now.
5646              */
5647             cm_HoldSCache(scp);
5648             dsp->flags |= SMB_DIRSEARCH_BULKST;
5649         }
5650     }
5651     lock_ReleaseMutex(&dsp->mx);
5652     if (code) {
5653         cm_ReleaseUser(userp);
5654         smb_FreeTran2Packet(outp);
5655         smb_DeleteDirSearch(dsp);
5656         smb_ReleaseDirSearch(dsp);
5657         return code;
5658     }
5659
5660     /* get the directory size */
5661     lock_ObtainWrite(&scp->rw);
5662     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5663                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5664     if (code) {
5665         lock_ReleaseWrite(&scp->rw);
5666         cm_ReleaseSCache(scp);
5667         cm_ReleaseUser(userp);
5668         smb_FreeTran2Packet(outp);
5669         smb_DeleteDirSearch(dsp);
5670         smb_ReleaseDirSearch(dsp);
5671         return code;
5672     }
5673
5674     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5675
5676   startsearch:
5677     dirLength = scp->length;
5678     bufferp = NULL;
5679     bufferOffset.LowPart = bufferOffset.HighPart = 0;
5680     curOffset.HighPart = 0;
5681     curOffset.LowPart = nextCookie;
5682     origOp = outp->datap;
5683
5684     foundInexact = 0;
5685     code = 0;
5686     returnedNames = 0;
5687     bytesInBuffer = 0;
5688     while (1) {
5689         normchar_t normName[MAX_PATH]; /* Normalized name */
5690         clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5691
5692         op = origOp;
5693         if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5694             /* skip over resume key */
5695             op += 4;
5696
5697         fp = (smb_tran2Find_t *) op;
5698
5699         /* make sure that curOffset.LowPart doesn't point to the first
5700          * 32 bytes in the 2nd through last dir page, and that it doesn't
5701          * point at the first 13 32-byte chunks in the first dir page,
5702          * since those are dir and page headers, and don't contain useful
5703          * information.
5704          */
5705         temp = curOffset.LowPart & (2048-1);
5706         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5707             /* we're in the first page */
5708             if (temp < 13*32) temp = 13*32;
5709         }
5710         else {
5711             /* we're in a later dir page */
5712             if (temp < 32) temp = 32;
5713         }
5714
5715         /* make sure the low order 5 bits are zero */
5716         temp &= ~(32-1);
5717
5718         /* now put temp bits back ito curOffset.LowPart */
5719         curOffset.LowPart &= ~(2048-1);
5720         curOffset.LowPart |= temp;
5721
5722         /* check if we've passed the dir's EOF */
5723         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5724             osi_Log0(smb_logp, "T2 search dir passed eof");
5725             eos = 1;
5726             break;
5727         }
5728
5729         /* check if we've returned all the names that will fit in the
5730          * response packet; we check return count as well as the number
5731          * of bytes requested.  We check the # of bytes after we find
5732          * the dir entry, since we'll need to check its size.
5733          */
5734         if (returnedNames >= maxCount) {
5735             osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5736                       returnedNames, maxCount);
5737             break;
5738         }
5739
5740         /* when we have obtained as many entries as can be processed in
5741          * a single Bulk Status call to the file server, apply the dir listing
5742          * patches.
5743          */
5744         if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5745             lock_ReleaseWrite(&scp->rw);
5746             code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5747                                                dsp->relPath, infoLevel, userp, &req);
5748             lock_ObtainWrite(&scp->rw);
5749         }
5750         /* Then check to see if we have time left to process more entries */
5751         if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5752             osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5753             break;
5754         }
5755
5756         /* see if we can use the bufferp we have now; compute in which
5757          * page the current offset would be, and check whether that's
5758          * the offset of the buffer we have.  If not, get the buffer.
5759          */
5760         thyper.HighPart = curOffset.HighPart;
5761         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5762         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5763             /* wrong buffer */
5764             if (bufferp) {
5765                 buf_Release(bufferp);
5766                 bufferp = NULL;
5767             }
5768             lock_ReleaseWrite(&scp->rw);
5769             code = buf_Get(scp, &thyper, &req, &bufferp);
5770             lock_ObtainWrite(&scp->rw);
5771             if (code) {
5772                 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5773                 break;
5774             }
5775
5776             bufferOffset = thyper;
5777
5778             /* now get the data in the cache */
5779             while (1) {
5780                 code = cm_SyncOp(scp, bufferp, userp, &req,
5781                                  PRSFS_LOOKUP,
5782                                  CM_SCACHESYNC_NEEDCALLBACK
5783                                  | CM_SCACHESYNC_READ);
5784                 if (code) {
5785                     osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5786                     break;
5787                 }
5788
5789                 if (cm_HaveBuffer(scp, bufferp, 0)) {
5790                     osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5791                     cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5792                     break;
5793                 }
5794
5795                 /* otherwise, load the buffer and try again */
5796                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5797                                     &req);
5798                 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5799                 if (code) {
5800                     osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5801                               scp, bufferp, code);
5802                     break;
5803                 }
5804             }
5805             if (code) {
5806                 buf_Release(bufferp);
5807                 bufferp = NULL;
5808                 break;
5809             }
5810         }       /* if (wrong buffer) ... */
5811
5812         /* now we have the buffer containing the entry we're interested
5813          * in; copy it out if it represents a non-deleted entry.
5814          */
5815         entryInDir = curOffset.LowPart & (2048-1);
5816         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5817
5818         /* page header will help tell us which entries are free.  Page
5819          * header can change more often than once per buffer, since
5820          * AFS 3 dir page size may be less than (but not more than)
5821          * a buffer package buffer.
5822          */
5823         /* only look intra-buffer */
5824         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5825         temp &= ~(2048 - 1);    /* turn off intra-page bits */
5826         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5827
5828         /* now determine which entry we're looking at in the page.
5829          * If it is free (there's a free bitmap at the start of the
5830          * dir), we should skip these 32 bytes.
5831          */
5832         slotInPage = (entryInDir & 0x7e0) >> 5;
5833         if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5834             (1 << (slotInPage & 0x7)))) {
5835             /* this entry is free */
5836             numDirChunks = 1;   /* only skip this guy */
5837             goto nextEntry;
5838         }
5839
5840         tp = bufferp->datap + entryInBuffer;
5841         dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
5842
5843         /* while we're here, compute the next entry's location, too,
5844          * since we'll need it when writing out the cookie into the dir
5845          * listing stream.
5846          *
5847          * XXXX Probably should do more sanity checking.
5848          */
5849         numDirChunks = cm_NameEntries(dep->name, &onbytes);
5850
5851         /* compute offset of cookie representing next entry */
5852         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5853
5854         if (dep->fid.vnode == 0)
5855             goto nextEntry;             /* This entry is not in use */
5856
5857         if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5858             cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5859
5860             osi_Log1(smb_logp, "Skipping entry [%s].  Can't convert or normalize FS String",
5861                      osi_LogSaveString(smb_logp, dep->name));
5862             goto nextEntry;
5863         }
5864
5865         /* Need 8.3 name? */
5866         NeedShortName = 0;
5867         if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5868             !cm_Is8Dot3(cfileName)) {
5869             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5870             NeedShortName = 1;
5871         }
5872
5873         osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5874                  dep->fid.vnode, dep->fid.unique,
5875                  osi_LogSaveClientString(smb_logp, cfileName),
5876                  NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5877
5878         /* When matching, we are using doing a case fold if we have a wildcard mask.
5879          * If we get a non-wildcard match, it's a lookup for a specific file.
5880          */
5881         if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5882             (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5883         {
5884             /* Eliminate entries that don't match requested attributes */
5885             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5886                 smb_IsDotFile(cfileName)) {
5887                 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5888                 goto nextEntry; /* no hidden files */
5889             }
5890
5891             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
5892             {
5893                 /* We have already done the cm_TryBulkStat above */
5894                 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5895                           ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5896                 fileType = cm_FindFileType(&fid);
5897                 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5898                  * "has filetype %d", dep->name, fileType);
5899                  */
5900                 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5901                      fileType == CM_SCACHETYPE_MOUNTPOINT ||
5902                      fileType == CM_SCACHETYPE_DFSLINK ||
5903                      fileType == CM_SCACHETYPE_INVALID)
5904                     osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5905                 goto nextEntry;
5906             }
5907
5908             /* finally check if this name will fit */
5909             onbytes = 0;
5910             smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5911             orbytes = ohbytes + onbytes;
5912
5913             /* now, we round up the record to a 4 byte alignment,
5914              * and we make sure that we have enough room here for
5915              * even the aligned version (so we don't have to worry
5916              * about an overflow when we pad things out below).
5917              * That's the reason for the alignment arithmetic below.
5918              */
5919             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5920                 align = (4 - (orbytes & 3)) & 3;
5921             else
5922                 align = 0;
5923
5924             if (orbytes + bytesInBuffer + align > maxReturnData) {
5925                 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5926                          maxReturnData);
5927                 break;
5928             }
5929
5930             /* this is one of the entries to use: it is not deleted
5931              * and it matches the star pattern we're looking for.
5932              * Put out the name, preceded by its length.
5933              */
5934             /* First zero everything else */
5935             memset(origOp, 0, orbytes);
5936
5937             onbytes = 0;
5938             smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5939
5940             switch (infoLevel) {
5941             case SMB_INFO_STANDARD:
5942                 fp->u.FstandardInfo.fileNameLength = onbytes;
5943                 attrp = &fp->u.FstandardInfo.fileAttrs;
5944                 break;
5945
5946             case SMB_INFO_QUERY_EA_SIZE:
5947                 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5948                 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5949                 fp->u.FeaSizeInfo.eaSize = 0;
5950                 break;
5951
5952             case SMB_INFO_QUERY_EAS_FROM_LIST:
5953                 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5954                 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5955                 fp->u.FeasFromListInfo.eaSize = 0;
5956                 break;
5957
5958             case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5959                 if (NeedShortName) {
5960 #ifdef SMB_UNICODE
5961                     int nchars;
5962
5963                     nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5964                                                     fp->u.FfileBothDirectoryInfo.shortName,
5965                                                     sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5966                     if (nchars > 0)
5967                         fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5968                     else
5969                         fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5970                     fp->u.FfileBothDirectoryInfo.reserved = 0;
5971 #else
5972                     cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5973                                     lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5974                                     shortName);
5975                     fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5976 #endif
5977                 }
5978                 /* Fallthrough */
5979
5980             case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5981                 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5982                 /* Fallthrough */
5983
5984             case SMB_FIND_FILE_DIRECTORY_INFO:
5985                 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5986                 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5987                 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5988                 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5989                 break;
5990
5991             case SMB_FIND_FILE_NAMES_INFO:
5992                 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5993                 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5994                 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5995                 attrp = NULL;
5996                 break;
5997
5998             default:
5999                 /* we shouldn't hit this case */
6000                 osi_assertx(FALSE, "Unknown query type");
6001             }
6002
6003             /* now, adjust the # of entries copied */
6004             returnedNames++;
6005
6006             /* now we emit the attribute.  This is tricky, since
6007              * we need to really stat the file to find out what
6008              * type of entry we've got.  Right now, we're copying
6009              * out data from a buffer, while holding the scp
6010              * locked, so it isn't really convenient to stat
6011              * something now.  We'll put in a place holder
6012              * now, and make a second pass before returning this
6013              * to get the real attributes.  So, we just skip the
6014              * data for now, and adjust it later.  We allocate a
6015              * patch record to make it easy to find this point
6016              * later.  The replay will happen at a time when it is
6017              * safe to unlock the directory.
6018              */
6019             if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
6020                 osi_assert(attrp != NULL);
6021                 curPatchp = malloc(sizeof(*curPatchp));
6022                 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
6023                 curPatchp->dptr = attrp;
6024
6025                 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
6026                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
6027                 } else {
6028                     curPatchp->flags = 0;
6029                 }
6030
6031                 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
6032
6033                 /* temp */
6034                 curPatchp->dep = dep;
6035             }
6036
6037             if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
6038                 /* put out resume key */
6039                 *((u_long *)origOp) = nextEntryCookie;
6040
6041             /* Adjust byte ptr and count */
6042             origOp += orbytes;  /* skip entire record */
6043             bytesInBuffer += orbytes;
6044
6045             /* and pad the record out */
6046             while (align-- > 0) {
6047                 *origOp++ = 0;
6048                 bytesInBuffer++;
6049             }
6050         }       /* if we're including this name */
6051         else if (!starPattern &&
6052                  !foundInexact &&
6053                  cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
6054             /* We were looking for exact matches, but here's an inexact one*/
6055             foundInexact = 1;
6056         }
6057
6058       nextEntry:
6059         /* and adjust curOffset to be where the new cookie is */
6060         thyper.HighPart = 0;
6061         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
6062         curOffset = LargeIntegerAdd(thyper, curOffset);
6063     } /* while copying data for dir listing */
6064
6065     /* If we didn't get a star pattern, we did an exact match during the first pass.
6066      * If there were no exact matches found, we fail over to inexact matches by
6067      * marking the query as a star pattern (matches all case permutations), and
6068      * re-running the query.
6069      */
6070     if (returnedNames == 0 && !starPattern && foundInexact) {
6071         osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
6072         starPattern = 1;
6073         goto startsearch;
6074     }
6075
6076     /* release the mutex */
6077     lock_ReleaseWrite(&scp->rw);
6078     if (bufferp) {
6079         buf_Release(bufferp);
6080         bufferp = NULL;
6081     }
6082
6083     /*
6084      * Finally, process whatever entries we have left.
6085      */
6086     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
6087                                       dsp->relPath, infoLevel, userp, &req);
6088
6089     /* now put out the final parameters */
6090     if (returnedNames == 0)
6091         eos = 1;
6092     if (p->opcode == 1) {
6093         /* find first */
6094         outp->parmsp[0] = (unsigned short) dsp->cookie;
6095         outp->parmsp[1] = returnedNames;
6096         outp->parmsp[2] = eos;
6097         outp->parmsp[3] = 0;            /* nothing wrong with EAS */
6098         outp->parmsp[4] = 0;
6099         /* don't need last name to continue
6100          * search, cookie is enough.  Normally,
6101          * this is the offset of the file name
6102          * of the last entry returned.
6103          */
6104         outp->totalParms = 10;  /* in bytes */
6105     }
6106     else {
6107         /* find next */
6108         outp->parmsp[0] = returnedNames;
6109         outp->parmsp[1] = eos;
6110         outp->parmsp[2] = 0;    /* EAS error */
6111         outp->parmsp[3] = 0;    /* last name, as above */
6112         outp->totalParms = 8;   /* in bytes */
6113     }
6114
6115     /* return # of bytes in the buffer */
6116     outp->totalData = bytesInBuffer;
6117
6118     /* Return error code if unsuccessful on first request */
6119     if (code == 0 && p->opcode == 1 && returnedNames == 0)
6120         code = CM_ERROR_NOSUCHFILE;
6121
6122     osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
6123              p->opcode, dsp->cookie, returnedNames, code);
6124
6125     /* if we're supposed to close the search after this request, or if
6126      * we're supposed to close the search if we're done, and we're done,
6127      * or if something went wrong, close the search.
6128      */
6129     if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
6130         (returnedNames == 0) ||
6131         ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
6132         code != 0)
6133         smb_DeleteDirSearch(dsp);
6134
6135     if (code)
6136         smb_SendTran2Error(vcp, p, opx, code);
6137     else
6138         smb_SendTran2Packet(vcp, outp, opx);
6139
6140     smb_FreeTran2Packet(outp);
6141     smb_ReleaseDirSearch(dsp);
6142     cm_ReleaseSCache(scp);
6143     cm_ReleaseUser(userp);
6144     return 0;
6145 }
6146
6147 /* SMB_COM_FIND_CLOSE2 */
6148 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6149 {
6150     int dirHandle;
6151     smb_dirSearch_t *dsp;
6152
6153     dirHandle = smb_GetSMBParm(inp, 0);
6154
6155     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
6156
6157     dsp = smb_FindDirSearch(dirHandle);
6158
6159     if (!dsp)
6160         return CM_ERROR_BADFD;
6161
6162     /* otherwise, we have an FD to destroy */
6163     smb_DeleteDirSearch(dsp);
6164     smb_ReleaseDirSearch(dsp);
6165
6166     /* and return results */
6167     smb_SetSMBDataLength(outp, 0);
6168
6169     return 0;
6170 }
6171
6172
6173 /* SMB_COM_FIND_NOTIFY_CLOSE */
6174 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6175 {
6176     smb_SetSMBDataLength(outp, 0);
6177     return 0;
6178 }
6179
6180 /* SMB_COM_OPEN_ANDX */
6181 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6182 {
6183     clientchar_t *pathp;
6184     long code = 0;
6185     cm_space_t *spacep;
6186     int excl;
6187     cm_user_t *userp;
6188     cm_scache_t *dscp;          /* dir we're dealing with */
6189     cm_scache_t *scp;           /* file we're creating */
6190     cm_attr_t setAttr;
6191     smb_fid_t *fidp;
6192     int attributes;
6193     clientchar_t *lastNamep;
6194     unsigned long dosTime;
6195     int openFun;
6196     int trunc;
6197     int openMode;
6198     int extraInfo;
6199     int openAction;
6200     int parmSlot;                       /* which parm we're dealing with */
6201     clientchar_t *tidPathp;
6202     cm_req_t req;
6203     int created = 0;
6204     BOOL is_rpc = FALSE;
6205     BOOL is_ipc = FALSE;
6206
6207     smb_InitReq(&req);
6208
6209     scp = NULL;
6210
6211     extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
6212     openFun = smb_GetSMBParm(inp, 8); /* open function */
6213     excl = ((openFun & 3) == 0);
6214     trunc = ((openFun & 3) == 2); /* truncate it */
6215     openMode = (smb_GetSMBParm(inp, 3) & 0x7);
6216     openAction = 0;             /* tracks what we did */
6217
6218     attributes = smb_GetSMBParm(inp, 5);
6219     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
6220
6221     pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
6222                                 SMB_STRF_ANSIPATH);
6223     if (!pathp)
6224         return CM_ERROR_BADSMB;
6225
6226     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6227     if (code) {
6228         if (code == CM_ERROR_TIDIPC) {
6229             is_ipc = TRUE;
6230         } else {
6231             return CM_ERROR_NOSUCHPATH;
6232         }
6233     }
6234
6235     spacep = inp->spacep;
6236     /* smb_StripLastComponent will strip "::$DATA" if present */
6237     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6238
6239     if (lastNamep &&
6240
6241         /* special case magic file name for receiving IOCTL requests
6242          * (since IOCTL calls themselves aren't getting through).
6243          */
6244         (cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
6245
6246          /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional) */
6247          (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
6248
6249         unsigned short file_type = 0;
6250         unsigned short device_state = 0;
6251
6252         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6253         if (is_rpc) {
6254             code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
6255             osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
6256             if (code) {
6257                 osi_Log1(smb_logp, "smb_SetupRPCFid failure code [%d]", code);
6258                 smb_ReleaseFID(fidp);
6259                 return code;
6260             }
6261         } else {
6262             smb_SetupIoctlFid(fidp, spacep);
6263             osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
6264         }
6265
6266         /* set inp->fid so that later read calls in same msg can find fid */
6267         inp->fid = fidp->fid;
6268
6269         /* copy out remainder of the parms */
6270         parmSlot = 2;
6271         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6272         if (extraInfo) {
6273             smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
6274             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* mod time */
6275             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6276             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* len */
6277             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
6278             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6279             smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
6280             smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
6281         }
6282         /* and the final "always present" stuff */
6283         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
6284         /* next write out the "unique" ID */
6285         smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
6286         smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
6287         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6288         smb_SetSMBDataLength(outp, 0);
6289
6290         /* and clean up fid reference */
6291         smb_ReleaseFID(fidp);
6292         return 0;
6293     }
6294
6295 #ifndef DFS_SUPPORT
6296     if (is_ipc) {
6297         osi_Log0(smb_logp, "NTOpenX rejecting IPC TID");
6298         return CM_ERROR_BADFD;
6299     }
6300 #endif
6301
6302     if (!cm_IsValidClientString(pathp)) {
6303 #ifdef DEBUG
6304         clientchar_t * hexp;
6305
6306         hexp = cm_GetRawCharsAlloc(pathp, -1);
6307         osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
6308                  osi_LogSaveClientString(smb_logp, hexp));
6309         if (hexp)
6310             free(hexp);
6311 #else
6312         osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
6313 #endif
6314         return CM_ERROR_BADNTFILENAME;
6315     }
6316
6317 #ifdef DEBUG_VERBOSE
6318     {
6319         char *hexp, *asciip;
6320         asciip = (lastNamep ? lastNamep : pathp );
6321         hexp = osi_HexifyString(asciip);
6322         DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
6323         free(hexp);
6324     }
6325 #endif
6326     userp = smb_GetUserFromVCP(vcp, inp);
6327
6328     dscp = NULL;
6329     code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
6330                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6331                     userp, tidPathp, &req, &scp);
6332
6333 #ifdef DFS_SUPPORT
6334     if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6335         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
6336         cm_ReleaseSCache(scp);
6337         cm_ReleaseUser(userp);
6338         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6339             return CM_ERROR_PATH_NOT_COVERED;
6340         else
6341             return CM_ERROR_NOSUCHPATH;
6342     }
6343 #endif /* DFS_SUPPORT */
6344
6345     if (code != 0) {
6346         if (code == CM_ERROR_NOSUCHFILE ||
6347             code == CM_ERROR_NOSUCHPATH ||
6348             code == CM_ERROR_BPLUS_NOMATCH)
6349             code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
6350                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6351                             userp, tidPathp, &req, &dscp);
6352         if (code) {
6353             cm_ReleaseUser(userp);
6354             return code;
6355         }
6356
6357 #ifdef DFS_SUPPORT
6358         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6359             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6360                                                       spacep->wdata);
6361             cm_ReleaseSCache(dscp);
6362             cm_ReleaseUser(userp);
6363             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6364                 return CM_ERROR_PATH_NOT_COVERED;
6365             else
6366                 return CM_ERROR_NOSUCHPATH;
6367         }
6368 #endif /* DFS_SUPPORT */
6369         /* otherwise, scp points to the parent directory.  Do a lookup,
6370          * and truncate the file if we find it, otherwise we create the
6371          * file.
6372          */
6373         if (!lastNamep)
6374             lastNamep = pathp;
6375         else
6376             lastNamep++;
6377         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
6378                           &req, &scp);
6379         if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6380             cm_ReleaseSCache(dscp);
6381             cm_ReleaseUser(userp);
6382             return code;
6383         }
6384     }
6385
6386     /* if we get here, if code is 0, the file exists and is represented by
6387      * scp.  Otherwise, we have to create it.  The dir may be represented
6388      * by dscp, or we may have found the file directly.  If code is non-zero,
6389      * scp is NULL.
6390      */
6391     if (code == 0) {
6392         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
6393         if (code) {
6394             if (dscp) cm_ReleaseSCache(dscp);
6395             cm_ReleaseSCache(scp);
6396             cm_ReleaseUser(userp);
6397             return code;
6398         }
6399
6400         if (excl) {
6401             /* oops, file shouldn't be there */
6402             if (dscp)
6403                 cm_ReleaseSCache(dscp);
6404             cm_ReleaseSCache(scp);
6405             cm_ReleaseUser(userp);
6406             return CM_ERROR_EXISTS;
6407         }
6408
6409         if (trunc) {
6410             setAttr.mask = CM_ATTRMASK_LENGTH;
6411             setAttr.length.LowPart = 0;
6412             setAttr.length.HighPart = 0;
6413             code = cm_SetAttr(scp, &setAttr, userp, &req);
6414             openAction = 3;     /* truncated existing file */
6415         }
6416         else openAction = 1;    /* found existing file */
6417     }
6418     else if (!(openFun & SMB_ATTR_DIRECTORY)) {
6419         /* don't create if not found */
6420         if (dscp) cm_ReleaseSCache(dscp);
6421         cm_ReleaseUser(userp);
6422         return CM_ERROR_NOSUCHFILE;
6423     }
6424     else {
6425         osi_assertx(dscp != NULL, "null cm_scache_t");
6426         osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
6427                  osi_LogSaveClientString(smb_logp, lastNamep));
6428         openAction = 2; /* created file */
6429         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6430         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6431         smb_SetInitialModeBitsForFile(attributes, &setAttr);
6432
6433         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6434                          &req);
6435         if (code == 0) {
6436             created = 1;
6437             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6438                 smb_NotifyChange(FILE_ACTION_ADDED,
6439                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6440                                  dscp, lastNamep, NULL, TRUE);
6441         } else if (!excl && code == CM_ERROR_EXISTS) {
6442             /* not an exclusive create, and someone else tried
6443              * creating it already, then we open it anyway.  We
6444              * don't bother retrying after this, since if this next
6445              * fails, that means that the file was deleted after we
6446              * started this call.
6447              */
6448             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6449                              userp, &req, &scp);
6450             if (code == 0) {
6451                 if (trunc) {
6452                     setAttr.mask = CM_ATTRMASK_LENGTH;
6453                     setAttr.length.LowPart = 0;
6454                     setAttr.length.HighPart = 0;
6455                     code = cm_SetAttr(scp, &setAttr, userp, &req);
6456                 }
6457             }   /* lookup succeeded */
6458         }
6459     }
6460
6461     /* we don't need this any longer */
6462     if (dscp)
6463         cm_ReleaseSCache(dscp);
6464
6465     if (code) {
6466         /* something went wrong creating or truncating the file */
6467         if (scp)
6468             cm_ReleaseSCache(scp);
6469         cm_ReleaseUser(userp);
6470         return code;
6471     }
6472
6473     /* make sure we're about to open a file */
6474     if (scp->fileType != CM_SCACHETYPE_FILE) {
6475         cm_ReleaseSCache(scp);
6476         cm_ReleaseUser(userp);
6477         return CM_ERROR_ISDIR;
6478     }
6479
6480     /* now all we have to do is open the file itself */
6481     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6482     osi_assertx(fidp, "null smb_fid_t");
6483
6484     cm_HoldUser(userp);
6485     lock_ObtainMutex(&fidp->mx);
6486     /* save a pointer to the vnode */
6487     fidp->scp = scp;
6488     lock_ObtainWrite(&scp->rw);
6489     scp->flags |= CM_SCACHEFLAG_SMB_FID;
6490     lock_ReleaseWrite(&scp->rw);
6491     osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
6492     /* also the user */
6493     fidp->userp = userp;
6494
6495     /* compute open mode */
6496     if (openMode != 1)
6497         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
6498     if (openMode == 1 || openMode == 2)
6499         fidp->flags |= SMB_FID_OPENWRITE;
6500
6501     /* remember if the file was newly created */
6502     if (created)
6503         fidp->flags |= SMB_FID_CREATED;
6504
6505     lock_ReleaseMutex(&fidp->mx);
6506     smb_ReleaseFID(fidp);
6507
6508     cm_Open(scp, 0, userp);
6509
6510     /* set inp->fid so that later read calls in same msg can find fid */
6511     inp->fid = fidp->fid;
6512
6513     /* copy out remainder of the parms */
6514     parmSlot = 2;
6515     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6516     lock_ObtainRead(&scp->rw);
6517     if (extraInfo) {
6518         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
6519         smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
6520         smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
6521         smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
6522         smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
6523         smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
6524         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6525         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
6526         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
6527     }
6528     /* and the final "always present" stuff */
6529     smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
6530     /* next write out the "unique" ID */
6531     smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
6532     smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
6533     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6534     lock_ReleaseRead(&scp->rw);
6535     smb_SetSMBDataLength(outp, 0);
6536
6537     osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
6538
6539     cm_ReleaseUser(userp);
6540     /* leave scp held since we put it in fidp->scp */
6541     return 0;
6542 }
6543
6544 static void smb_GetLockParams(unsigned char LockType,
6545                               char ** buf,
6546                               unsigned int * ppid,
6547                               LARGE_INTEGER * pOffset,
6548                               LARGE_INTEGER * pLength)
6549 {
6550     if (LockType & LOCKING_ANDX_LARGE_FILES) {
6551         /* Large Files */
6552         *ppid = *((USHORT *) *buf);
6553         pOffset->HighPart = *((LONG *)(*buf + 4));
6554         pOffset->LowPart = *((DWORD *)(*buf + 8));
6555         pLength->HighPart = *((LONG *)(*buf + 12));
6556         pLength->LowPart = *((DWORD *)(*buf + 16));
6557         *buf += 20;
6558     }
6559     else {
6560         /* Not Large Files */
6561         *ppid = *((USHORT *) *buf);
6562         pOffset->HighPart = 0;
6563         pOffset->LowPart = *((DWORD *)(*buf + 2));
6564         pLength->HighPart = 0;
6565         pLength->LowPart = *((DWORD *)(*buf + 6));
6566         *buf += 10;
6567     }
6568 }
6569
6570 /* SMB_COM_LOCKING_ANDX */
6571 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6572 {
6573     cm_req_t req;
6574     cm_user_t *userp;
6575     unsigned short fid;
6576     smb_fid_t *fidp;
6577     cm_scache_t *scp;
6578     unsigned char LockType;
6579     unsigned short NumberOfUnlocks, NumberOfLocks;
6580     afs_uint32 Timeout;
6581     char *op;
6582     char *op_locks;
6583     LARGE_INTEGER LOffset, LLength;
6584     smb_waitingLockRequest_t *wlRequest = NULL;
6585     cm_file_lock_t *lockp;
6586     long code = 0;
6587     int i;
6588     cm_key_t key;
6589     unsigned int pid;
6590     afs_uint32 smb_vc_hold_required = 0;
6591
6592     smb_InitReq(&req);
6593
6594     fid = smb_GetSMBParm(inp, 2);
6595     fid = smb_ChainFID(fid, inp);
6596
6597     fidp = smb_FindFID(vcp, fid, 0);
6598     if (!fidp) {
6599         osi_Log2(smb_logp, "V3LockingX Unknown SMB Fid vcp 0x%p fid %d",
6600                  vcp, fid);
6601         return CM_ERROR_BADFD;
6602     }
6603     lock_ObtainMutex(&fidp->mx);
6604     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6605         lock_ReleaseMutex(&fidp->mx);
6606         smb_CloseFID(vcp, fidp, NULL, 0);
6607         smb_ReleaseFID(fidp);
6608         return CM_ERROR_NOSUCHFILE;
6609     }
6610
6611     if (fidp->flags & SMB_FID_IOCTL) {
6612         osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6613         lock_ReleaseMutex(&fidp->mx);
6614         smb_ReleaseFID(fidp);
6615         return CM_ERROR_BADFD;
6616     }
6617     scp = fidp->scp;
6618     osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6619     cm_HoldSCache(scp);
6620     lock_ReleaseMutex(&fidp->mx);
6621
6622     /* set inp->fid so that later read calls in same msg can find fid */
6623     inp->fid = fid;
6624
6625     userp = smb_GetUserFromVCP(vcp, inp);
6626     smb_HoldVC(vcp);
6627
6628     lock_ObtainWrite(&scp->rw);
6629     code = cm_SyncOp(scp, NULL, userp, &req, 0,
6630                       CM_SCACHESYNC_NEEDCALLBACK
6631                          | CM_SCACHESYNC_GETSTATUS
6632                          | CM_SCACHESYNC_LOCK);
6633     if (code) {
6634         osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6635         goto doneSync;
6636     }
6637
6638     LockType = smb_GetSMBParm(inp, 3) & 0xff;
6639     Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6640     NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6641     NumberOfLocks = smb_GetSMBParm(inp, 7);
6642
6643     if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6644         !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6645         /* somebody wants exclusive locks on a file that they only
6646            opened for reading.  We downgrade this to a shared lock. */
6647         osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6648         LockType |= LOCKING_ANDX_SHARED_LOCK;
6649     }
6650
6651     if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6652         /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6653         osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6654         code = CM_ERROR_BADOP;
6655         goto done;
6656
6657     }
6658
6659     op = smb_GetSMBData(inp, NULL);
6660
6661     if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6662         /* Cancel outstanding lock requests */
6663         smb_waitingLock_t * wl;
6664
6665         for (i=0; i<NumberOfLocks; i++) {
6666             smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6667
6668             key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6669
6670             lock_ObtainWrite(&smb_globalLock);
6671             for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6672             {
6673                 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6674                     if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6675                         LargeIntegerEqualTo(wl->LLength, LLength)) {
6676                         wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6677                         goto found_lock_request;
6678                     }
6679                 }
6680             }
6681           found_lock_request:
6682             lock_ReleaseWrite(&smb_globalLock);
6683         }
6684         code = 0;
6685         smb_SetSMBDataLength(outp, 0);
6686         goto done;
6687     }
6688
6689
6690     for (i=0; i<NumberOfUnlocks; i++) {
6691         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6692
6693         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6694
6695         code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6696
6697         if (code)
6698             goto done;
6699     }
6700
6701     op_locks = op;
6702
6703     for (i=0; i<NumberOfLocks; i++) {
6704         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6705
6706         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6707
6708         code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6709                         userp, &req, &lockp);
6710
6711         if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6712             (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6713         {
6714             code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6715                             userp, &req, &lockp);
6716         }
6717
6718         if (code == CM_ERROR_LOCK_NOT_GRANTED && Timeout != 0) {
6719             smb_waitingLock_t * wLock;
6720
6721             /* Put on waiting list */
6722             if(wlRequest == NULL) {
6723                 int j;
6724                 char * opt;
6725                 cm_key_t tkey;
6726                 LARGE_INTEGER tOffset, tLength;
6727
6728                 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6729
6730                 osi_assertx(wlRequest != NULL, "null wlRequest");
6731
6732                 wlRequest->vcp = vcp;
6733                 smb_vc_hold_required = 1;
6734                 wlRequest->scp = scp;
6735                 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6736                 cm_HoldSCache(scp);
6737                 wlRequest->inp = smb_CopyPacket(inp);
6738                 wlRequest->outp = smb_CopyPacket(outp);
6739                 wlRequest->lockType = LockType;
6740                 wlRequest->msTimeout = Timeout;
6741                 wlRequest->start_t = osi_Time();
6742                 wlRequest->locks = NULL;
6743
6744                 /* The waiting lock request needs to have enough
6745                    information to undo all the locks in the request.
6746                    We do the following to store info about locks that
6747                    have already been granted.  Sure, we can get most
6748                    of the info from the packet, but the packet doesn't
6749                    hold the result of cm_Lock call.  In practice we
6750                    only receive packets with one or two locks, so we
6751                    are only wasting a few bytes here and there and
6752                    only for a limited period of time until the waiting
6753                    lock times out or is freed. */
6754
6755                 for(opt = op_locks, j=i; j > 0; j--) {
6756                     smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6757
6758                     tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6759
6760                     wLock = malloc(sizeof(smb_waitingLock_t));
6761
6762                     osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6763
6764                     wLock->key = tkey;
6765                     wLock->LOffset = tOffset;
6766                     wLock->LLength = tLength;
6767                     wLock->lockp = NULL;
6768                     wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6769                     osi_QAdd((osi_queue_t **) &wlRequest->locks,
6770                              &wLock->q);
6771                 }
6772             }
6773
6774             wLock = malloc(sizeof(smb_waitingLock_t));
6775
6776             osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6777
6778             wLock->key = key;
6779             wLock->LOffset = LOffset;
6780             wLock->LLength = LLength;
6781             wLock->lockp = lockp;
6782             wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6783             osi_QAdd((osi_queue_t **) &wlRequest->locks,
6784                      &wLock->q);
6785
6786             osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6787                      wLock);
6788
6789             code = 0;
6790             continue;
6791         }
6792
6793         if (code) {
6794             osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6795             break;
6796         }
6797     }
6798
6799     if (code) {
6800
6801         /* Since something went wrong with the lock number i, we now
6802            have to go ahead and release any locks acquired before the
6803            failure.  All locks before lock number i (of which there
6804            are i of them) have either been successful or are waiting.
6805            Either case requires calling cm_Unlock(). */
6806
6807         /* And purge the waiting lock */
6808         if(wlRequest != NULL) {
6809             smb_waitingLock_t * wl;
6810             smb_waitingLock_t * wlNext;
6811             long ul_code;
6812
6813             for(wl = wlRequest->locks; wl; wl = wlNext) {
6814
6815                 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6816
6817                 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6818
6819                 if(ul_code != 0) {
6820                     osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6821                 } else {
6822                     osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6823                 }
6824
6825                 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6826                 free(wl);
6827
6828             }
6829
6830             smb_ReleaseVC(wlRequest->vcp);
6831             cm_ReleaseSCache(wlRequest->scp);
6832             smb_FreePacket(wlRequest->inp);
6833             smb_FreePacket(wlRequest->outp);
6834
6835             free(wlRequest);
6836
6837             wlRequest = NULL;
6838         }
6839
6840     } else {
6841
6842         if (wlRequest != NULL) {
6843
6844             lock_ObtainWrite(&smb_globalLock);
6845             osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6846                      &wlRequest->q);
6847             osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6848             lock_ReleaseWrite(&smb_globalLock);
6849
6850             /* don't send reply immediately */
6851             outp->flags |= SMB_PACKETFLAG_NOSEND;
6852         }
6853
6854         smb_SetSMBDataLength(outp, 0);
6855     }
6856
6857   done:
6858     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6859
6860   doneSync:
6861     lock_ReleaseWrite(&scp->rw);
6862     cm_ReleaseSCache(scp);
6863     cm_ReleaseUser(userp);
6864     smb_ReleaseFID(fidp);
6865     if (!smb_vc_hold_required)
6866         smb_HoldVC(vcp);
6867
6868     return code;
6869 }
6870
6871 /* SMB_COM_QUERY_INFORMATION2 */
6872 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6873 {
6874     unsigned short fid;
6875     smb_fid_t *fidp;
6876     cm_scache_t *scp;
6877     long code = 0;
6878     afs_uint32 searchTime;
6879     cm_user_t *userp;
6880     cm_req_t req;
6881     int readlock = 0;
6882
6883     smb_InitReq(&req);
6884
6885     fid = smb_GetSMBParm(inp, 0);
6886     fid = smb_ChainFID(fid, inp);
6887
6888     fidp = smb_FindFID(vcp, fid, 0);
6889     if (!fidp) {
6890         osi_Log2(smb_logp, "V3GetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6891                  vcp, fid);
6892         return CM_ERROR_BADFD;
6893     }
6894     lock_ObtainMutex(&fidp->mx);
6895     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6896         lock_ReleaseMutex(&fidp->mx);
6897         smb_CloseFID(vcp, fidp, NULL, 0);
6898         smb_ReleaseFID(fidp);
6899         return CM_ERROR_NOSUCHFILE;
6900     }
6901
6902     if (fidp->flags & SMB_FID_IOCTL) {
6903         lock_ReleaseMutex(&fidp->mx);
6904         smb_ReleaseFID(fidp);
6905         return CM_ERROR_BADFD;
6906     }
6907     scp = fidp->scp;
6908     osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6909     cm_HoldSCache(scp);
6910     lock_ReleaseMutex(&fidp->mx);
6911
6912     userp = smb_GetUserFromVCP(vcp, inp);
6913
6914
6915     /* otherwise, stat the file */
6916     lock_ObtainWrite(&scp->rw);
6917     code = cm_SyncOp(scp, NULL, userp, &req, 0,
6918                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6919     if (code)
6920         goto done;
6921
6922     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6923
6924     lock_ConvertWToR(&scp->rw);
6925     readlock = 1;
6926
6927     /* decode times.  We need a search time, but the response to this
6928      * call provides the date first, not the time, as returned in the
6929      * searchTime variable.  So we take the high-order bits first.
6930      */
6931     cm_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6932     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);       /* ctime */
6933     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6934     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);       /* atime */
6935     smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6936     smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);       /* mtime */
6937     smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6938
6939     /* now handle file size and allocation size */
6940     smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);              /* file size */
6941     smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6942     smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);              /* alloc size */
6943     smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6944
6945     /* file attribute */
6946     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6947
6948     /* and finalize stuff */
6949     smb_SetSMBDataLength(outp, 0);
6950     code = 0;
6951
6952   done:
6953     if (readlock)
6954         lock_ReleaseRead(&scp->rw);
6955     else
6956         lock_ReleaseWrite(&scp->rw);
6957     cm_ReleaseSCache(scp);
6958     cm_ReleaseUser(userp);
6959     smb_ReleaseFID(fidp);
6960     return code;
6961 }
6962
6963 /* SMB_COM_SET_INFORMATION2 */
6964 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6965 {
6966     unsigned short fid;
6967     smb_fid_t *fidp;
6968     cm_scache_t *scp;
6969     long code = 0;
6970     afs_uint32 searchTime;
6971     time_t unixTime;
6972     cm_user_t *userp;
6973     cm_attr_t attrs;
6974     cm_req_t req;
6975
6976     smb_InitReq(&req);
6977
6978     fid = smb_GetSMBParm(inp, 0);
6979     fid = smb_ChainFID(fid, inp);
6980
6981     fidp = smb_FindFID(vcp, fid, 0);
6982     if (!fidp) {
6983         osi_Log2(smb_logp, "V3SetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6984                  vcp, fid);
6985         return CM_ERROR_BADFD;
6986     }
6987     lock_ObtainMutex(&fidp->mx);
6988     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6989         lock_ReleaseMutex(&fidp->mx);
6990         smb_CloseFID(vcp, fidp, NULL, 0);
6991         smb_ReleaseFID(fidp);
6992         return CM_ERROR_NOSUCHFILE;
6993     }
6994
6995     if (fidp->flags & SMB_FID_IOCTL) {
6996         lock_ReleaseMutex(&fidp->mx);
6997         smb_ReleaseFID(fidp);
6998         return CM_ERROR_BADFD;
6999     }
7000     scp = fidp->scp;
7001     osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
7002     cm_HoldSCache(scp);
7003     lock_ReleaseMutex(&fidp->mx);
7004
7005     userp = smb_GetUserFromVCP(vcp, inp);
7006
7007     /* now prepare to call cm_setattr.  This message only sets various times,
7008      * and AFS only implements mtime, and we'll set the mtime if that's
7009      * requested.  The others we'll ignore.
7010      */
7011     searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
7012
7013     if (searchTime != 0) {
7014         cm_UnixTimeFromSearchTime(&unixTime, searchTime);
7015
7016         if ( unixTime != -1 ) {
7017             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
7018             attrs.clientModTime = unixTime;
7019             code = cm_SetAttr(scp, &attrs, userp, &req);
7020
7021             osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
7022         } else {
7023             osi_Log1(smb_logp, "**cm_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
7024         }
7025     }
7026     else
7027         code = 0;
7028
7029     cm_ReleaseSCache(scp);
7030     cm_ReleaseUser(userp);
7031     smb_ReleaseFID(fidp);
7032     return code;
7033 }
7034
7035 /* SMB_COM_WRITE_ANDX */
7036 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7037 {
7038     osi_hyper_t offset;
7039     long count, written = 0, total_written = 0;
7040     unsigned short fd;
7041     unsigned pid;
7042     smb_fid_t *fidp;
7043     smb_t *smbp = (smb_t*) inp;
7044     long code = 0;
7045     cm_scache_t *scp;
7046     cm_user_t *userp;
7047     char *op;
7048     int inDataBlockCount;
7049
7050     fd = smb_GetSMBParm(inp, 2);
7051     count = smb_GetSMBParm(inp, 10);
7052
7053     offset.HighPart = 0;
7054     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7055
7056     if (*inp->wctp == 14) {
7057         /* we have a request with 64-bit file offsets */
7058         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7059     }
7060
7061     op = inp->data + smb_GetSMBParm(inp, 11);
7062     inDataBlockCount = count;
7063
7064     osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
7065              fd, offset.HighPart, offset.LowPart, count);
7066
7067     fd = smb_ChainFID(fd, inp);
7068     fidp = smb_FindFID(vcp, fd, 0);
7069     if (!fidp) {
7070         osi_Log2(smb_logp, "smb_ReceiveV3WriteX Unknown SMB Fid vcp 0x%p fid %d",
7071                  vcp, fd);
7072         return CM_ERROR_BADFD;
7073     }
7074     lock_ObtainMutex(&fidp->mx);
7075     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7076         lock_ReleaseMutex(&fidp->mx);
7077         smb_CloseFID(vcp, fidp, NULL, 0);
7078         smb_ReleaseFID(fidp);
7079         return CM_ERROR_NOSUCHFILE;
7080     }
7081
7082     if (fidp->flags & SMB_FID_IOCTL) {
7083         lock_ReleaseMutex(&fidp->mx);
7084         code = smb_IoctlV3Write(fidp, vcp, inp, outp);
7085         smb_ReleaseFID(fidp);
7086         return code;
7087     }
7088
7089     if (fidp->flags & SMB_FID_RPC) {
7090         lock_ReleaseMutex(&fidp->mx);
7091         code = smb_RPCV3Write(fidp, vcp, inp, outp);
7092         smb_ReleaseFID(fidp);
7093         return code;
7094     }
7095
7096     if (!fidp->scp) {
7097         lock_ReleaseMutex(&fidp->mx);
7098         smb_ReleaseFID(fidp);
7099         return CM_ERROR_BADFDOP;
7100     }
7101
7102     scp = fidp->scp;
7103     cm_HoldSCache(scp);
7104     lock_ReleaseMutex(&fidp->mx);
7105
7106     userp = smb_GetUserFromVCP(vcp, inp);
7107
7108     /* special case: 0 bytes transferred means there is no data
7109        transferred.  A slight departure from SMB_COM_WRITE where this
7110        means that we are supposed to truncate the file at this
7111        position. */
7112
7113     {
7114         cm_key_t key;
7115         LARGE_INTEGER LOffset;
7116         LARGE_INTEGER LLength;
7117
7118         pid = smbp->pid;
7119         key = cm_GenerateKey(vcp->vcID, pid, fd);
7120
7121         LOffset.HighPart = offset.HighPart;
7122         LOffset.LowPart = offset.LowPart;
7123         LLength.HighPart = 0;
7124         LLength.LowPart = count;
7125
7126         lock_ObtainWrite(&scp->rw);
7127         code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7128         lock_ReleaseWrite(&scp->rw);
7129
7130         if (code)
7131             goto done;
7132     }
7133
7134     /*
7135      * Work around bug in NT client
7136      *
7137      * When copying a file, the NT client should first copy the data,
7138      * then copy the last write time.  But sometimes the NT client does
7139      * these in the wrong order, so the data copies would inadvertently
7140      * cause the last write time to be overwritten.  We try to detect this,
7141      * and don't set client mod time if we think that would go against the
7142      * intention.
7143      */
7144     lock_ObtainMutex(&fidp->mx);
7145     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7146         lock_ObtainWrite(&fidp->scp->rw);
7147         scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7148         scp->clientModTime = time(NULL);
7149         lock_ReleaseWrite(&fidp->scp->rw);
7150     }
7151     lock_ReleaseMutex(&fidp->mx);
7152
7153     code = 0;
7154     while ( code == 0 && count > 0 ) {
7155         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7156         if (code == 0 && written == 0)
7157             code = CM_ERROR_PARTIALWRITE;
7158
7159         offset = LargeIntegerAdd(offset,
7160                                  ConvertLongToLargeInteger(written));
7161         count -= written;
7162         total_written += written;
7163         written = 0;
7164     }
7165
7166     /* slots 0 and 1 are reserved for request chaining and will be
7167        filled in when we return. */
7168     smb_SetSMBParm(outp, 2, total_written);
7169     smb_SetSMBParm(outp, 3, 0); /* reserved */
7170     smb_SetSMBParm(outp, 4, 0); /* reserved */
7171     smb_SetSMBParm(outp, 5, 0); /* reserved */
7172     smb_SetSMBDataLength(outp, 0);
7173
7174  done:
7175
7176     cm_ReleaseSCache(scp);
7177     cm_ReleaseUser(userp);
7178     smb_ReleaseFID(fidp);
7179
7180     return code;
7181 }
7182
7183 /* SMB_COM_READ_ANDX */
7184 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7185 {
7186     osi_hyper_t offset;
7187     long count;
7188     long finalCount = 0;
7189     unsigned short fd;
7190     unsigned pid;
7191     smb_fid_t *fidp;
7192     smb_t *smbp = (smb_t*) inp;
7193     long code = 0;
7194     cm_scache_t *scp;
7195     cm_user_t *userp;
7196     cm_key_t key;
7197     char *op;
7198
7199     fd = smb_GetSMBParm(inp, 2); /* File ID */
7200     count = smb_GetSMBParm(inp, 5); /* MaxCount */
7201     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7202
7203     if (*inp->wctp == 12) {
7204         /* a request with 64-bit offsets */
7205         offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
7206
7207         if (LargeIntegerLessThanZero(offset)) {
7208             osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
7209                      offset.HighPart, offset.LowPart);
7210             return CM_ERROR_BADSMB;
7211         }
7212     } else {
7213         offset.HighPart = 0;
7214     }
7215
7216     osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
7217              fd, offset.HighPart, offset.LowPart, count);
7218
7219     fd = smb_ChainFID(fd, inp);
7220     fidp = smb_FindFID(vcp, fd, 0);
7221     if (!fidp) {
7222         osi_Log2(smb_logp, "smb_ReceiveV3Read Unknown SMB Fid vcp 0x%p fid %d",
7223                  vcp, fd);
7224         return CM_ERROR_BADFD;
7225     }
7226
7227     lock_ObtainMutex(&fidp->mx);
7228
7229     if (fidp->flags & SMB_FID_IOCTL) {
7230         lock_ReleaseMutex(&fidp->mx);
7231         inp->fid = fd;
7232         code = smb_IoctlV3Read(fidp, vcp, inp, outp);
7233         smb_ReleaseFID(fidp);
7234         return code;
7235     }
7236
7237     if (fidp->flags & SMB_FID_RPC) {
7238         lock_ReleaseMutex(&fidp->mx);
7239         inp->fid = fd;
7240         code = smb_RPCV3Read(fidp, vcp, inp, outp);
7241         smb_ReleaseFID(fidp);
7242         return code;
7243     }
7244
7245     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7246         lock_ReleaseMutex(&fidp->mx);
7247         smb_CloseFID(vcp, fidp, NULL, 0);
7248         smb_ReleaseFID(fidp);
7249         return CM_ERROR_NOSUCHFILE;
7250     }
7251
7252     if (!fidp->scp) {
7253         lock_ReleaseMutex(&fidp->mx);
7254         smb_ReleaseFID(fidp);
7255         return CM_ERROR_BADFDOP;
7256     }
7257
7258     scp = fidp->scp;
7259     cm_HoldSCache(scp);
7260
7261     lock_ReleaseMutex(&fidp->mx);
7262
7263     pid = smbp->pid;
7264     key = cm_GenerateKey(vcp->vcID, pid, fd);
7265     {
7266         LARGE_INTEGER LOffset, LLength;
7267
7268         LOffset.HighPart = offset.HighPart;
7269         LOffset.LowPart = offset.LowPart;
7270         LLength.HighPart = 0;
7271         LLength.LowPart = count;
7272
7273         lock_ObtainWrite(&scp->rw);
7274         code = cm_LockCheckRead(scp, LOffset, LLength, key);
7275         lock_ReleaseWrite(&scp->rw);
7276     }
7277     cm_ReleaseSCache(scp);
7278
7279     if (code) {
7280         smb_ReleaseFID(fidp);
7281         return code;
7282     }
7283
7284     /* set inp->fid so that later read calls in same msg can find fid */
7285     inp->fid = fd;
7286
7287     userp = smb_GetUserFromVCP(vcp, inp);
7288
7289     /* 0 and 1 are reserved for request chaining, were setup by our caller,
7290      * and will be further filled in after we return.
7291      */
7292     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
7293     smb_SetSMBParm(outp, 3, 0); /* resvd */
7294     smb_SetSMBParm(outp, 4, 0); /* resvd */
7295     smb_SetSMBParm(outp, 5, count);     /* # of bytes we're going to read */
7296     /* fill in #6 when we have all the parameters' space reserved */
7297     smb_SetSMBParm(outp, 7, 0); /* resv'd */
7298     smb_SetSMBParm(outp, 8, 0); /* resv'd */
7299     smb_SetSMBParm(outp, 9, 0); /* resv'd */
7300     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
7301     smb_SetSMBParm(outp, 11, 0);        /* reserved */
7302
7303     /* get op ptr after putting in the parms, since otherwise we don't
7304      * know where the data really is.
7305      */
7306     op = smb_GetSMBData(outp, NULL);
7307
7308     /* now fill in offset from start of SMB header to first data byte (to op) */
7309     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
7310
7311     /* set the packet data length the count of the # of bytes */
7312     smb_SetSMBDataLength(outp, count);
7313
7314     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7315
7316     /* fix some things up */
7317     smb_SetSMBParm(outp, 5, finalCount);
7318     smb_SetSMBDataLength(outp, finalCount);
7319
7320     cm_ReleaseUser(userp);
7321     smb_ReleaseFID(fidp);
7322     return code;
7323 }
7324
7325 /*
7326  * Values for createDisp, copied from NTDDK.H
7327  */
7328 #define  FILE_SUPERSEDE 0       // (???)
7329 #define  FILE_OPEN      1       // (open)
7330 #define  FILE_CREATE    2       // (exclusive)
7331 #define  FILE_OPEN_IF   3       // (non-exclusive)
7332 #define  FILE_OVERWRITE 4       // (open & truncate, but do not create)
7333 #define  FILE_OVERWRITE_IF 5    // (open & truncate, or create)
7334
7335 /* Flags field */
7336 #define REQUEST_OPLOCK 2
7337 #define REQUEST_BATCH_OPLOCK 4
7338 #define OPEN_DIRECTORY 8
7339 #define EXTENDED_RESPONSE_REQUIRED 0x10
7340
7341 /* CreateOptions field. */
7342 #define FILE_DIRECTORY_FILE       0x0001
7343 #define FILE_WRITE_THROUGH        0x0002
7344 #define FILE_SEQUENTIAL_ONLY      0x0004
7345 #define FILE_NON_DIRECTORY_FILE   0x0040
7346 #define FILE_NO_EA_KNOWLEDGE      0x0200
7347 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
7348 #define FILE_RANDOM_ACCESS        0x0800
7349 #define FILE_DELETE_ON_CLOSE      0x1000
7350 #define FILE_OPEN_BY_FILE_ID      0x2000
7351 #define FILE_OPEN_FOR_BACKUP_INTENT             0x00004000
7352 #define FILE_NO_COMPRESSION                     0x00008000
7353 #define FILE_RESERVE_OPFILTER                   0x00100000
7354 #define FILE_OPEN_REPARSE_POINT                 0x00200000
7355 #define FILE_OPEN_NO_RECALL                     0x00400000
7356 #define FILE_OPEN_FOR_FREE_SPACE_QUERY          0x00800000
7357
7358 /* SMB_COM_NT_CREATE_ANDX */
7359 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7360 {
7361     clientchar_t *pathp, *realPathp;
7362     long code = 0;
7363     cm_space_t *spacep;
7364     cm_user_t *userp;
7365     cm_scache_t *dscp;          /* parent dir */
7366     cm_scache_t *scp;           /* file to create or open */
7367     cm_scache_t *targetScp;     /* if scp is a symlink */
7368     cm_attr_t setAttr;
7369     clientchar_t *lastNamep;
7370     clientchar_t *treeStartp;
7371     unsigned short nameLength;
7372     unsigned int flags;
7373     unsigned int requestOpLock;
7374     unsigned int requestBatchOpLock;
7375     unsigned int mustBeDir;
7376     unsigned int extendedRespRequired;
7377     unsigned int treeCreate;
7378     int realDirFlag;
7379     unsigned int desiredAccess;
7380     unsigned int extAttributes;
7381     unsigned int createDisp;
7382     unsigned int createOptions;
7383     unsigned int shareAccess;
7384     unsigned short baseFid;
7385     smb_fid_t *baseFidp;
7386     smb_fid_t *fidp;
7387     cm_scache_t *baseDirp;
7388     unsigned short openAction;
7389     int parmSlot;
7390     long fidflags;
7391     FILETIME ft;
7392     LARGE_INTEGER sz;
7393     clientchar_t *tidPathp;
7394     BOOL foundscp;
7395     cm_req_t req;
7396     int created = 0;
7397     int prefetch = 0;
7398     int checkDoneRequired = 0;
7399     cm_lock_data_t *ldp = NULL;
7400     BOOL is_rpc = FALSE;
7401     BOOL is_ipc = FALSE;
7402
7403     smb_InitReq(&req);
7404
7405     /* This code is very long and has a lot of if-then-else clauses
7406      * scp and dscp get reused frequently and we need to ensure that
7407      * we don't lose a reference.  Start by ensuring that they are NULL.
7408      */
7409     scp = NULL;
7410     dscp = NULL;
7411     treeCreate = FALSE;
7412     foundscp = FALSE;
7413
7414     nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
7415     flags = smb_GetSMBOffsetParm(inp, 3, 1)
7416         | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
7417     requestOpLock = flags & REQUEST_OPLOCK;
7418     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7419     mustBeDir = flags & OPEN_DIRECTORY;
7420     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7421
7422     /*
7423      * Why all of a sudden 32-bit FID?
7424      * We will reject all bits higher than 16.
7425      */
7426     if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
7427         return CM_ERROR_INVAL;
7428     baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
7429     desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
7430         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7431     extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
7432         | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
7433     shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
7434         | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
7435     createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
7436         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
7437     createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
7438         | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
7439
7440     /* mustBeDir is never set; createOptions directory bit seems to be
7441      * more important
7442      */
7443     if (createOptions & FILE_DIRECTORY_FILE)
7444         realDirFlag = 1;
7445     else if (createOptions & FILE_NON_DIRECTORY_FILE)
7446         realDirFlag = 0;
7447     else
7448         realDirFlag = -1;
7449
7450     pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
7451                               NULL, SMB_STRF_ANSIPATH);
7452
7453     /* Sometimes path is not null-terminated, so we make a copy. */
7454     realPathp = malloc(nameLength+sizeof(clientchar_t));
7455     memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
7456     realPathp[nameLength/sizeof(clientchar_t)] = 0;
7457
7458     spacep = inp->spacep;
7459     /* smb_StripLastComponent will strip "::$DATA" if present */
7460     smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7461
7462     osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
7463     osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
7464     osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
7465
7466     if (baseFid == 0) {
7467         baseFidp = NULL;
7468         baseDirp = cm_RootSCachep(cm_rootUserp, &req);
7469         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7470         if (code == CM_ERROR_TIDIPC) {
7471             /* Attempt to use a TID allocated for IPC.  The client
7472              * is probably looking for DCE RPC end points which we
7473              * don't support OR it could be looking to make a DFS
7474              * referral request.
7475              */
7476             osi_Log0(smb_logp, "NTCreateX received IPC TID");
7477             is_ipc = TRUE;
7478         }
7479     }
7480
7481     osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
7482
7483     if (lastNamep &&
7484
7485         ((is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)) ||
7486
7487          /* special case magic file name for receiving IOCTL requests
7488           * (since IOCTL calls themselves aren't getting through).
7489           */
7490          cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0)) {
7491
7492         unsigned short file_type = 0;
7493         unsigned short device_state = 0;
7494
7495         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7496
7497         if (is_rpc) {
7498             code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
7499             osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
7500             if (code) {
7501                 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
7502                 smb_ReleaseFID(fidp);
7503                 free(realPathp);
7504                 return code;
7505             }
7506         } else {
7507             smb_SetupIoctlFid(fidp, spacep);
7508             osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
7509         }
7510
7511         /* set inp->fid so that later read calls in same msg can find fid */
7512         inp->fid = fidp->fid;
7513
7514         /* out parms */
7515         parmSlot = 2;
7516         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
7517         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7518         smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
7519         /* times */
7520         memset(&ft, 0, sizeof(ft));
7521         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7522         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7523         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7524         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7525         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
7526         sz.HighPart = 0x7fff; sz.LowPart = 0;
7527         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
7528         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
7529         smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;  /* filetype */
7530         smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;       /* dev state */
7531         smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
7532         smb_SetSMBDataLength(outp, 0);
7533
7534         /* clean up fid reference */
7535         smb_ReleaseFID(fidp);
7536         free(realPathp);
7537         return 0;
7538     }
7539
7540 #ifndef DFS_SUPPORT
7541     if (is_ipc) {
7542         osi_Log0(smb_logp, "NTCreateX rejecting IPC TID");
7543         free(realPathp);
7544         return CM_ERROR_BADFD;
7545     }
7546 #endif
7547
7548     if (!cm_IsValidClientString(realPathp)) {
7549 #ifdef DEBUG
7550         clientchar_t * hexp;
7551
7552         hexp = cm_GetRawCharsAlloc(realPathp, -1);
7553         osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
7554                  osi_LogSaveClientString(smb_logp, hexp));
7555         if (hexp)
7556             free(hexp);
7557 #else
7558         osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
7559 #endif
7560         free(realPathp);
7561         return CM_ERROR_BADNTFILENAME;
7562     }
7563
7564     userp = smb_GetUserFromVCP(vcp, inp);
7565     if (!userp) {
7566         osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
7567         free(realPathp);
7568         return CM_ERROR_INVAL;
7569     }
7570
7571     if (baseFidp != 0) {
7572         baseFidp = smb_FindFID(vcp, baseFid, 0);
7573         if (!baseFidp) {
7574             osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
7575             cm_ReleaseUser(userp);
7576             free(realPathp);
7577             return CM_ERROR_INVAL;
7578         }
7579
7580         if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7581             free(realPathp);
7582             smb_CloseFID(vcp, baseFidp, NULL, 0);
7583             smb_ReleaseFID(baseFidp);
7584             cm_ReleaseUser(userp);
7585             return CM_ERROR_NOSUCHPATH;
7586         }
7587
7588         baseDirp = baseFidp->scp;
7589         tidPathp = NULL;
7590     }
7591
7592     /* compute open mode */
7593     fidflags = 0;
7594     if (desiredAccess & DELETE)
7595         fidflags |= SMB_FID_OPENDELETE;
7596     if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7597         fidflags |= SMB_FID_OPENREAD_LISTDIR;
7598     if (desiredAccess & AFS_ACCESS_WRITE)
7599         fidflags |= SMB_FID_OPENWRITE;
7600     if (createOptions & FILE_DELETE_ON_CLOSE)
7601         fidflags |= SMB_FID_DELONCLOSE;
7602     if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7603         fidflags |= SMB_FID_SEQUENTIAL;
7604     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7605         fidflags |= SMB_FID_RANDOM;
7606     if (createOptions & FILE_OPEN_REPARSE_POINT)
7607         osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7608     if (smb_IsExecutableFileName(lastNamep))
7609         fidflags |= SMB_FID_EXECUTABLE;
7610
7611     /* and the share mode */
7612     if (shareAccess & FILE_SHARE_READ)
7613         fidflags |= SMB_FID_SHARE_READ;
7614     if (shareAccess & FILE_SHARE_WRITE)
7615         fidflags |= SMB_FID_SHARE_WRITE;
7616
7617     osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7618     code = 0;
7619
7620     /* For an exclusive create, we want to do a case sensitive match for the last component. */
7621     if ( createDisp == FILE_CREATE ||
7622          createDisp == FILE_OVERWRITE ||
7623          createDisp == FILE_OVERWRITE_IF) {
7624         code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7625                         userp, tidPathp, &req, &dscp);
7626         if (code == 0) {
7627 #ifdef DFS_SUPPORT
7628             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7629                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7630                                                           spacep->wdata);
7631                 cm_ReleaseSCache(dscp);
7632                 cm_ReleaseUser(userp);
7633                 free(realPathp);
7634                 if (baseFidp)
7635                     smb_ReleaseFID(baseFidp);
7636                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7637                     return CM_ERROR_PATH_NOT_COVERED;
7638                 else
7639                     return CM_ERROR_NOSUCHPATH;
7640             }
7641 #endif /* DFS_SUPPORT */
7642             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7643                              userp, &req, &scp);
7644             if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7645                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7646                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7647                 if (code == 0 && realDirFlag == 1) {
7648                     cm_ReleaseSCache(scp);
7649                     cm_ReleaseSCache(dscp);
7650                     cm_ReleaseUser(userp);
7651                     free(realPathp);
7652                     if (baseFidp)
7653                         smb_ReleaseFID(baseFidp);
7654                     return CM_ERROR_EXISTS;
7655                 }
7656             }
7657             /* we have both scp and dscp */
7658         }
7659     } else {
7660         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7661                         userp, tidPathp, &req, &scp);
7662 #ifdef DFS_SUPPORT
7663         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7664             int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7665             cm_ReleaseSCache(scp);
7666             cm_ReleaseUser(userp);
7667             free(realPathp);
7668             if (baseFidp)
7669                 smb_ReleaseFID(baseFidp);
7670             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7671                 return CM_ERROR_PATH_NOT_COVERED;
7672             else
7673                 return CM_ERROR_NOSUCHPATH;
7674         }
7675 #endif /* DFS_SUPPORT */
7676         /* we might have scp but not dscp */
7677     }
7678
7679     if (code &&
7680         code != CM_ERROR_NOSUCHFILE &&
7681         code != CM_ERROR_NOSUCHPATH &&
7682         code != CM_ERROR_BPLUS_NOMATCH) {
7683         cm_ReleaseUser(userp);
7684         free(realPathp);
7685         if (baseFidp)
7686             smb_ReleaseFID(baseFidp);
7687         return code;
7688     }
7689
7690     if (scp)
7691         foundscp = TRUE;
7692
7693     if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7694         /* look up parent directory */
7695         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7696          * the immediate parent.  We have to work our way up realPathp until we hit something that we
7697          * recognize.
7698          */
7699
7700         /* we might or might not have scp */
7701
7702         if (dscp == NULL) {
7703             do {
7704                 clientchar_t *tp;
7705
7706                 code = cm_NameI(baseDirp, spacep->wdata,
7707                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7708                                 userp, tidPathp, &req, &dscp);
7709
7710 #ifdef DFS_SUPPORT
7711                 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7712                     int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7713                                                               spacep->wdata);
7714                     if (scp)
7715                         cm_ReleaseSCache(scp);
7716                     cm_ReleaseSCache(dscp);
7717                     cm_ReleaseUser(userp);
7718                     free(realPathp);
7719                     if (baseFidp)
7720                         smb_ReleaseFID(baseFidp);
7721                     if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7722                         return CM_ERROR_PATH_NOT_COVERED;
7723                     else
7724                         return CM_ERROR_NOSUCHPATH;
7725                 }
7726 #endif /* DFS_SUPPORT */
7727
7728                 if (code &&
7729                     (code == CM_ERROR_NOSUCHFILE ||
7730                      code == CM_ERROR_NOSUCHPATH ||
7731                      code == CM_ERROR_BPLUS_NOMATCH) &&
7732                     (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7733                     (createDisp == FILE_CREATE) &&
7734                     (realDirFlag == 1)) {
7735                     *tp++ = 0;
7736                     treeCreate = TRUE;
7737                     treeStartp = realPathp + (tp - spacep->wdata);
7738
7739                     if (*tp && !smb_IsLegalFilename(tp)) {
7740                         cm_ReleaseUser(userp);
7741                         if (baseFidp)
7742                             smb_ReleaseFID(baseFidp);
7743                         free(realPathp);
7744                         if (scp)
7745                             cm_ReleaseSCache(scp);
7746                         return CM_ERROR_BADNTFILENAME;
7747                     }
7748                     code = 0;
7749                 }
7750             } while (dscp == NULL && code == 0);
7751         } else
7752             code = 0;
7753
7754         /* we might have scp and we might have dscp */
7755
7756         if (baseFidp)
7757             smb_ReleaseFID(baseFidp);
7758
7759         if (code) {
7760             osi_Log0(smb_logp,"NTCreateX parent not found");
7761             if (scp)
7762                 cm_ReleaseSCache(scp);
7763             if (dscp)
7764                 cm_ReleaseSCache(dscp);
7765             cm_ReleaseUser(userp);
7766             free(realPathp);
7767             return code;
7768         }
7769
7770         if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7771             /* A file exists where we want a directory. */
7772             if (scp)
7773                 cm_ReleaseSCache(scp);
7774             cm_ReleaseSCache(dscp);
7775             cm_ReleaseUser(userp);
7776             free(realPathp);
7777             return CM_ERROR_EXISTS;
7778         }
7779
7780         if (!lastNamep)
7781             lastNamep = realPathp;
7782         else
7783             lastNamep++;
7784
7785         if (!smb_IsLegalFilename(lastNamep)) {
7786             if (scp)
7787                 cm_ReleaseSCache(scp);
7788             if (dscp)
7789                 cm_ReleaseSCache(dscp);
7790             cm_ReleaseUser(userp);
7791             free(realPathp);
7792             return CM_ERROR_BADNTFILENAME;
7793         }
7794
7795         if (!foundscp && !treeCreate) {
7796             if ( createDisp == FILE_CREATE ||
7797                  createDisp == FILE_OVERWRITE ||
7798                  createDisp == FILE_OVERWRITE_IF)
7799             {
7800                 code = cm_Lookup(dscp, lastNamep,
7801                                   CM_FLAG_FOLLOW, userp, &req, &scp);
7802             } else {
7803                 code = cm_Lookup(dscp, lastNamep,
7804                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7805                                  userp, &req, &scp);
7806             }
7807             if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7808                 if (dscp)
7809                     cm_ReleaseSCache(dscp);
7810                 cm_ReleaseUser(userp);
7811                 free(realPathp);
7812                 return code;
7813             }
7814         }
7815         /* we have scp and dscp */
7816     } else {
7817         /* we have scp but not dscp */
7818         if (baseFidp)
7819             smb_ReleaseFID(baseFidp);
7820     }
7821
7822     /* if we get here, if code is 0, the file exists and is represented by
7823      * scp.  Otherwise, we have to create it.  The dir may be represented
7824      * by dscp, or we may have found the file directly.  If code is non-zero,
7825      * scp is NULL.
7826      */
7827     if (code == 0 && !treeCreate) {
7828         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7829         if (code) {
7830             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7831             if (dscp)
7832                 cm_ReleaseSCache(dscp);
7833             if (scp)
7834                 cm_ReleaseSCache(scp);
7835             cm_ReleaseUser(userp);
7836             free(realPathp);
7837             return code;
7838         }
7839         checkDoneRequired = 1;
7840
7841         if (createDisp == FILE_CREATE) {
7842             /* oops, file shouldn't be there */
7843             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7844             if (dscp)
7845                 cm_ReleaseSCache(dscp);
7846             if (scp)
7847                 cm_ReleaseSCache(scp);
7848             cm_ReleaseUser(userp);
7849             free(realPathp);
7850             return CM_ERROR_EXISTS;
7851         }
7852
7853         if ( createDisp == FILE_OVERWRITE ||
7854              createDisp == FILE_OVERWRITE_IF) {
7855
7856             setAttr.mask = CM_ATTRMASK_LENGTH;
7857             setAttr.length.LowPart = 0;
7858             setAttr.length.HighPart = 0;
7859             /* now watch for a symlink */
7860             code = 0;
7861             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7862                 targetScp = 0;
7863                 osi_assertx(dscp != NULL, "null cm_scache_t");
7864                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7865                 if (code == 0) {
7866                     /* we have a more accurate file to use (the
7867                      * target of the symbolic link).  Otherwise,
7868                      * we'll just use the symlink anyway.
7869                      */
7870                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
7871                               scp, targetScp);
7872                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7873                     cm_ReleaseSCache(scp);
7874                     scp = targetScp;
7875                     code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7876                     if (code) {
7877                         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7878                         if (dscp)
7879                             cm_ReleaseSCache(dscp);
7880                         if (scp)
7881                             cm_ReleaseSCache(scp);
7882                         cm_ReleaseUser(userp);
7883                         free(realPathp);
7884                         return code;
7885                     }
7886                 }
7887             }
7888             code = cm_SetAttr(scp, &setAttr, userp, &req);
7889             openAction = 3;     /* truncated existing file */
7890         }
7891         else
7892             openAction = 1;     /* found existing file */
7893
7894     } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7895         /* don't create if not found */
7896         if (dscp)
7897             cm_ReleaseSCache(dscp);
7898         if (scp)
7899             cm_ReleaseSCache(scp);
7900         cm_ReleaseUser(userp);
7901         free(realPathp);
7902         return CM_ERROR_NOSUCHFILE;
7903     } else if (realDirFlag == 0 || realDirFlag == -1) {
7904         osi_assertx(dscp != NULL, "null cm_scache_t");
7905         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7906                   osi_LogSaveClientString(smb_logp, lastNamep));
7907         openAction = 2;         /* created file */
7908         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7909         setAttr.clientModTime = time(NULL);
7910         smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
7911
7912         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7913         if (code == 0) {
7914             created = 1;
7915             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7916                 smb_NotifyChange(FILE_ACTION_ADDED,
7917                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7918                                  dscp, lastNamep, NULL, TRUE);
7919         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7920             /* Not an exclusive create, and someone else tried
7921              * creating it already, then we open it anyway.  We
7922              * don't bother retrying after this, since if this next
7923              * fails, that means that the file was deleted after we
7924              * started this call.
7925              */
7926             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7927                               userp, &req, &scp);
7928             if (code == 0) {
7929                 if (createDisp == FILE_OVERWRITE_IF) {
7930                     setAttr.mask = CM_ATTRMASK_LENGTH;
7931                     setAttr.length.LowPart = 0;
7932                     setAttr.length.HighPart = 0;
7933
7934                     /* now watch for a symlink */
7935                     code = 0;
7936                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7937                         targetScp = 0;
7938                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7939                         if (code == 0) {
7940                             /* we have a more accurate file to use (the
7941                              * target of the symbolic link).  Otherwise,
7942                              * we'll just use the symlink anyway.
7943                              */
7944                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
7945                                       scp, targetScp);
7946                             cm_ReleaseSCache(scp);
7947                             scp = targetScp;
7948                         }
7949                     }
7950                     code = cm_SetAttr(scp, &setAttr, userp, &req);
7951                 }
7952             }   /* lookup succeeded */
7953         }
7954     } else {
7955         clientchar_t *tp, *pp;
7956         clientchar_t *cp; /* This component */
7957         int clen = 0; /* length of component */
7958         cm_scache_t *tscp1, *tscp2;
7959         int isLast = 0;
7960
7961         /* create directory */
7962         if ( !treeCreate )
7963             treeStartp = lastNamep;
7964         osi_assertx(dscp != NULL, "null cm_scache_t");
7965         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7966                   osi_LogSaveClientString(smb_logp, treeStartp));
7967         openAction = 2;         /* created directory */
7968
7969         /* if the request is to create the root directory
7970          * it will appear as a directory name of the nul-string
7971          * and a code of CM_ERROR_NOSUCHFILE
7972          */
7973         if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7974             code = CM_ERROR_EXISTS;
7975
7976         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7977         setAttr.clientModTime = time(NULL);
7978         smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
7979
7980         pp = treeStartp;
7981         cp = spacep->wdata;
7982         tscp1 = dscp;
7983         cm_HoldSCache(tscp1);
7984         tscp2 = NULL;
7985
7986         while (pp && *pp) {
7987             tp = cm_ClientStrChr(pp, '\\');
7988             if (!tp) {
7989                 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7990                 clen = (int)cm_ClientStrLen(cp);
7991                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
7992             } else {
7993                 clen = (int)(tp - pp);
7994                 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7995                                  pp, clen);
7996                 *(cp + clen) = 0;
7997                 tp++;
7998             }
7999             pp = tp;
8000
8001             if (clen == 0)
8002                 continue; /* the supplied path can't have consecutive slashes either , but */
8003
8004             /* cp is the next component to be created. */
8005             code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
8006             if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
8007                 smb_NotifyChange(FILE_ACTION_ADDED,
8008                                  FILE_NOTIFY_CHANGE_DIR_NAME,
8009                                  tscp1, cp, NULL, TRUE);
8010             if (code == 0 ||
8011                 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8012                 /* Not an exclusive create, and someone else tried
8013                  * creating it already, then we open it anyway.  We
8014                  * don't bother retrying after this, since if this next
8015                  * fails, that means that the file was deleted after we
8016                  * started this call.
8017                  */
8018                 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
8019                                  userp, &req, &tscp2);
8020             }
8021             if (code)
8022                 break;
8023
8024             if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
8025                 cm_ReleaseSCache(tscp1);
8026                 tscp1 = tscp2; /* Newly created directory will be next parent */
8027                 /* the hold is transfered to tscp1 from tscp2 */
8028             }
8029         }
8030
8031         if (dscp)
8032             cm_ReleaseSCache(dscp);
8033         dscp = tscp1;
8034         if (scp)
8035             cm_ReleaseSCache(scp);
8036         scp = tscp2;
8037         /*
8038          * if we get here and code == 0, then scp is the last directory created, and dscp is the
8039          * parent of scp.
8040          */
8041     }
8042
8043     if (code) {
8044         /* something went wrong creating or truncating the file */
8045         if (checkDoneRequired)
8046             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8047         if (scp)
8048             cm_ReleaseSCache(scp);
8049         if (dscp)
8050             cm_ReleaseSCache(dscp);
8051         cm_ReleaseUser(userp);
8052         free(realPathp);
8053         return code;
8054     }
8055
8056     /* make sure we have file vs. dir right (only applies for single component case) */
8057     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8058         /* now watch for a symlink */
8059         code = 0;
8060         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8061             cm_scache_t * targetScp = 0;
8062             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8063             if (code == 0) {
8064                 /* we have a more accurate file to use (the
8065                 * target of the symbolic link).  Otherwise,
8066                 * we'll just use the symlink anyway.
8067                 */
8068                 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
8069                 if (checkDoneRequired) {
8070                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8071                     checkDoneRequired = 0;
8072                 }
8073                 cm_ReleaseSCache(scp);
8074                 scp = targetScp;
8075             }
8076         }
8077
8078         if (scp->fileType != CM_SCACHETYPE_FILE) {
8079             if (checkDoneRequired)
8080                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8081             if (dscp)
8082                 cm_ReleaseSCache(dscp);
8083             cm_ReleaseSCache(scp);
8084             cm_ReleaseUser(userp);
8085             free(realPathp);
8086             return CM_ERROR_ISDIR;
8087         }
8088     }
8089
8090     /* (only applies to single component case) */
8091     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8092         if (checkDoneRequired)
8093             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8094         cm_ReleaseSCache(scp);
8095         if (dscp)
8096             cm_ReleaseSCache(dscp);
8097         cm_ReleaseUser(userp);
8098         free(realPathp);
8099         return CM_ERROR_NOTDIR;
8100     }
8101
8102     /* open the file itself */
8103     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8104     osi_assertx(fidp, "null smb_fid_t");
8105
8106     /* save a reference to the user */
8107     cm_HoldUser(userp);
8108     fidp->userp = userp;
8109
8110     /* If we are restricting sharing, we should do so with a suitable
8111        share lock. */
8112     if (scp->fileType == CM_SCACHETYPE_FILE &&
8113         !(fidflags & SMB_FID_SHARE_WRITE)) {
8114         cm_key_t key;
8115         LARGE_INTEGER LOffset, LLength;
8116         int sLockType;
8117
8118         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8119         LOffset.LowPart = SMB_FID_QLOCK_LOW;
8120         LLength.HighPart = 0;
8121         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8122
8123         /* If we are not opening the file for writing, then we don't
8124            try to get an exclusive lock.  No one else should be able to
8125            get an exclusive lock on the file anyway, although someone
8126            else can get a shared lock. */
8127         if ((fidflags & SMB_FID_SHARE_READ) ||
8128             !(fidflags & SMB_FID_OPENWRITE)) {
8129             sLockType = LOCKING_ANDX_SHARED_LOCK;
8130         } else {
8131             sLockType = 0;
8132         }
8133
8134         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8135
8136         lock_ObtainWrite(&scp->rw);
8137         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8138         lock_ReleaseWrite(&scp->rw);
8139
8140         if (code) {
8141             if (checkDoneRequired)
8142                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8143             cm_ReleaseSCache(scp);
8144             if (dscp)
8145                 cm_ReleaseSCache(dscp);
8146             cm_ReleaseUser(userp);
8147             /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
8148             smb_CloseFID(vcp, fidp, NULL, 0);
8149             smb_ReleaseFID(fidp);
8150             free(realPathp);
8151             return CM_ERROR_SHARING_VIOLATION;
8152         }
8153     }
8154
8155     /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
8156     if (checkDoneRequired) {
8157         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8158         checkDoneRequired = 0;
8159     }
8160
8161     lock_ObtainMutex(&fidp->mx);
8162     /* save a pointer to the vnode */
8163     fidp->scp = scp;    /* Hold transfered to fidp->scp and no longer needed */
8164     lock_ObtainWrite(&scp->rw);
8165     scp->flags |= CM_SCACHEFLAG_SMB_FID;
8166     lock_ReleaseWrite(&scp->rw);
8167     osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
8168
8169     fidp->flags = fidflags;
8170
8171     /* remember if the file was newly created */
8172     if (created)
8173         fidp->flags |= SMB_FID_CREATED;
8174
8175     /* save parent dir and pathname for delete or change notification */
8176     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8177         osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
8178         fidp->flags |= SMB_FID_NTOPEN;
8179         fidp->NTopen_dscp = dscp;
8180         dscp = NULL;
8181         fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8182     }
8183     fidp->NTopen_wholepathp = realPathp;
8184     lock_ReleaseMutex(&fidp->mx);
8185
8186     /* we don't need this any longer */
8187     if (dscp) {
8188         cm_ReleaseSCache(dscp);
8189         dscp = NULL;
8190     }
8191
8192     cm_Open(scp, 0, userp);
8193
8194     /* set inp->fid so that later read calls in same msg can find fid */
8195     inp->fid = fidp->fid;
8196
8197     lock_ObtainRead(&scp->rw);
8198
8199     /*
8200      * Always send the standard response.  Sending the extended
8201      * response results in the Explorer Shell being unable to
8202      * access directories at random times.
8203      */
8204     if (1 /*!extendedRespRequired */) {
8205         /* out parms */
8206         parmSlot = 2;
8207         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
8208         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8209         smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8210         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8211         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8212         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8213         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8214         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8215         smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8216         parmSlot += 2;
8217         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8218         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8219         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
8220         smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8221         parmSlot++;     /* dev state */
8222         smb_SetSMBParmByte(outp, parmSlot,
8223                             (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8224                               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8225                               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8226         smb_SetSMBDataLength(outp, 0);
8227     } else {
8228         /* out parms */
8229         parmSlot = 2;
8230         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
8231         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8232         smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8233         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8234         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8235         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8236         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8237         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8238         smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8239         parmSlot += 2;
8240         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8241         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8242         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
8243         smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8244         parmSlot++;     /* dev state */
8245         smb_SetSMBParmByte(outp, parmSlot,
8246                             (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8247                               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8248                               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8249         /* Setting the GUID results in a failure with cygwin */
8250         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8251         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8252         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8253         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8254         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8255         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8256         /* Maxmimal access rights */
8257         smb_SetSMBParmLong(outp, parmSlot, 0x001f01ff); parmSlot += 2;
8258         /* Guest access rights */
8259         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8260         smb_SetSMBDataLength(outp, 0);
8261     }
8262
8263     if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8264         LargeIntegerGreaterThanZero(scp->length) &&
8265         !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8266         prefetch = 1;
8267     }
8268     lock_ReleaseRead(&scp->rw);
8269
8270     if (prefetch)
8271         cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8272                            scp->length.LowPart, scp->length.HighPart,
8273                            userp);
8274
8275
8276     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
8277               osi_LogSaveClientString(smb_logp, realPathp));
8278
8279     cm_ReleaseUser(userp);
8280     smb_ReleaseFID(fidp);
8281
8282     /* Can't free realPathp if we get here since
8283        fidp->NTopen_wholepathp is pointing there */
8284
8285     /* leave scp held since we put it in fidp->scp */
8286     return 0;
8287 }
8288
8289 /*
8290  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
8291  * Instead, ultimately, would like to use a subroutine for common code.
8292  */
8293
8294 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
8295 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8296 {
8297     clientchar_t *pathp, *realPathp;
8298     long code = 0;
8299     cm_space_t *spacep;
8300     cm_user_t *userp;
8301     cm_scache_t *dscp;          /* parent dir */
8302     cm_scache_t *scp;           /* file to create or open */
8303     cm_scache_t *targetScp;     /* if scp is a symlink */
8304     cm_attr_t setAttr;
8305     clientchar_t *lastNamep;
8306     unsigned long nameLength;
8307     unsigned int flags;
8308     unsigned int requestOpLock;
8309     unsigned int requestBatchOpLock;
8310     unsigned int mustBeDir;
8311     unsigned int extendedRespRequired;
8312     int realDirFlag;
8313     unsigned int desiredAccess;
8314     unsigned int allocSize;
8315     unsigned int shareAccess;
8316     unsigned int extAttributes;
8317     unsigned int createDisp;
8318     unsigned int sdLen;
8319     unsigned int eaLen;
8320     unsigned int impLevel;
8321     unsigned int secFlags;
8322     unsigned int createOptions;
8323     unsigned short baseFid;
8324     smb_fid_t *baseFidp;
8325     smb_fid_t *fidp;
8326     cm_scache_t *baseDirp;
8327     unsigned short openAction;
8328     int parmSlot;
8329     long fidflags;
8330     FILETIME ft;
8331     clientchar_t *tidPathp;
8332     BOOL foundscp;
8333     int parmOffset, dataOffset;
8334     char *parmp;
8335     ULONG *lparmp;
8336     char *outData;
8337     cm_req_t req;
8338     int created = 0;
8339     int prefetch = 0;
8340     cm_lock_data_t *ldp = NULL;
8341     int checkDoneRequired = 0;
8342
8343     smb_InitReq(&req);
8344
8345     foundscp = FALSE;
8346     scp = NULL;
8347
8348     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8349         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8350     parmp = inp->data + parmOffset;
8351     lparmp = (ULONG *) parmp;
8352
8353     flags = lparmp[0];
8354     requestOpLock = flags & REQUEST_OPLOCK;
8355     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
8356     mustBeDir = flags & OPEN_DIRECTORY;
8357     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
8358
8359     /*
8360      * Why all of a sudden 32-bit FID?
8361      * We will reject all bits higher than 16.
8362      */
8363     if (lparmp[1] & 0xFFFF0000)
8364         return CM_ERROR_INVAL;
8365     baseFid = (unsigned short)lparmp[1];
8366     desiredAccess = lparmp[2];
8367     allocSize = lparmp[3];
8368     extAttributes = lparmp[5];
8369     shareAccess = lparmp[6];
8370     createDisp = lparmp[7];
8371     createOptions = lparmp[8];
8372     sdLen = lparmp[9];
8373     eaLen = lparmp[10];
8374     nameLength = lparmp[11];    /* spec says chars but appears to be bytes */
8375     impLevel = lparmp[12];
8376     secFlags = lparmp[13];
8377
8378     /* mustBeDir is never set; createOptions directory bit seems to be
8379      * more important
8380      */
8381     if (createOptions & FILE_DIRECTORY_FILE)
8382         realDirFlag = 1;
8383     else if (createOptions & FILE_NON_DIRECTORY_FILE)
8384         realDirFlag = 0;
8385     else
8386         realDirFlag = -1;
8387
8388     pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
8389                                nameLength, NULL, SMB_STRF_ANSIPATH);
8390     /* Sometimes path is not nul-terminated, so we make a copy. */
8391     realPathp = malloc(nameLength+sizeof(clientchar_t));
8392     memcpy(realPathp, pathp, nameLength);
8393     realPathp[nameLength/sizeof(clientchar_t)] = 0;
8394     spacep = cm_GetSpace();
8395     /* smb_StripLastComponent will strip "::$DATA" if present */
8396     smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
8397
8398     osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
8399     osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
8400     osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
8401     osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
8402
8403     if ( realDirFlag == 1 &&
8404          ( createDisp == FILE_SUPERSEDE ||
8405            createDisp == FILE_OVERWRITE ||
8406            createDisp == FILE_OVERWRITE_IF))
8407     {
8408         osi_Log0(smb_logp, "NTTranCreate rejecting invalid readDirFlag and createDisp combination");
8409         cm_FreeSpace(spacep);
8410         free(realPathp);
8411         return CM_ERROR_INVAL;
8412     }
8413
8414     /*
8415      * Nothing here to handle SMB_IOCTL_FILENAME.
8416      * Will add it if necessary.
8417      */
8418
8419     if (!cm_IsValidClientString(realPathp)) {
8420 #ifdef DEBUG
8421         clientchar_t * hexp;
8422
8423         hexp = cm_GetRawCharsAlloc(realPathp, -1);
8424         osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
8425                  osi_LogSaveClientString(smb_logp, hexp));
8426         if (hexp)
8427         free(hexp);
8428 #else
8429         osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
8430 #endif
8431         cm_FreeSpace(spacep);
8432         free(realPathp);
8433         return CM_ERROR_BADNTFILENAME;
8434     }
8435
8436     userp = smb_GetUserFromVCP(vcp, inp);
8437     if (!userp) {
8438         osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
8439         cm_FreeSpace(spacep);
8440         free(realPathp);
8441         return CM_ERROR_INVAL;
8442     }
8443
8444     if (baseFid == 0) {
8445         baseFidp = NULL;
8446         baseDirp = cm_RootSCachep(cm_rootUserp, &req);
8447         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8448         if (code == CM_ERROR_TIDIPC) {
8449             /* Attempt to use a TID allocated for IPC.  The client
8450              * is probably looking for DCE RPC end points which we
8451              * don't support OR it could be looking to make a DFS
8452              * referral request.
8453              */
8454             osi_Log0(smb_logp, "NTTranCreate received IPC TID");
8455 #ifndef DFS_SUPPORT
8456             cm_FreeSpace(spacep);
8457             free(realPathp);
8458             cm_ReleaseUser(userp);
8459             return CM_ERROR_NOSUCHPATH;
8460 #endif
8461         }
8462     } else {
8463         baseFidp = smb_FindFID(vcp, baseFid, 0);
8464         if (!baseFidp) {
8465             osi_Log2(smb_logp, "NTTranCreate Unknown SMB Fid vcp 0x%p fid %d",
8466                       vcp, baseFid);
8467             cm_FreeSpace(spacep);
8468             free(realPathp);
8469             cm_ReleaseUser(userp);
8470             return CM_ERROR_BADFD;
8471         }
8472
8473         if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8474             cm_FreeSpace(spacep);
8475             free(realPathp);
8476             cm_ReleaseUser(userp);
8477             smb_CloseFID(vcp, baseFidp, NULL, 0);
8478             smb_ReleaseFID(baseFidp);
8479             return CM_ERROR_NOSUCHPATH;
8480         }
8481
8482         baseDirp = baseFidp->scp;
8483         tidPathp = NULL;
8484     }
8485
8486     /* compute open mode */
8487     fidflags = 0;
8488     if (desiredAccess & DELETE)
8489         fidflags |= SMB_FID_OPENDELETE;
8490     if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
8491         fidflags |= SMB_FID_OPENREAD_LISTDIR;
8492     if (desiredAccess & AFS_ACCESS_WRITE)
8493         fidflags |= SMB_FID_OPENWRITE;
8494     if (createOptions & FILE_DELETE_ON_CLOSE)
8495         fidflags |= SMB_FID_DELONCLOSE;
8496     if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
8497         fidflags |= SMB_FID_SEQUENTIAL;
8498     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
8499         fidflags |= SMB_FID_RANDOM;
8500     if (createOptions & FILE_OPEN_REPARSE_POINT)
8501         osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
8502     if (smb_IsExecutableFileName(lastNamep))
8503         fidflags |= SMB_FID_EXECUTABLE;
8504
8505     /* And the share mode */
8506     if (shareAccess & FILE_SHARE_READ)
8507         fidflags |= SMB_FID_SHARE_READ;
8508     if (shareAccess & FILE_SHARE_WRITE)
8509         fidflags |= SMB_FID_SHARE_WRITE;
8510
8511     dscp = NULL;
8512     code = 0;
8513
8514     code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8515                     userp, tidPathp, &req, &dscp);
8516     if (code == 0) {
8517 #ifdef DFS_SUPPORT
8518         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8519             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8520             cm_ReleaseSCache(dscp);
8521             cm_ReleaseUser(userp);
8522             cm_FreeSpace(spacep);
8523             free(realPathp);
8524             if (baseFidp)
8525                 smb_ReleaseFID(baseFidp);
8526             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8527                 return CM_ERROR_PATH_NOT_COVERED;
8528             else
8529                 return CM_ERROR_NOSUCHPATH;
8530         }
8531 #endif /* DFS_SUPPORT */
8532         code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
8533                          userp, &req, &scp);
8534         if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
8535
8536             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
8537                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
8538             if (code == 0 && realDirFlag == 1 &&
8539                 (createDisp == FILE_OPEN ||
8540                  createDisp == FILE_OVERWRITE ||
8541                  createDisp == FILE_OVERWRITE_IF)) {
8542                 cm_ReleaseSCache(scp);
8543                 cm_ReleaseSCache(dscp);
8544                 cm_ReleaseUser(userp);
8545                 cm_FreeSpace(spacep);
8546                 free(realPathp);
8547                 if (baseFidp)
8548                     smb_ReleaseFID(baseFidp);
8549                 return CM_ERROR_EXISTS;
8550             }
8551         }
8552     } else {
8553         cm_ReleaseUser(userp);
8554         if (baseFidp)
8555             smb_ReleaseFID(baseFidp);
8556         cm_FreeSpace(spacep);
8557         free(realPathp);
8558         return CM_ERROR_NOSUCHPATH;
8559     }
8560
8561     if (code == 0)
8562         foundscp = TRUE;
8563
8564     if (code == CM_ERROR_NOSUCHFILE ||
8565         code == CM_ERROR_NOSUCHPATH ||
8566         code == CM_ERROR_BPLUS_NOMATCH ||
8567         (code == 0 && (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)))) {
8568         code = 0;
8569
8570         cm_FreeSpace(spacep);
8571
8572         if (baseFidp)
8573             smb_ReleaseFID(baseFidp);
8574
8575         if (code) {
8576             cm_ReleaseSCache(dscp);
8577             cm_ReleaseUser(userp);
8578             free(realPathp);
8579             return code;
8580         }
8581
8582         if (!lastNamep)
8583             lastNamep = realPathp;
8584         else
8585             lastNamep++;
8586
8587         if (!smb_IsLegalFilename(lastNamep)) {
8588             cm_ReleaseSCache(dscp);
8589             cm_ReleaseUser(userp);
8590             free(realPathp);
8591             return CM_ERROR_BADNTFILENAME;
8592         }
8593
8594         if (!foundscp) {
8595             if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF || createDisp == FILE_OPEN_IF) {
8596                 code = cm_Lookup(dscp, lastNamep,
8597                                   CM_FLAG_FOLLOW, userp, &req, &scp);
8598             } else {
8599                 code = cm_Lookup(dscp, lastNamep,
8600                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8601                                  userp, &req, &scp);
8602             }
8603             if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8604                 cm_ReleaseSCache(dscp);
8605                 cm_ReleaseUser(userp);
8606                 free(realPathp);
8607                 return code;
8608             }
8609         }
8610     } else {
8611         if (baseFidp)
8612             smb_ReleaseFID(baseFidp);
8613         cm_FreeSpace(spacep);
8614     }
8615
8616     /* if we get here, if code is 0, the file exists and is represented by
8617      * scp.  Otherwise, we have to create it.  The dir may be represented
8618      * by dscp, or we may have found the file directly.  If code is non-zero,
8619      * scp is NULL.
8620      */
8621     if (code == 0) {
8622         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8623         if (code) {
8624             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8625             cm_ReleaseSCache(dscp);
8626             cm_ReleaseSCache(scp);
8627             cm_ReleaseUser(userp);
8628             free(realPathp);
8629             return code;
8630         }
8631         checkDoneRequired = 1;
8632
8633         if (createDisp == FILE_CREATE) {
8634             /* oops, file shouldn't be there */
8635             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8636             cm_ReleaseSCache(dscp);
8637             cm_ReleaseSCache(scp);
8638             cm_ReleaseUser(userp);
8639             free(realPathp);
8640             return CM_ERROR_EXISTS;
8641         }
8642
8643         if (createDisp == FILE_OVERWRITE ||
8644             createDisp == FILE_OVERWRITE_IF) {
8645             setAttr.mask = CM_ATTRMASK_LENGTH;
8646             setAttr.length.LowPart = 0;
8647             setAttr.length.HighPart = 0;
8648
8649             /* now watch for a symlink */
8650             code = 0;
8651             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8652                 targetScp = 0;
8653                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8654                 if (code == 0) {
8655                     /* we have a more accurate file to use (the
8656                     * target of the symbolic link).  Otherwise,
8657                     * we'll just use the symlink anyway.
8658                     */
8659                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
8660                               scp, targetScp);
8661                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8662                     cm_ReleaseSCache(scp);
8663                     scp = targetScp;
8664                     code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8665                     if (code) {
8666                         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8667                         cm_ReleaseSCache(dscp);
8668                         if (scp)
8669                             cm_ReleaseSCache(scp);
8670                         cm_ReleaseUser(userp);
8671                         free(realPathp);
8672                         return code;
8673                     }
8674                 }
8675             }
8676             code = cm_SetAttr(scp, &setAttr, userp, &req);
8677             openAction = 3;     /* truncated existing file */
8678         }
8679         else openAction = 1;    /* found existing file */
8680     }
8681     else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8682         /* don't create if not found */
8683         cm_ReleaseSCache(dscp);
8684         cm_ReleaseUser(userp);
8685         free(realPathp);
8686         return CM_ERROR_NOSUCHFILE;
8687     }
8688     else if (realDirFlag == 0 || realDirFlag == -1) {
8689         /* createDisp: FILE_SUPERSEDE, FILE_CREATE, FILE_OPEN_IF, FILE_OVERWRITE_IF */
8690         osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8691                   osi_LogSaveClientString(smb_logp, lastNamep));
8692         openAction = 2;         /* created file */
8693         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8694         setAttr.clientModTime = time(NULL);
8695         smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
8696
8697         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8698                           &req);
8699         if (code == 0) {
8700             created = 1;
8701             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8702                 smb_NotifyChange(FILE_ACTION_ADDED,
8703                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8704                                  dscp, lastNamep, NULL, TRUE);
8705         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8706             /* Not an exclusive create, and someone else tried
8707              * creating it already, then we open it anyway.  We
8708              * don't bother retrying after this, since if this next
8709              * fails, that means that the file was deleted after we
8710              * started this call.
8711              */
8712             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8713                               userp, &req, &scp);
8714             if (code == 0) {
8715                 if (createDisp == FILE_OVERWRITE_IF) {
8716                     setAttr.mask = CM_ATTRMASK_LENGTH;
8717                     setAttr.length.LowPart = 0;
8718                     setAttr.length.HighPart = 0;
8719
8720                     /* now watch for a symlink */
8721                     code = 0;
8722                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8723                         targetScp = 0;
8724                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8725                         if (code == 0) {
8726                             /* we have a more accurate file to use (the
8727                             * target of the symbolic link).  Otherwise,
8728                             * we'll just use the symlink anyway.
8729                             */
8730                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
8731                                       scp, targetScp);
8732                             cm_ReleaseSCache(scp);
8733                             scp = targetScp;
8734                         }
8735                     }
8736                     code = cm_SetAttr(scp, &setAttr, userp, &req);
8737                 }
8738             }   /* lookup succeeded */
8739         }
8740     } else {
8741         /* create directory; createDisp: FILE_CREATE, FILE_OPEN_IF */
8742         osi_Log1(smb_logp,
8743                   "smb_ReceiveNTTranCreate creating directory %S",
8744                   osi_LogSaveClientString(smb_logp, lastNamep));
8745         openAction = 2;         /* created directory */
8746         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8747         setAttr.clientModTime = time(NULL);
8748         smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
8749
8750         code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8751         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8752             smb_NotifyChange(FILE_ACTION_ADDED,
8753                               FILE_NOTIFY_CHANGE_DIR_NAME,
8754                               dscp, lastNamep, NULL, TRUE);
8755         if (code == 0 ||
8756             (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8757             /* Not an exclusive create, and someone else tried
8758              * creating it already, then we open it anyway.  We
8759              * don't bother retrying after this, since if this next
8760              * fails, that means that the file was deleted after we
8761              * started this call.
8762              */
8763             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8764                               userp, &req, &scp);
8765         }
8766     }
8767
8768     if (code) {
8769         /* something went wrong creating or truncating the file */
8770         if (checkDoneRequired)
8771             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8772         if (scp)
8773             cm_ReleaseSCache(scp);
8774         cm_ReleaseUser(userp);
8775         free(realPathp);
8776         return code;
8777     }
8778
8779     /* make sure we have file vs. dir right */
8780     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8781         /* now watch for a symlink */
8782         code = 0;
8783         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8784             targetScp = 0;
8785             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8786             if (code == 0) {
8787                 /* we have a more accurate file to use (the
8788                 * target of the symbolic link).  Otherwise,
8789                 * we'll just use the symlink anyway.
8790                 */
8791                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8792                           scp, targetScp);
8793                 if (checkDoneRequired) {
8794                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8795                     checkDoneRequired = 0;
8796                 }
8797                 cm_ReleaseSCache(scp);
8798                 scp = targetScp;
8799             }
8800         }
8801
8802         if (scp->fileType != CM_SCACHETYPE_FILE) {
8803             if (checkDoneRequired)
8804                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8805             cm_ReleaseSCache(scp);
8806             cm_ReleaseUser(userp);
8807             free(realPathp);
8808             return CM_ERROR_ISDIR;
8809         }
8810     }
8811
8812     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8813         if (checkDoneRequired)
8814             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8815         cm_ReleaseSCache(scp);
8816         cm_ReleaseUser(userp);
8817         free(realPathp);
8818         return CM_ERROR_NOTDIR;
8819     }
8820
8821     /* open the file itself */
8822     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8823     osi_assertx(fidp, "null smb_fid_t");
8824
8825     /* save a reference to the user */
8826     cm_HoldUser(userp);
8827     fidp->userp = userp;
8828
8829     /* If we are restricting sharing, we should do so with a suitable
8830        share lock. */
8831     if (scp->fileType == CM_SCACHETYPE_FILE &&
8832         !(fidflags & SMB_FID_SHARE_WRITE)) {
8833         cm_key_t key;
8834         LARGE_INTEGER LOffset, LLength;
8835         int sLockType;
8836
8837         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8838         LOffset.LowPart = SMB_FID_QLOCK_LOW;
8839         LLength.HighPart = 0;
8840         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8841
8842         /* Similar to what we do in handling NTCreateX.  We get a
8843            shared lock if we are only opening the file for reading. */
8844         if ((fidflags & SMB_FID_SHARE_READ) ||
8845             !(fidflags & SMB_FID_OPENWRITE)) {
8846             sLockType = LOCKING_ANDX_SHARED_LOCK;
8847         } else {
8848             sLockType = 0;
8849         }
8850
8851         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8852
8853         lock_ObtainWrite(&scp->rw);
8854         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8855         lock_ReleaseWrite(&scp->rw);
8856
8857         if (code) {
8858             if (checkDoneRequired)
8859                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8860             cm_ReleaseSCache(scp);
8861             cm_ReleaseUser(userp);
8862             /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
8863             smb_CloseFID(vcp, fidp, NULL, 0);
8864             smb_ReleaseFID(fidp);
8865             free(realPathp);
8866             return CM_ERROR_SHARING_VIOLATION;
8867         }
8868     }
8869
8870     /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8871     if (checkDoneRequired) {
8872         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8873         checkDoneRequired = 0;
8874     }
8875
8876     lock_ObtainMutex(&fidp->mx);
8877     /* save a pointer to the vnode */
8878     fidp->scp = scp;
8879     lock_ObtainWrite(&scp->rw);
8880     scp->flags |= CM_SCACHEFLAG_SMB_FID;
8881     lock_ReleaseWrite(&scp->rw);
8882     osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8883
8884     fidp->flags = fidflags;
8885
8886     /* remember if the file was newly created */
8887     if (created)
8888         fidp->flags |= SMB_FID_CREATED;
8889
8890     /* save parent dir and pathname for deletion or change notification */
8891     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8892         fidp->flags |= SMB_FID_NTOPEN;
8893         fidp->NTopen_dscp = dscp;
8894         osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8895         dscp = NULL;
8896         fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8897     }
8898     fidp->NTopen_wholepathp = realPathp;
8899     lock_ReleaseMutex(&fidp->mx);
8900
8901     /* we don't need this any longer */
8902     if (dscp)
8903         cm_ReleaseSCache(dscp);
8904
8905     cm_Open(scp, 0, userp);
8906
8907     /* set inp->fid so that later read calls in same msg can find fid */
8908     inp->fid = fidp->fid;
8909
8910     /* check whether we are required to send an extended response */
8911     if (!extendedRespRequired) {
8912         /* out parms */
8913         parmOffset = 8*4 + 39;
8914         parmOffset += 1;        /* pad to 4 */
8915         dataOffset = parmOffset + 70;
8916
8917         parmSlot = 1;
8918         outp->oddByte = 1;
8919         /* Total Parameter Count */
8920         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8921         /* Total Data Count */
8922         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8923         /* Parameter Count */
8924         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8925         /* Parameter Offset */
8926         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8927         /* Parameter Displacement */
8928         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8929         /* Data Count */
8930         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8931         /* Data Offset */
8932         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8933         /* Data Displacement */
8934         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8935         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
8936         smb_SetSMBDataLength(outp, 70);
8937
8938         lock_ObtainRead(&scp->rw);
8939         outData = smb_GetSMBData(outp, NULL);
8940         outData++;                      /* round to get to parmOffset */
8941         *outData = 0; outData++;        /* oplock */
8942         *outData = 0; outData++;        /* reserved */
8943         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8944         *((ULONG *)outData) = openAction; outData += 4;
8945         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
8946         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8947         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
8948         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
8949         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
8950         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
8951         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8952         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8953         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8954         *((USHORT *)outData) = 0; outData += 2; /* filetype */
8955         *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
8956         outData += 2;   /* dev state */
8957         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8958                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8959                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8960         outData += 2;   /* is a dir? */
8961     } else {
8962         /* out parms */
8963         parmOffset = 8*4 + 39;
8964         parmOffset += 1;        /* pad to 4 */
8965         dataOffset = parmOffset + 104;
8966
8967         parmSlot = 1;
8968         outp->oddByte = 1;
8969         /* Total Parameter Count */
8970         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8971         /* Total Data Count */
8972         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8973         /* Parameter Count */
8974         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8975         /* Parameter Offset */
8976         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8977         /* Parameter Displacement */
8978         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8979         /* Data Count */
8980         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8981         /* Data Offset */
8982         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8983         /* Data Displacement */
8984         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8985         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
8986         smb_SetSMBDataLength(outp, 105);
8987
8988         lock_ObtainRead(&scp->rw);
8989         outData = smb_GetSMBData(outp, NULL);
8990         outData++;                      /* round to get to parmOffset */
8991         *outData = 0; outData++;        /* oplock */
8992         *outData = 1; outData++;        /* response type */
8993         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8994         *((ULONG *)outData) = openAction; outData += 4;
8995         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
8996         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8997         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
8998         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
8999         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
9000         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
9001         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
9002         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
9003         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
9004         *((USHORT *)outData) = 0; outData += 2; /* filetype */
9005         *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
9006         outData += 2;   /* dev state */
9007         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
9008                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
9009                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
9010         outData += 1;   /* is a dir? */
9011         /* Setting the GUID results in failures with cygwin */
9012         memset(outData,0,24); outData += 24; /* GUID */
9013         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
9014         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
9015     }
9016
9017     if ((fidp->flags & SMB_FID_EXECUTABLE) &&
9018          LargeIntegerGreaterThanZero(scp->length) &&
9019          !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
9020         prefetch = 1;
9021     }
9022     lock_ReleaseRead(&scp->rw);
9023
9024     if (prefetch)
9025         cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
9026                            scp->length.LowPart, scp->length.HighPart,
9027                            userp);
9028
9029     osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
9030
9031     cm_ReleaseUser(userp);
9032     smb_ReleaseFID(fidp);
9033
9034     /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
9035     /* leave scp held since we put it in fidp->scp */
9036     return 0;
9037 }
9038
9039 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
9040 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
9041         smb_packet_t *outp)
9042 {
9043     smb_packet_t *savedPacketp;
9044     ULONG filter;
9045     USHORT fid, watchtree;
9046     smb_fid_t *fidp;
9047     cm_scache_t *scp;
9048
9049     filter = smb_GetSMBParm(inp, 19) |
9050              (smb_GetSMBParm(inp, 20) << 16);
9051     fid = smb_GetSMBParm(inp, 21);
9052     watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
9053
9054     fidp = smb_FindFID(vcp, fid, 0);
9055     if (!fidp) {
9056         osi_Log2(smb_logp, "NotifyChange Unknown SMB Fid vcp 0x%p fid %d",
9057                  vcp, fid);
9058         return CM_ERROR_BADFD;
9059     }
9060
9061     lock_ObtainMutex(&fidp->mx);
9062     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
9063         lock_ReleaseMutex(&fidp->mx);
9064         smb_CloseFID(vcp, fidp, NULL, 0);
9065         smb_ReleaseFID(fidp);
9066         return CM_ERROR_NOSUCHFILE;
9067     }
9068     scp = fidp->scp;
9069     cm_HoldSCache(scp);
9070     lock_ReleaseMutex(&fidp->mx);
9071
9072     /* Create a copy of the Directory Watch Packet to use when sending the
9073      * notification if in the future a matching change is detected.
9074      */
9075     savedPacketp = smb_CopyPacket(inp);
9076     if (vcp != savedPacketp->vcp) {
9077         smb_HoldVC(vcp);
9078         if (savedPacketp->vcp)
9079             smb_ReleaseVC(savedPacketp->vcp);
9080         savedPacketp->vcp = vcp;
9081     }
9082
9083     /* Add the watch to the list of events to send notifications for */
9084     lock_ObtainMutex(&smb_Dir_Watch_Lock);
9085     savedPacketp->nextp = smb_Directory_Watches;
9086     smb_Directory_Watches = savedPacketp;
9087     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9088
9089     osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
9090               fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
9091     osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
9092              filter, fid, watchtree);
9093     if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9094         osi_Log0(smb_logp, "      Notify Change File Name");
9095     if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9096         osi_Log0(smb_logp, "      Notify Change Directory Name");
9097     if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9098         osi_Log0(smb_logp, "      Notify Change Attributes");
9099     if (filter & FILE_NOTIFY_CHANGE_SIZE)
9100         osi_Log0(smb_logp, "      Notify Change Size");
9101     if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9102         osi_Log0(smb_logp, "      Notify Change Last Write");
9103     if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9104         osi_Log0(smb_logp, "      Notify Change Last Access");
9105     if (filter & FILE_NOTIFY_CHANGE_CREATION)
9106         osi_Log0(smb_logp, "      Notify Change Creation");
9107     if (filter & FILE_NOTIFY_CHANGE_EA)
9108         osi_Log0(smb_logp, "      Notify Change Extended Attributes");
9109     if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9110         osi_Log0(smb_logp, "      Notify Change Security");
9111     if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9112         osi_Log0(smb_logp, "      Notify Change Stream Name");
9113     if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9114         osi_Log0(smb_logp, "      Notify Change Stream Size");
9115     if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9116         osi_Log0(smb_logp, "      Notify Change Stream Write");
9117
9118     lock_ObtainWrite(&scp->rw);
9119     if (watchtree)
9120         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
9121     else
9122         scp->flags |= CM_SCACHEFLAG_WATCHED;
9123     lock_ReleaseWrite(&scp->rw);
9124     cm_ReleaseSCache(scp);
9125     smb_ReleaseFID(fidp);
9126
9127     outp->flags |= SMB_PACKETFLAG_NOSEND;
9128     return 0;
9129 }
9130
9131 unsigned char nullSecurityDesc[] = {
9132     0x01,                               /* security descriptor revision */
9133     0x00,                               /* reserved, should be zero */
9134     0x04, 0x80,                         /* security descriptor control;
9135                                          * 0x0004 : null-DACL present - everyone has full access
9136                                          * 0x8000 : relative format */
9137     0x14, 0x00, 0x00, 0x00,             /* offset of owner SID */
9138     0x20, 0x00, 0x00, 0x00,             /* offset of group SID */
9139     0x00, 0x00, 0x00, 0x00,             /* offset of DACL would go here */
9140     0x00, 0x00, 0x00, 0x00,             /* offset of SACL would go here */
9141     0x01, 0x01, 0x00, 0x00,             /* "everyone SID" owner SID */
9142     0x00, 0x00, 0x00, 0x01,
9143     0x00, 0x00, 0x00, 0x00,
9144     0x01, 0x01, 0x00, 0x00,             /* "everyone SID" owner SID */
9145     0x00, 0x00, 0x00, 0x01,
9146     0x00, 0x00, 0x00, 0x00
9147 };
9148
9149 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
9150 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9151 {
9152     int parmOffset, parmCount, dataOffset, dataCount;
9153     int totalParmCount, totalDataCount;
9154     int parmSlot;
9155     int maxData, maxParm;
9156     int inTotalParm, inTotalData;
9157     int inParm, inData;
9158     int inParmOffset, inDataOffset;
9159     char *outData;
9160     char *parmp;
9161     USHORT *sparmp;
9162     ULONG *lparmp;
9163     USHORT fid;
9164     ULONG securityInformation;
9165     smb_fid_t *fidp;
9166     long code = 0;
9167     DWORD dwLength;
9168
9169     /*
9170      * For details on the meanings of the various
9171      * SMB_COM_TRANSACTION fields, see sections 2.2.4.33
9172      * of http://msdn.microsoft.com/en-us/library/ee442092%28PROT.13%29.aspx
9173      */
9174
9175     inTotalParm = smb_GetSMBOffsetParm(inp, 1, 1)
9176         | (smb_GetSMBOffsetParm(inp, 2, 1) << 16);
9177
9178     inTotalData = smb_GetSMBOffsetParm(inp, 3, 1)
9179         | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
9180
9181     maxParm = smb_GetSMBOffsetParm(inp, 5, 1)
9182         | (smb_GetSMBOffsetParm(inp, 6, 1) << 16);
9183
9184     maxData = smb_GetSMBOffsetParm(inp, 7, 1)
9185         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
9186
9187     inParm = smb_GetSMBOffsetParm(inp, 9, 1)
9188         | (smb_GetSMBOffsetParm(inp, 10, 1) << 16);
9189
9190     inParmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
9191         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
9192
9193     inData = smb_GetSMBOffsetParm(inp, 13, 1)
9194         | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
9195
9196     inDataOffset = smb_GetSMBOffsetParm(inp, 15, 1)
9197         | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
9198
9199     parmp = inp->data + inParmOffset;
9200     sparmp = (USHORT *) parmp;
9201     lparmp = (ULONG *) parmp;
9202
9203     fid = sparmp[0];
9204     securityInformation = lparmp[1];
9205
9206     fidp = smb_FindFID(vcp, fid, 0);
9207     if (!fidp) {
9208         osi_Log2(smb_logp, "smb_ReceiveNTTranQuerySecurityDesc Unknown SMB Fid vcp 0x%p fid %d",
9209                  vcp, fid);
9210         return CM_ERROR_BADFD;
9211     }
9212
9213     lock_ObtainMutex(&fidp->mx);
9214     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
9215         lock_ReleaseMutex(&fidp->mx);
9216         smb_CloseFID(vcp, fidp, NULL, 0);
9217         smb_ReleaseFID(fidp);
9218         return CM_ERROR_NOSUCHFILE;
9219     }
9220     lock_ReleaseMutex(&fidp->mx);
9221
9222     osi_Log4(smb_logp,"smb_ReceiveNTTranQuerySecurityDesc fidp 0x%p scp 0x%p file \"%S\" Info=0x%x",
9223               fidp, fidp->scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp),
9224               securityInformation);
9225
9226     smb_ReleaseFID(fidp);
9227
9228     if ( securityInformation & ~(OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION) )
9229     {
9230         code = CM_ERROR_BAD_LEVEL;
9231         goto done;
9232     }
9233
9234     dwLength = sizeof( nullSecurityDesc);
9235
9236     totalDataCount = dwLength;
9237     totalParmCount = 4;
9238
9239     if (maxData >= totalDataCount) {
9240         dataCount = totalDataCount;
9241         parmCount = min(totalParmCount, maxParm);
9242     } else if (maxParm >= totalParmCount) {
9243         totalDataCount = dataCount = 0;
9244         parmCount = totalParmCount;
9245     } else {
9246         totalDataCount = dataCount = 0;
9247         totalParmCount = parmCount = 0;
9248     }
9249
9250     /* out parms */
9251     parmOffset = 8*4 + 39;
9252     parmOffset += 1;    /* pad to 4 */
9253
9254     dataOffset = parmOffset + parmCount;
9255
9256     parmSlot = 1;
9257     outp->oddByte = 1;
9258     /* Total Parameter Count */
9259     smb_SetSMBParmLong(outp, parmSlot, totalParmCount); parmSlot += 2;
9260     /* Total Data Count */
9261     smb_SetSMBParmLong(outp, parmSlot, totalDataCount); parmSlot += 2;
9262     /* Parameter Count */
9263     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
9264     /* Parameter Offset */
9265     smb_SetSMBParmLong(outp, parmSlot, parmCount ? parmOffset : 0); parmSlot += 2;
9266     /* Parameter Displacement */
9267     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9268     /* Data Count */
9269     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
9270     /* Data Offset */
9271     smb_SetSMBParmLong(outp, parmSlot, dataCount ? dataOffset : 0); parmSlot += 2;
9272     /* Data Displacement */
9273     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9274     /* Setup Count */
9275     smb_SetSMBParmByte(outp, parmSlot, 0);
9276
9277     if (parmCount == totalParmCount && dwLength == dataCount) {
9278         smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
9279
9280         /* Data */
9281         outData = smb_GetSMBData(outp, NULL);
9282         outData++;                      /* round to get to dataOffset */
9283
9284         *((ULONG *)outData) = dataCount; outData += 4;  /* SD Length (4 bytes) */
9285         memcpy(outData, nullSecurityDesc, dataCount);
9286         outData += dataCount;
9287
9288         code = 0;
9289     } else if (parmCount >= 4) {
9290         smb_SetSMBDataLength(outp, 1 + parmCount);
9291
9292         /* Data */
9293         outData = smb_GetSMBData(outp, NULL);
9294         outData++;                      /* round to get to dataOffset */
9295
9296         *((ULONG *)outData) = dwLength; outData += 4;   /* SD Length (4 bytes) */
9297         code = CM_ERROR_BUFFERTOOSMALL;
9298     } else {
9299         smb_SetSMBDataLength(outp, 0);
9300         code = CM_ERROR_BUFFER_OVERFLOW;
9301     }
9302
9303   done:
9304     return code;
9305 }
9306
9307 /* SMB_COM_NT_TRANSACT
9308
9309    SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
9310  */
9311 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9312 {
9313     unsigned short function;
9314
9315     function = smb_GetSMBParm(inp, 18);
9316
9317     osi_Log1(smb_logp, "SMB NT Transact function %d", function);
9318
9319     /* We can handle long names */
9320     if (vcp->flags & SMB_VCFLAG_USENT)
9321         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
9322
9323     switch (function) {
9324     case 1:                     /* NT_TRANSACT_CREATE */
9325         return smb_ReceiveNTTranCreate(vcp, inp, outp);
9326     case 2:                     /* NT_TRANSACT_IOCTL */
9327         osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
9328         break;
9329     case 3:                     /* NT_TRANSACT_SET_SECURITY_DESC */
9330         osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
9331         break;
9332     case 4:                     /* NT_TRANSACT_NOTIFY_CHANGE */
9333         return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
9334     case 5:                     /* NT_TRANSACT_RENAME */
9335         osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
9336         break;
9337     case 6:                     /* NT_TRANSACT_QUERY_SECURITY_DESC */
9338         return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
9339     case 7:
9340         osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
9341         break;
9342     case 8:
9343         osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
9344         break;
9345     }
9346     return CM_ERROR_BADOP;
9347 }
9348
9349 /*
9350  * smb_NotifyChange -- find relevant change notification messages and
9351  *                     reply to them
9352  *
9353  * If we don't know the file name (i.e. a callback break), filename is
9354  * NULL, and we return a zero-length list.
9355  *
9356  * At present there is not a single call to smb_NotifyChange that
9357  * has the isDirectParent parameter set to FALSE.
9358  */
9359 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
9360         cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
9361         BOOL isDirectParent)
9362 {
9363     smb_packet_t *watch, *lastWatch, *nextWatch;
9364     ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
9365     char *outData, *oldOutData;
9366     ULONG filter;
9367     USHORT fid, wtree;
9368     ULONG maxLen;
9369     BOOL twoEntries = FALSE;
9370     ULONG otherNameLen, oldParmCount = 0;
9371     DWORD otherAction;
9372     smb_fid_t *fidp;
9373
9374     /* Get ready for rename within directory */
9375     if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
9376         twoEntries = TRUE;
9377         otherAction = FILE_ACTION_RENAMED_NEW_NAME;
9378     }
9379
9380     osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
9381              osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
9382     if (action == 0)
9383         osi_Log0(smb_logp,"      FILE_ACTION_NONE");
9384     if (action == FILE_ACTION_ADDED)
9385         osi_Log0(smb_logp,"      FILE_ACTION_ADDED");
9386     if (action == FILE_ACTION_REMOVED)
9387         osi_Log0(smb_logp,"      FILE_ACTION_REMOVED");
9388     if (action == FILE_ACTION_MODIFIED)
9389         osi_Log0(smb_logp,"      FILE_ACTION_MODIFIED");
9390     if (action == FILE_ACTION_RENAMED_OLD_NAME)
9391         osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_OLD_NAME");
9392     if (action == FILE_ACTION_RENAMED_NEW_NAME)
9393         osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_NEW_NAME");
9394
9395     lock_ObtainMutex(&smb_Dir_Watch_Lock);
9396     watch = smb_Directory_Watches;
9397     while (watch) {
9398         filter = smb_GetSMBParm(watch, 19)
9399             | (smb_GetSMBParm(watch, 20) << 16);
9400         fid = smb_GetSMBParm(watch, 21);
9401         wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
9402
9403         maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
9404             | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
9405
9406         /*
9407          * Strange hack - bug in NT Client and NT Server that we must emulate?
9408          */
9409         if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
9410             filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
9411
9412         fidp = smb_FindFID(watch->vcp, fid, 0);
9413         if (!fidp) {
9414             osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
9415             lastWatch = watch;
9416             watch = watch->nextp;
9417             continue;
9418         }
9419
9420         if (fidp->scp != dscp ||
9421             fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
9422             (filter & notifyFilter) == 0 ||
9423             (!isDirectParent && !wtree))
9424         {
9425             osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
9426             lastWatch = watch;
9427             watch = watch->nextp;
9428             smb_ReleaseFID(fidp);
9429             continue;
9430         }
9431
9432         osi_Log4(smb_logp,
9433                   "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
9434                   fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
9435         if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9436             osi_Log0(smb_logp, "      Notify Change File Name");
9437         if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9438             osi_Log0(smb_logp, "      Notify Change Directory Name");
9439         if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9440             osi_Log0(smb_logp, "      Notify Change Attributes");
9441         if (filter & FILE_NOTIFY_CHANGE_SIZE)
9442             osi_Log0(smb_logp, "      Notify Change Size");
9443         if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9444             osi_Log0(smb_logp, "      Notify Change Last Write");
9445         if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9446             osi_Log0(smb_logp, "      Notify Change Last Access");
9447         if (filter & FILE_NOTIFY_CHANGE_CREATION)
9448             osi_Log0(smb_logp, "      Notify Change Creation");
9449         if (filter & FILE_NOTIFY_CHANGE_EA)
9450             osi_Log0(smb_logp, "      Notify Change Extended Attributes");
9451         if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9452             osi_Log0(smb_logp, "      Notify Change Security");
9453         if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9454             osi_Log0(smb_logp, "      Notify Change Stream Name");
9455         if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9456             osi_Log0(smb_logp, "      Notify Change Stream Size");
9457         if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9458             osi_Log0(smb_logp, "      Notify Change Stream Write");
9459
9460         /* A watch can only be notified once.  Remove it from the list */
9461         nextWatch = watch->nextp;
9462         if (watch == smb_Directory_Watches)
9463             smb_Directory_Watches = nextWatch;
9464         else
9465             lastWatch->nextp = nextWatch;
9466
9467         /* Turn off WATCHED flag in dscp */
9468         lock_ObtainWrite(&dscp->rw);
9469         if (wtree)
9470             dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9471         else
9472             dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
9473         lock_ReleaseWrite(&dscp->rw);
9474
9475         /* Convert to response packet */
9476         ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
9477 #ifdef SEND_CANONICAL_PATHNAMES
9478         ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
9479 #endif
9480         ((smb_t *) watch)->wct = 0;
9481
9482         /* out parms */
9483         if (filename == NULL) {
9484             parmCount = 0;
9485         } else {
9486             nameLen = (ULONG)cm_ClientStrLen(filename);
9487             parmCount = 3*4 + nameLen*2;
9488             parmCount = (parmCount + 3) & ~3;   /* pad to 4 */
9489             if (twoEntries) {
9490                 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
9491                 oldParmCount = parmCount;
9492                 parmCount += 3*4 + otherNameLen*2;
9493                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9494             }
9495             if (maxLen < parmCount)
9496                 parmCount = 0;  /* not enough room */
9497         }
9498         parmOffset = 8*4 + 39;
9499         parmOffset += 1;                        /* pad to 4 */
9500         dataOffset = parmOffset + parmCount;
9501
9502         parmSlot = 1;
9503         watch->oddByte = 1;
9504         /* Total Parameter Count */
9505         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9506         /* Total Data Count */
9507         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9508         /* Parameter Count */
9509         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9510         /* Parameter Offset */
9511         smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
9512         /* Parameter Displacement */
9513         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9514         /* Data Count */
9515         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9516         /* Data Offset */
9517         smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
9518         /* Data Displacement */
9519         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9520         smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
9521         smb_SetSMBDataLength(watch, parmCount + 1);
9522
9523         if (parmCount != 0) {
9524             outData = smb_GetSMBData(watch, NULL);
9525             outData++;  /* round to get to parmOffset */
9526             oldOutData = outData;
9527             *((DWORD *)outData) = oldParmCount; outData += 4;
9528             /* Next Entry Offset */
9529             *((DWORD *)outData) = action; outData += 4;
9530             /* Action */
9531             *((DWORD *)outData) = nameLen*2; outData += 4;
9532             /* File Name Length */
9533
9534             smb_UnparseString(watch, outData, filename, NULL, 0);
9535             /* File Name */
9536
9537             if (twoEntries) {
9538                 outData = oldOutData + oldParmCount;
9539                 *((DWORD *)outData) = 0; outData += 4;
9540                 /* Next Entry Offset */
9541                 *((DWORD *)outData) = otherAction; outData += 4;
9542                 /* Action */
9543                 *((DWORD *)outData) = otherNameLen*2;
9544                 outData += 4;   /* File Name Length */
9545                 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
9546             }
9547         }
9548
9549         /*
9550          * If filename is null, we don't know the cause of the
9551          * change notification.  We return zero data (see above),
9552          * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
9553          * (= 0x010C).  We set the error code here by hand, without
9554          * modifying wct and bcc.
9555          */
9556         if (filename == NULL) {
9557             ((smb_t *) watch)->rcls = 0x0C;
9558             ((smb_t *) watch)->reh = 0x01;
9559             ((smb_t *) watch)->errLow = 0;
9560             ((smb_t *) watch)->errHigh = 0;
9561             /* Set NT Status codes flag */
9562             ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9563         }
9564
9565         smb_SendPacket(watch->vcp, watch);
9566         smb_FreePacket(watch);
9567
9568         smb_ReleaseFID(fidp);
9569         watch = nextWatch;
9570     }
9571     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9572 }
9573
9574 /* SMB_COM_NT_CANCEL */
9575 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9576 {
9577     unsigned char *replyWctp;
9578     smb_packet_t *watch, *lastWatch;
9579     USHORT fid, watchtree;
9580     smb_fid_t *fidp;
9581     cm_scache_t *scp;
9582
9583     osi_Log0(smb_logp, "SMB3 receive NT cancel");
9584
9585     lock_ObtainMutex(&smb_Dir_Watch_Lock);
9586     watch = smb_Directory_Watches;
9587     while (watch) {
9588         if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
9589              && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
9590              && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
9591              && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
9592             if (watch == smb_Directory_Watches)
9593                 smb_Directory_Watches = watch->nextp;
9594             else
9595                 lastWatch->nextp = watch->nextp;
9596             lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9597
9598             /* Turn off WATCHED flag in scp */
9599             fid = smb_GetSMBParm(watch, 21);
9600             watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
9601
9602             if (vcp != watch->vcp)
9603                 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
9604                           vcp, watch->vcp);
9605
9606             fidp = smb_FindFID(vcp, fid, 0);
9607             if (fidp) {
9608                 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
9609                          fid, watchtree,
9610                          (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
9611
9612                 scp = fidp->scp;
9613                 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
9614                 if (scp) {
9615                     lock_ObtainWrite(&scp->rw);
9616                     if (watchtree)
9617                         scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9618                     else
9619                         scp->flags &= ~CM_SCACHEFLAG_WATCHED;
9620                     lock_ReleaseWrite(&scp->rw);
9621                 }
9622                 smb_ReleaseFID(fidp);
9623             } else {
9624                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
9625             }
9626
9627             /* assume STATUS32; return 0xC0000120 (CANCELED) */
9628             replyWctp = watch->wctp;
9629             *replyWctp++ = 0;
9630             *replyWctp++ = 0;
9631             *replyWctp++ = 0;
9632             ((smb_t *)watch)->rcls = 0x20;
9633             ((smb_t *)watch)->reh = 0x1;
9634             ((smb_t *)watch)->errLow = 0;
9635             ((smb_t *)watch)->errHigh = 0xC0;
9636             ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9637             smb_SendPacket(vcp, watch);
9638             smb_FreePacket(watch);
9639             return 0;
9640         }
9641         lastWatch = watch;
9642         watch = watch->nextp;
9643     }
9644     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9645
9646     return 0;
9647 }
9648
9649 /*
9650  * NT rename also does hard links.
9651  */
9652
9653 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
9654 #define RENAME_FLAG_HARD_LINK                0x103
9655 #define RENAME_FLAG_RENAME                   0x104
9656 #define RENAME_FLAG_COPY                     0x105
9657
9658 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9659 {
9660     clientchar_t *oldPathp, *newPathp;
9661     long code = 0;
9662     char * tp;
9663     int attrs;
9664     int rename_type;
9665
9666     attrs = smb_GetSMBParm(inp, 0);
9667     rename_type = smb_GetSMBParm(inp, 1);
9668
9669     if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
9670         osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
9671         return CM_ERROR_NOACCESS;
9672     }
9673
9674     tp = smb_GetSMBData(inp, NULL);
9675     oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9676     if (!oldPathp)
9677         return CM_ERROR_BADSMB;
9678     newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9679     if (!newPathp)
9680         return CM_ERROR_BADSMB;
9681
9682     osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
9683              osi_LogSaveClientString(smb_logp, oldPathp),
9684              osi_LogSaveClientString(smb_logp, newPathp),
9685              ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
9686
9687     if (rename_type == RENAME_FLAG_RENAME) {
9688         code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
9689     } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
9690         code = smb_Link(vcp,inp,oldPathp,newPathp);
9691     } else
9692         code = CM_ERROR_BADOP;
9693     return code;
9694 }
9695
9696 void smb3_Init()
9697 {
9698     lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
9699 }
9700
9701 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9702 {
9703     smb_username_t *unp;
9704     cm_user_t *     userp;
9705
9706     unp = smb_FindUserByName(usern, machine, flags);
9707     if (!unp->userp) {
9708         lock_ObtainMutex(&unp->mx);
9709         unp->userp = cm_NewUser();
9710         lock_ReleaseMutex(&unp->mx);
9711         osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9712     }  else     {
9713         osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9714     }
9715     userp = unp->userp;
9716     cm_HoldUser(userp);
9717     smb_ReleaseUsername(unp);
9718     return userp;
9719 }
9720
9721 cm_user_t *smb_FindCMUserBySID(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9722 {
9723     smb_username_t *unp;
9724     cm_user_t *     userp;
9725
9726     unp = smb_FindUserByName(usern, machine, flags);
9727     if (!unp->userp) {
9728         lock_ObtainMutex(&unp->mx);
9729         unp->flags |= SMB_USERNAMEFLAG_SID;
9730         unp->userp = cm_NewUser();
9731         lock_ReleaseMutex(&unp->mx);
9732         osi_Log2(smb_logp,"smb_FindCMUserBySID New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9733     }  else     {
9734         osi_Log2(smb_logp,"smb_FindCMUserBySID Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9735     }
9736     userp = unp->userp;
9737     cm_HoldUser(userp);
9738     smb_ReleaseUsername(unp);
9739     return userp;
9740 }