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