Windows: disable short names on Windows 8
[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_shortNames && !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_shortNames &&
5964             !cm_Is8Dot3(cfileName)) {
5965             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5966             NeedShortName = 1;
5967         }
5968
5969         osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5970                  dep->fid.vnode, dep->fid.unique,
5971                  osi_LogSaveClientString(smb_logp, cfileName),
5972                  NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5973
5974         /* When matching, we are using doing a case fold if we have a wildcard mask.
5975          * If we get a non-wildcard match, it's a lookup for a specific file.
5976          */
5977         if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5978             (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5979         {
5980             /* Eliminate entries that don't match requested attributes */
5981             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5982                 smb_IsDotFile(cfileName)) {
5983                 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5984                 goto nextEntry; /* no hidden files */
5985             }
5986
5987             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
5988             {
5989                 /* We have already done the cm_TryBulkStat above */
5990                 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5991                           ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5992                 fileType = cm_FindFileType(&fid);
5993                 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5994                  * "has filetype %d", dep->name, fileType);
5995                  */
5996                 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5997                      fileType == CM_SCACHETYPE_MOUNTPOINT ||
5998                      fileType == CM_SCACHETYPE_DFSLINK ||
5999                      fileType == CM_SCACHETYPE_INVALID)
6000                     osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
6001                 goto nextEntry;
6002             }
6003
6004             /* finally check if this name will fit */
6005             onbytes = 0;
6006             smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
6007             orbytes = ohbytes + onbytes;
6008
6009             /* now, we round up the record to a 4 byte alignment,
6010              * and we make sure that we have enough room here for
6011              * even the aligned version (so we don't have to worry
6012              * about an overflow when we pad things out below).
6013              * That's the reason for the alignment arithmetic below.
6014              */
6015             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
6016                 align = (4 - (orbytes & 3)) & 3;
6017             else
6018                 align = 0;
6019
6020             if (orbytes + bytesInBuffer + align > maxReturnData) {
6021                 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
6022                          maxReturnData);
6023                 break;
6024             }
6025
6026             /* this is one of the entries to use: it is not deleted
6027              * and it matches the star pattern we're looking for.
6028              * Put out the name, preceded by its length.
6029              */
6030             /* First zero everything else */
6031             memset(origOp, 0, orbytes);
6032
6033             onbytes = 0;
6034             smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
6035
6036             switch (infoLevel) {
6037             case SMB_INFO_STANDARD:
6038                 fp->u.FstandardInfo.fileNameLength = onbytes;
6039                 attrp = &fp->u.FstandardInfo.fileAttrs;
6040                 break;
6041
6042             case SMB_INFO_QUERY_EA_SIZE:
6043                 fp->u.FeaSizeInfo.fileNameLength = onbytes;
6044                 attrp = &fp->u.FeaSizeInfo.fileAttrs;
6045                 fp->u.FeaSizeInfo.eaSize = 0;
6046                 break;
6047
6048             case SMB_INFO_QUERY_EAS_FROM_LIST:
6049                 fp->u.FeasFromListInfo.fileNameLength = onbytes;
6050                 attrp = &fp->u.FeasFromListInfo.fileAttrs;
6051                 fp->u.FeasFromListInfo.eaSize = 0;
6052                 break;
6053
6054             case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
6055                 if (NeedShortName) {
6056 #ifdef SMB_UNICODE
6057                     int nchars;
6058
6059                     nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
6060                                                     fp->u.FfileBothDirectoryInfo.shortName,
6061                                                     sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
6062                     if (nchars > 0)
6063                         fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
6064                     else
6065                         fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
6066                     fp->u.FfileBothDirectoryInfo.reserved = 0;
6067 #else
6068                     cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
6069                                     lengthof(fp->u.FfileBothDirectoryInfo.shortName),
6070                                     shortName);
6071                     fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
6072 #endif
6073                 }
6074                 /* Fallthrough */
6075
6076             case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
6077                 fp->u.FfileFullDirectoryInfo.eaSize = 0;
6078                 /* Fallthrough */
6079
6080             case SMB_FIND_FILE_DIRECTORY_INFO:
6081                 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
6082                 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
6083                 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
6084                 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
6085                 break;
6086
6087             case SMB_FIND_FILE_NAMES_INFO:
6088                 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
6089                 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
6090                 fp->u.FfileNamesInfo.fileNameLength = onbytes;
6091                 attrp = NULL;
6092                 break;
6093
6094             default:
6095                 /* we shouldn't hit this case */
6096                 osi_assertx(FALSE, "Unknown query type");
6097             }
6098
6099             /* now, adjust the # of entries copied */
6100             returnedNames++;
6101
6102             /* now we emit the attribute.  This is tricky, since
6103              * we need to really stat the file to find out what
6104              * type of entry we've got.  Right now, we're copying
6105              * out data from a buffer, while holding the scp
6106              * locked, so it isn't really convenient to stat
6107              * something now.  We'll put in a place holder
6108              * now, and make a second pass before returning this
6109              * to get the real attributes.  So, we just skip the
6110              * data for now, and adjust it later.  We allocate a
6111              * patch record to make it easy to find this point
6112              * later.  The replay will happen at a time when it is
6113              * safe to unlock the directory.
6114              */
6115             if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
6116                 osi_assert(attrp != NULL);
6117                 curPatchp = malloc(sizeof(*curPatchp));
6118                 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
6119                 curPatchp->dptr = attrp;
6120
6121                 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
6122                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
6123                 } else {
6124                     curPatchp->flags = 0;
6125                 }
6126
6127                 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
6128
6129                 /* temp */
6130                 curPatchp->dep = dep;
6131             }
6132
6133             if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
6134                 /* put out resume key */
6135                 *((u_long *)origOp) = nextEntryCookie;
6136
6137             /* Adjust byte ptr and count */
6138             origOp += orbytes;  /* skip entire record */
6139             bytesInBuffer += orbytes;
6140
6141             /* and pad the record out */
6142             while (align-- > 0) {
6143                 *origOp++ = 0;
6144                 bytesInBuffer++;
6145             }
6146         }       /* if we're including this name */
6147         else if (!starPattern &&
6148                  !foundInexact &&
6149                  cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
6150             /* We were looking for exact matches, but here's an inexact one*/
6151             foundInexact = 1;
6152         }
6153
6154       nextEntry:
6155         /* and adjust curOffset to be where the new cookie is */
6156         thyper.HighPart = 0;
6157         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
6158         curOffset = LargeIntegerAdd(thyper, curOffset);
6159     } /* while copying data for dir listing */
6160
6161     /* If we didn't get a star pattern, we did an exact match during the first pass.
6162      * If there were no exact matches found, we fail over to inexact matches by
6163      * marking the query as a star pattern (matches all case permutations), and
6164      * re-running the query.
6165      */
6166     if (returnedNames == 0 && !starPattern && foundInexact) {
6167         osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
6168         starPattern = 1;
6169         goto startsearch;
6170     }
6171
6172     /* release the mutex */
6173     lock_ReleaseWrite(&scp->rw);
6174     if (bufferp) {
6175         buf_Release(bufferp);
6176         bufferp = NULL;
6177     }
6178
6179     /*
6180      * Finally, process whatever entries we have left.
6181      */
6182     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
6183                                       dsp->relPath, infoLevel, userp, &req);
6184
6185     /* now put out the final parameters */
6186     if (returnedNames == 0)
6187         eos = 1;
6188     if (p->opcode == 1) {
6189         /* find first */
6190         outp->parmsp[0] = (unsigned short) dsp->cookie;
6191         outp->parmsp[1] = returnedNames;
6192         outp->parmsp[2] = eos;
6193         outp->parmsp[3] = 0;            /* nothing wrong with EAS */
6194         outp->parmsp[4] = 0;
6195         /* don't need last name to continue
6196          * search, cookie is enough.  Normally,
6197          * this is the offset of the file name
6198          * of the last entry returned.
6199          */
6200         outp->totalParms = 10;  /* in bytes */
6201     }
6202     else {
6203         /* find next */
6204         outp->parmsp[0] = returnedNames;
6205         outp->parmsp[1] = eos;
6206         outp->parmsp[2] = 0;    /* EAS error */
6207         outp->parmsp[3] = 0;    /* last name, as above */
6208         outp->totalParms = 8;   /* in bytes */
6209     }
6210
6211     /* return # of bytes in the buffer */
6212     outp->totalData = bytesInBuffer;
6213
6214     /* Return error code if unsuccessful on first request */
6215     if (code == 0 && p->opcode == 1 && returnedNames == 0)
6216         code = CM_ERROR_NOSUCHFILE;
6217
6218     osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
6219              p->opcode, dsp->cookie, returnedNames, code);
6220
6221     /* if we're supposed to close the search after this request, or if
6222      * we're supposed to close the search if we're done, and we're done,
6223      * or if something went wrong, close the search.
6224      */
6225     if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
6226         (returnedNames == 0) ||
6227         ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
6228         code != 0)
6229         smb_DeleteDirSearch(dsp);
6230
6231     if (code)
6232         smb_SendTran2Error(vcp, p, opx, code);
6233     else
6234         smb_SendTran2Packet(vcp, outp, opx);
6235
6236     smb_FreeTran2Packet(outp);
6237     smb_ReleaseDirSearch(dsp);
6238     cm_ReleaseSCache(scp);
6239     cm_ReleaseUser(userp);
6240     return 0;
6241 }
6242
6243 /* SMB_COM_FIND_CLOSE2 */
6244 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6245 {
6246     int dirHandle;
6247     smb_dirSearch_t *dsp;
6248
6249     dirHandle = smb_GetSMBParm(inp, 0);
6250
6251     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
6252
6253     dsp = smb_FindDirSearch(dirHandle);
6254
6255     if (!dsp)
6256         return CM_ERROR_BADFD;
6257
6258     /* otherwise, we have an FD to destroy */
6259     smb_DeleteDirSearch(dsp);
6260     smb_ReleaseDirSearch(dsp);
6261
6262     /* and return results */
6263     smb_SetSMBDataLength(outp, 0);
6264
6265     return 0;
6266 }
6267
6268
6269 /* SMB_COM_FIND_NOTIFY_CLOSE */
6270 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6271 {
6272     smb_SetSMBDataLength(outp, 0);
6273     return 0;
6274 }
6275
6276 /* SMB_COM_OPEN_ANDX */
6277 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6278 {
6279     clientchar_t *pathp;
6280     long code = 0;
6281     cm_space_t *spacep;
6282     int excl;
6283     cm_user_t *userp;
6284     cm_scache_t *dscp;          /* dir we're dealing with */
6285     cm_scache_t *scp;           /* file we're creating */
6286     cm_attr_t setAttr;
6287     smb_fid_t *fidp;
6288     int attributes;
6289     clientchar_t *lastNamep;
6290     unsigned long dosTime;
6291     int openFun;
6292     int trunc;
6293     int openMode;
6294     int extraInfo;
6295     int openAction;
6296     int parmSlot;                       /* which parm we're dealing with */
6297     clientchar_t *tidPathp;
6298     cm_req_t req;
6299     int created = 0;
6300     BOOL is_rpc = FALSE;
6301     BOOL is_ipc = FALSE;
6302
6303     smb_InitReq(&req);
6304
6305     scp = NULL;
6306
6307     extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
6308     openFun = smb_GetSMBParm(inp, 8); /* open function */
6309     excl = ((openFun & 3) == 0);
6310     trunc = ((openFun & 3) == 2); /* truncate it */
6311     openMode = (smb_GetSMBParm(inp, 3) & 0x7);
6312     openAction = 0;             /* tracks what we did */
6313
6314     attributes = smb_GetSMBParm(inp, 5);
6315     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
6316
6317     pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
6318                                 SMB_STRF_ANSIPATH);
6319     if (!pathp)
6320         return CM_ERROR_BADSMB;
6321
6322     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6323     if (code) {
6324         if (code == CM_ERROR_TIDIPC) {
6325             is_ipc = TRUE;
6326         } else {
6327             return CM_ERROR_NOSUCHPATH;
6328         }
6329     }
6330
6331     spacep = inp->spacep;
6332     /* smb_StripLastComponent will strip "::$DATA" if present */
6333     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6334
6335     if (lastNamep &&
6336
6337         /* special case magic file name for receiving IOCTL requests
6338          * (since IOCTL calls themselves aren't getting through).
6339          */
6340         (cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
6341
6342          /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional) */
6343          (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
6344
6345         unsigned short file_type = 0;
6346         unsigned short device_state = 0;
6347
6348         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6349         if (is_rpc) {
6350             code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
6351             osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
6352             if (code) {
6353                 osi_Log1(smb_logp, "smb_SetupRPCFid failure code [%d]", code);
6354                 smb_ReleaseFID(fidp);
6355                 return code;
6356             }
6357         } else {
6358             smb_SetupIoctlFid(fidp, spacep);
6359             osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
6360         }
6361
6362         /* set inp->fid so that later read calls in same msg can find fid */
6363         inp->fid = fidp->fid;
6364
6365         /* copy out remainder of the parms */
6366         parmSlot = 2;
6367         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6368         if (extraInfo) {
6369             smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
6370             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* mod time */
6371             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6372             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* len */
6373             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
6374             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6375             smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
6376             smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
6377         }
6378         /* and the final "always present" stuff */
6379         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
6380         /* next write out the "unique" ID */
6381         smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
6382         smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
6383         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6384         smb_SetSMBDataLength(outp, 0);
6385
6386         /* and clean up fid reference */
6387         smb_ReleaseFID(fidp);
6388         return 0;
6389     }
6390
6391 #ifndef DFS_SUPPORT
6392     if (is_ipc) {
6393         osi_Log0(smb_logp, "NTOpenX rejecting IPC TID");
6394         return CM_ERROR_BADFD;
6395     }
6396 #endif
6397
6398     if (!cm_IsValidClientString(pathp)) {
6399 #ifdef DEBUG
6400         clientchar_t * hexp;
6401
6402         hexp = cm_GetRawCharsAlloc(pathp, -1);
6403         osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
6404                  osi_LogSaveClientString(smb_logp, hexp));
6405         if (hexp)
6406             free(hexp);
6407 #else
6408         osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
6409 #endif
6410         return CM_ERROR_BADNTFILENAME;
6411     }
6412
6413 #ifdef DEBUG_VERBOSE
6414     {
6415         char *hexp, *asciip;
6416         asciip = (lastNamep ? lastNamep : pathp );
6417         hexp = osi_HexifyString(asciip);
6418         DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
6419         free(hexp);
6420     }
6421 #endif
6422     userp = smb_GetUserFromVCP(vcp, inp);
6423
6424     dscp = NULL;
6425     code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
6426                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6427                     userp, tidPathp, &req, &scp);
6428
6429 #ifdef DFS_SUPPORT
6430     if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6431         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
6432         cm_ReleaseSCache(scp);
6433         cm_ReleaseUser(userp);
6434         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6435             return CM_ERROR_PATH_NOT_COVERED;
6436         else
6437             return CM_ERROR_NOSUCHPATH;
6438     }
6439 #endif /* DFS_SUPPORT */
6440
6441     if (code != 0) {
6442         if (code == CM_ERROR_NOSUCHFILE ||
6443             code == CM_ERROR_NOSUCHPATH ||
6444             code == CM_ERROR_BPLUS_NOMATCH)
6445             code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
6446                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6447                             userp, tidPathp, &req, &dscp);
6448         if (code) {
6449             cm_ReleaseUser(userp);
6450             return code;
6451         }
6452
6453 #ifdef DFS_SUPPORT
6454         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6455             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6456                                                       spacep->wdata);
6457             cm_ReleaseSCache(dscp);
6458             cm_ReleaseUser(userp);
6459             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6460                 return CM_ERROR_PATH_NOT_COVERED;
6461             else
6462                 return CM_ERROR_NOSUCHPATH;
6463         }
6464 #endif /* DFS_SUPPORT */
6465         /* otherwise, scp points to the parent directory.  Do a lookup,
6466          * and truncate the file if we find it, otherwise we create the
6467          * file.
6468          */
6469         if (!lastNamep)
6470             lastNamep = pathp;
6471         else
6472             lastNamep++;
6473         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
6474                           &req, &scp);
6475         if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6476             cm_ReleaseSCache(dscp);
6477             cm_ReleaseUser(userp);
6478             return code;
6479         }
6480     }
6481
6482     /* if we get here, if code is 0, the file exists and is represented by
6483      * scp.  Otherwise, we have to create it.  The dir may be represented
6484      * by dscp, or we may have found the file directly.  If code is non-zero,
6485      * scp is NULL.
6486      */
6487     if (code == 0) {
6488         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
6489         if (code) {
6490             if (dscp) cm_ReleaseSCache(dscp);
6491             cm_ReleaseSCache(scp);
6492             cm_ReleaseUser(userp);
6493             return code;
6494         }
6495
6496         if (excl) {
6497             /* oops, file shouldn't be there */
6498             if (dscp)
6499                 cm_ReleaseSCache(dscp);
6500             cm_ReleaseSCache(scp);
6501             cm_ReleaseUser(userp);
6502             return CM_ERROR_EXISTS;
6503         }
6504
6505         if (trunc) {
6506             setAttr.mask = CM_ATTRMASK_LENGTH;
6507             setAttr.length.LowPart = 0;
6508             setAttr.length.HighPart = 0;
6509             code = cm_SetAttr(scp, &setAttr, userp, &req);
6510             openAction = 3;     /* truncated existing file */
6511         }
6512         else openAction = 1;    /* found existing file */
6513     }
6514     else if (!(openFun & SMB_ATTR_DIRECTORY)) {
6515         /* don't create if not found */
6516         if (dscp) cm_ReleaseSCache(dscp);
6517         cm_ReleaseUser(userp);
6518         return CM_ERROR_NOSUCHFILE;
6519     }
6520     else {
6521         osi_assertx(dscp != NULL, "null cm_scache_t");
6522         osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
6523                  osi_LogSaveClientString(smb_logp, lastNamep));
6524         openAction = 2; /* created file */
6525         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6526         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6527         smb_SetInitialModeBitsForFile(attributes, &setAttr);
6528
6529         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6530                          &req);
6531         if (code == 0) {
6532             created = 1;
6533             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6534                 smb_NotifyChange(FILE_ACTION_ADDED,
6535                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6536                                  dscp, lastNamep, NULL, TRUE);
6537         } else if (!excl && code == CM_ERROR_EXISTS) {
6538             /* not an exclusive create, and someone else tried
6539              * creating it already, then we open it anyway.  We
6540              * don't bother retrying after this, since if this next
6541              * fails, that means that the file was deleted after we
6542              * started this call.
6543              */
6544             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6545                              userp, &req, &scp);
6546             if (code == 0) {
6547                 if (trunc) {
6548                     setAttr.mask = CM_ATTRMASK_LENGTH;
6549                     setAttr.length.LowPart = 0;
6550                     setAttr.length.HighPart = 0;
6551                     code = cm_SetAttr(scp, &setAttr, userp, &req);
6552                 }
6553             }   /* lookup succeeded */
6554         }
6555     }
6556
6557     /* we don't need this any longer */
6558     if (dscp)
6559         cm_ReleaseSCache(dscp);
6560
6561     if (code) {
6562         /* something went wrong creating or truncating the file */
6563         if (scp)
6564             cm_ReleaseSCache(scp);
6565         cm_ReleaseUser(userp);
6566         return code;
6567     }
6568
6569     /* make sure we're about to open a file */
6570     if (scp->fileType != CM_SCACHETYPE_FILE) {
6571         cm_ReleaseSCache(scp);
6572         cm_ReleaseUser(userp);
6573         return CM_ERROR_ISDIR;
6574     }
6575
6576     /* now all we have to do is open the file itself */
6577     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6578     osi_assertx(fidp, "null smb_fid_t");
6579
6580     cm_HoldUser(userp);
6581     lock_ObtainMutex(&fidp->mx);
6582     /* save a pointer to the vnode */
6583     fidp->scp = scp;
6584     lock_ObtainWrite(&scp->rw);
6585     scp->flags |= CM_SCACHEFLAG_SMB_FID;
6586     lock_ReleaseWrite(&scp->rw);
6587     osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
6588     /* also the user */
6589     fidp->userp = userp;
6590
6591     /* compute open mode */
6592     if (openMode != 1)
6593         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
6594     if (openMode == 1 || openMode == 2)
6595         fidp->flags |= SMB_FID_OPENWRITE;
6596
6597     /* remember if the file was newly created */
6598     if (created)
6599         fidp->flags |= SMB_FID_CREATED;
6600
6601     lock_ReleaseMutex(&fidp->mx);
6602     smb_ReleaseFID(fidp);
6603
6604     cm_Open(scp, 0, userp);
6605
6606     /* set inp->fid so that later read calls in same msg can find fid */
6607     inp->fid = fidp->fid;
6608
6609     /* copy out remainder of the parms */
6610     parmSlot = 2;
6611     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6612     lock_ObtainRead(&scp->rw);
6613     if (extraInfo) {
6614         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
6615         smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
6616         smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
6617         smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
6618         smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
6619         smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
6620         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6621         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
6622         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
6623     }
6624     /* and the final "always present" stuff */
6625     smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
6626     /* next write out the "unique" ID */
6627     smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
6628     smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
6629     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6630     lock_ReleaseRead(&scp->rw);
6631     smb_SetSMBDataLength(outp, 0);
6632
6633     osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
6634
6635     cm_ReleaseUser(userp);
6636     /* leave scp held since we put it in fidp->scp */
6637     return 0;
6638 }
6639
6640 static void smb_GetLockParams(unsigned char LockType,
6641                               char ** buf,
6642                               unsigned int * ppid,
6643                               LARGE_INTEGER * pOffset,
6644                               LARGE_INTEGER * pLength)
6645 {
6646     if (LockType & LOCKING_ANDX_LARGE_FILES) {
6647         /* Large Files */
6648         *ppid = *((USHORT *) *buf);
6649         pOffset->HighPart = *((LONG *)(*buf + 4));
6650         pOffset->LowPart = *((DWORD *)(*buf + 8));
6651         pLength->HighPart = *((LONG *)(*buf + 12));
6652         pLength->LowPart = *((DWORD *)(*buf + 16));
6653         *buf += 20;
6654     }
6655     else {
6656         /* Not Large Files */
6657         *ppid = *((USHORT *) *buf);
6658         pOffset->HighPart = 0;
6659         pOffset->LowPart = *((DWORD *)(*buf + 2));
6660         pLength->HighPart = 0;
6661         pLength->LowPart = *((DWORD *)(*buf + 6));
6662         *buf += 10;
6663     }
6664 }
6665
6666 /* SMB_COM_LOCKING_ANDX */
6667 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6668 {
6669     cm_req_t req;
6670     cm_user_t *userp;
6671     unsigned short fid;
6672     smb_fid_t *fidp;
6673     cm_scache_t *scp;
6674     unsigned char LockType;
6675     unsigned short NumberOfUnlocks, NumberOfLocks;
6676     afs_uint32 Timeout;
6677     char *op;
6678     char *op_locks;
6679     LARGE_INTEGER LOffset, LLength;
6680     smb_waitingLockRequest_t *wlRequest = NULL;
6681     cm_file_lock_t *lockp;
6682     long code = 0;
6683     int i;
6684     cm_key_t key;
6685     unsigned int pid;
6686     afs_uint32 smb_vc_hold_required = 0;
6687
6688     smb_InitReq(&req);
6689
6690     fid = smb_GetSMBParm(inp, 2);
6691     fid = smb_ChainFID(fid, inp);
6692
6693     fidp = smb_FindFID(vcp, fid, 0);
6694     if (!fidp) {
6695         osi_Log2(smb_logp, "V3LockingX Unknown SMB Fid vcp 0x%p fid %d",
6696                  vcp, fid);
6697         return CM_ERROR_BADFD;
6698     }
6699     lock_ObtainMutex(&fidp->mx);
6700     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6701         lock_ReleaseMutex(&fidp->mx);
6702         smb_CloseFID(vcp, fidp, NULL, 0);
6703         smb_ReleaseFID(fidp);
6704         return CM_ERROR_NOSUCHFILE;
6705     }
6706
6707     if (fidp->flags & SMB_FID_IOCTL) {
6708         osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6709         lock_ReleaseMutex(&fidp->mx);
6710         smb_ReleaseFID(fidp);
6711         return CM_ERROR_BADFD;
6712     }
6713     scp = fidp->scp;
6714     osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6715     cm_HoldSCache(scp);
6716     lock_ReleaseMutex(&fidp->mx);
6717
6718     /* set inp->fid so that later read calls in same msg can find fid */
6719     inp->fid = fid;
6720
6721     userp = smb_GetUserFromVCP(vcp, inp);
6722     smb_HoldVC(vcp);
6723
6724     lock_ObtainWrite(&scp->rw);
6725     code = cm_SyncOp(scp, NULL, userp, &req, 0,
6726                       CM_SCACHESYNC_NEEDCALLBACK
6727                          | CM_SCACHESYNC_GETSTATUS
6728                          | CM_SCACHESYNC_LOCK);
6729     if (code) {
6730         osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6731         goto doneSync;
6732     }
6733
6734     LockType = smb_GetSMBParm(inp, 3) & 0xff;
6735     Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6736     NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6737     NumberOfLocks = smb_GetSMBParm(inp, 7);
6738
6739     if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6740         !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6741         /* somebody wants exclusive locks on a file that they only
6742            opened for reading.  We downgrade this to a shared lock. */
6743         osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6744         LockType |= LOCKING_ANDX_SHARED_LOCK;
6745     }
6746
6747     if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6748         /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6749         osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6750         code = CM_ERROR_BADOP;
6751         goto done;
6752
6753     }
6754
6755     op = smb_GetSMBData(inp, NULL);
6756
6757     if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6758         /* Cancel outstanding lock requests */
6759         smb_waitingLock_t * wl;
6760
6761         for (i=0; i<NumberOfLocks; i++) {
6762             smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6763
6764             key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6765
6766             lock_ObtainWrite(&smb_globalLock);
6767             for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6768             {
6769                 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6770                     if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6771                         LargeIntegerEqualTo(wl->LLength, LLength)) {
6772                         wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6773                         goto found_lock_request;
6774                     }
6775                 }
6776             }
6777           found_lock_request:
6778             lock_ReleaseWrite(&smb_globalLock);
6779         }
6780         code = 0;
6781         smb_SetSMBDataLength(outp, 0);
6782         goto done;
6783     }
6784
6785
6786     for (i=0; i<NumberOfUnlocks; i++) {
6787         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6788
6789         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6790
6791         code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6792
6793         if (code)
6794             goto done;
6795     }
6796
6797     op_locks = op;
6798
6799     for (i=0; i<NumberOfLocks; i++) {
6800         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6801
6802         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6803
6804         code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6805                         userp, &req, &lockp);
6806
6807         if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6808             (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6809         {
6810             code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6811                             userp, &req, &lockp);
6812         }
6813
6814         if (code == CM_ERROR_LOCK_NOT_GRANTED && Timeout != 0) {
6815             smb_waitingLock_t * wLock;
6816
6817             /* Put on waiting list */
6818             if(wlRequest == NULL) {
6819                 int j;
6820                 char * opt;
6821                 cm_key_t tkey;
6822                 LARGE_INTEGER tOffset, tLength;
6823
6824                 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6825
6826                 osi_assertx(wlRequest != NULL, "null wlRequest");
6827
6828                 wlRequest->vcp = vcp;
6829                 smb_vc_hold_required = 1;
6830                 wlRequest->scp = scp;
6831                 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6832                 cm_HoldSCache(scp);
6833                 wlRequest->inp = smb_CopyPacket(inp);
6834                 wlRequest->outp = smb_CopyPacket(outp);
6835                 wlRequest->lockType = LockType;
6836                 wlRequest->msTimeout = Timeout;
6837                 wlRequest->start_t = osi_Time();
6838                 wlRequest->locks = NULL;
6839
6840                 /* The waiting lock request needs to have enough
6841                    information to undo all the locks in the request.
6842                    We do the following to store info about locks that
6843                    have already been granted.  Sure, we can get most
6844                    of the info from the packet, but the packet doesn't
6845                    hold the result of cm_Lock call.  In practice we
6846                    only receive packets with one or two locks, so we
6847                    are only wasting a few bytes here and there and
6848                    only for a limited period of time until the waiting
6849                    lock times out or is freed. */
6850
6851                 for(opt = op_locks, j=i; j > 0; j--) {
6852                     smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6853
6854                     tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6855
6856                     wLock = malloc(sizeof(smb_waitingLock_t));
6857
6858                     osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6859
6860                     wLock->key = tkey;
6861                     wLock->LOffset = tOffset;
6862                     wLock->LLength = tLength;
6863                     wLock->lockp = NULL;
6864                     wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6865                     osi_QAdd((osi_queue_t **) &wlRequest->locks,
6866                              &wLock->q);
6867                 }
6868             }
6869
6870             wLock = malloc(sizeof(smb_waitingLock_t));
6871
6872             osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6873
6874             wLock->key = key;
6875             wLock->LOffset = LOffset;
6876             wLock->LLength = LLength;
6877             wLock->lockp = lockp;
6878             wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6879             osi_QAdd((osi_queue_t **) &wlRequest->locks,
6880                      &wLock->q);
6881
6882             osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6883                      wLock);
6884
6885             code = 0;
6886             continue;
6887         }
6888
6889         if (code) {
6890             osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6891             break;
6892         }
6893     }
6894
6895     if (code) {
6896
6897         /* Since something went wrong with the lock number i, we now
6898            have to go ahead and release any locks acquired before the
6899            failure.  All locks before lock number i (of which there
6900            are i of them) have either been successful or are waiting.
6901            Either case requires calling cm_Unlock(). */
6902
6903         /* And purge the waiting lock */
6904         if(wlRequest != NULL) {
6905             smb_waitingLock_t * wl;
6906             smb_waitingLock_t * wlNext;
6907             long ul_code;
6908
6909             for(wl = wlRequest->locks; wl; wl = wlNext) {
6910
6911                 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6912
6913                 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6914
6915                 if(ul_code != 0) {
6916                     osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6917                 } else {
6918                     osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6919                 }
6920
6921                 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6922                 free(wl);
6923
6924             }
6925
6926             smb_ReleaseVC(wlRequest->vcp);
6927             cm_ReleaseSCache(wlRequest->scp);
6928             smb_FreePacket(wlRequest->inp);
6929             smb_FreePacket(wlRequest->outp);
6930
6931             free(wlRequest);
6932
6933             wlRequest = NULL;
6934         }
6935
6936     } else {
6937
6938         if (wlRequest != NULL) {
6939
6940             lock_ObtainWrite(&smb_globalLock);
6941             osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6942                      &wlRequest->q);
6943             osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6944             lock_ReleaseWrite(&smb_globalLock);
6945
6946             /* don't send reply immediately */
6947             outp->flags |= SMB_PACKETFLAG_NOSEND;
6948         }
6949
6950         smb_SetSMBDataLength(outp, 0);
6951     }
6952
6953   done:
6954     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6955
6956   doneSync:
6957     lock_ReleaseWrite(&scp->rw);
6958     cm_ReleaseSCache(scp);
6959     cm_ReleaseUser(userp);
6960     smb_ReleaseFID(fidp);
6961     if (!smb_vc_hold_required)
6962         smb_HoldVC(vcp);
6963
6964     return code;
6965 }
6966
6967 /* SMB_COM_QUERY_INFORMATION2 */
6968 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6969 {
6970     unsigned short fid;
6971     smb_fid_t *fidp;
6972     cm_scache_t *scp;
6973     long code = 0;
6974     afs_uint32 searchTime;
6975     cm_user_t *userp;
6976     cm_req_t req;
6977     int readlock = 0;
6978
6979     smb_InitReq(&req);
6980
6981     fid = smb_GetSMBParm(inp, 0);
6982     fid = smb_ChainFID(fid, inp);
6983
6984     fidp = smb_FindFID(vcp, fid, 0);
6985     if (!fidp) {
6986         osi_Log2(smb_logp, "V3GetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6987                  vcp, fid);
6988         return CM_ERROR_BADFD;
6989     }
6990     lock_ObtainMutex(&fidp->mx);
6991     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6992         lock_ReleaseMutex(&fidp->mx);
6993         smb_CloseFID(vcp, fidp, NULL, 0);
6994         smb_ReleaseFID(fidp);
6995         return CM_ERROR_NOSUCHFILE;
6996     }
6997
6998     if (fidp->flags & SMB_FID_IOCTL) {
6999         lock_ReleaseMutex(&fidp->mx);
7000         smb_ReleaseFID(fidp);
7001         return CM_ERROR_BADFD;
7002     }
7003     scp = fidp->scp;
7004     osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
7005     cm_HoldSCache(scp);
7006     lock_ReleaseMutex(&fidp->mx);
7007
7008     userp = smb_GetUserFromVCP(vcp, inp);
7009
7010
7011     /* otherwise, stat the file */
7012     lock_ObtainWrite(&scp->rw);
7013     code = cm_SyncOp(scp, NULL, userp, &req, 0,
7014                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7015     if (code)
7016         goto done;
7017
7018     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7019
7020     lock_ConvertWToR(&scp->rw);
7021     readlock = 1;
7022
7023     /* decode times.  We need a search time, but the response to this
7024      * call provides the date first, not the time, as returned in the
7025      * searchTime variable.  So we take the high-order bits first.
7026      */
7027     cm_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
7028     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);       /* ctime */
7029     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
7030     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);       /* atime */
7031     smb_SetSMBParm(outp, 3, searchTime & 0xffff);
7032     smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);       /* mtime */
7033     smb_SetSMBParm(outp, 5, searchTime & 0xffff);
7034
7035     /* now handle file size and allocation size */
7036     smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);              /* file size */
7037     smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
7038     smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);              /* alloc size */
7039     smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
7040
7041     /* file attribute */
7042     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
7043
7044     /* and finalize stuff */
7045     smb_SetSMBDataLength(outp, 0);
7046     code = 0;
7047
7048   done:
7049     if (readlock)
7050         lock_ReleaseRead(&scp->rw);
7051     else
7052         lock_ReleaseWrite(&scp->rw);
7053     cm_ReleaseSCache(scp);
7054     cm_ReleaseUser(userp);
7055     smb_ReleaseFID(fidp);
7056     return code;
7057 }
7058
7059 /* SMB_COM_SET_INFORMATION2 */
7060 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7061 {
7062     unsigned short fid;
7063     smb_fid_t *fidp;
7064     cm_scache_t *scp;
7065     long code = 0;
7066     afs_uint32 searchTime;
7067     time_t unixTime;
7068     cm_user_t *userp;
7069     cm_attr_t attrs;
7070     cm_req_t req;
7071
7072     smb_InitReq(&req);
7073
7074     fid = smb_GetSMBParm(inp, 0);
7075     fid = smb_ChainFID(fid, inp);
7076
7077     fidp = smb_FindFID(vcp, fid, 0);
7078     if (!fidp) {
7079         osi_Log2(smb_logp, "V3SetAttributes Unknown SMB Fid vcp 0x%p fid %d",
7080                  vcp, fid);
7081         return CM_ERROR_BADFD;
7082     }
7083     lock_ObtainMutex(&fidp->mx);
7084     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7085         lock_ReleaseMutex(&fidp->mx);
7086         smb_CloseFID(vcp, fidp, NULL, 0);
7087         smb_ReleaseFID(fidp);
7088         return CM_ERROR_NOSUCHFILE;
7089     }
7090
7091     if (fidp->flags & SMB_FID_IOCTL) {
7092         lock_ReleaseMutex(&fidp->mx);
7093         smb_ReleaseFID(fidp);
7094         return CM_ERROR_BADFD;
7095     }
7096     scp = fidp->scp;
7097     osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
7098     cm_HoldSCache(scp);
7099     lock_ReleaseMutex(&fidp->mx);
7100
7101     userp = smb_GetUserFromVCP(vcp, inp);
7102
7103     /* now prepare to call cm_setattr.  This message only sets various times,
7104      * and AFS only implements mtime, and we'll set the mtime if that's
7105      * requested.  The others we'll ignore.
7106      */
7107     searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
7108
7109     if (searchTime != 0) {
7110         cm_UnixTimeFromSearchTime(&unixTime, searchTime);
7111
7112         if ( unixTime != -1 ) {
7113             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
7114             attrs.clientModTime = unixTime;
7115             code = cm_SetAttr(scp, &attrs, userp, &req);
7116
7117             osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
7118         } else {
7119             osi_Log1(smb_logp, "**cm_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
7120         }
7121     }
7122     else
7123         code = 0;
7124
7125     cm_ReleaseSCache(scp);
7126     cm_ReleaseUser(userp);
7127     smb_ReleaseFID(fidp);
7128     return code;
7129 }
7130
7131 /* SMB_COM_WRITE_ANDX */
7132 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7133 {
7134     osi_hyper_t offset;
7135     long count, written = 0, total_written = 0;
7136     unsigned short fd;
7137     unsigned pid;
7138     smb_fid_t *fidp;
7139     smb_t *smbp = (smb_t*) inp;
7140     long code = 0;
7141     cm_scache_t *scp;
7142     cm_user_t *userp;
7143     char *op;
7144     int inDataBlockCount;
7145
7146     fd = smb_GetSMBParm(inp, 2);
7147     count = smb_GetSMBParm(inp, 10);
7148
7149     offset.HighPart = 0;
7150     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7151
7152     if (*inp->wctp == 14) {
7153         /* we have a request with 64-bit file offsets */
7154         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7155     }
7156
7157     op = inp->data + smb_GetSMBParm(inp, 11);
7158     inDataBlockCount = count;
7159
7160     osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
7161              fd, offset.HighPart, offset.LowPart, count);
7162
7163     fd = smb_ChainFID(fd, inp);
7164     fidp = smb_FindFID(vcp, fd, 0);
7165     if (!fidp) {
7166         osi_Log2(smb_logp, "smb_ReceiveV3WriteX Unknown SMB Fid vcp 0x%p fid %d",
7167                  vcp, fd);
7168         return CM_ERROR_BADFD;
7169     }
7170     lock_ObtainMutex(&fidp->mx);
7171     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7172         lock_ReleaseMutex(&fidp->mx);
7173         smb_CloseFID(vcp, fidp, NULL, 0);
7174         smb_ReleaseFID(fidp);
7175         return CM_ERROR_NOSUCHFILE;
7176     }
7177
7178     if (fidp->flags & SMB_FID_IOCTL) {
7179         lock_ReleaseMutex(&fidp->mx);
7180         code = smb_IoctlV3Write(fidp, vcp, inp, outp);
7181         smb_ReleaseFID(fidp);
7182         return code;
7183     }
7184
7185     if (fidp->flags & SMB_FID_RPC) {
7186         lock_ReleaseMutex(&fidp->mx);
7187         code = smb_RPCV3Write(fidp, vcp, inp, outp);
7188         smb_ReleaseFID(fidp);
7189         return code;
7190     }
7191
7192     if (!fidp->scp) {
7193         lock_ReleaseMutex(&fidp->mx);
7194         smb_ReleaseFID(fidp);
7195         return CM_ERROR_BADFDOP;
7196     }
7197
7198     scp = fidp->scp;
7199     cm_HoldSCache(scp);
7200     lock_ReleaseMutex(&fidp->mx);
7201
7202     userp = smb_GetUserFromVCP(vcp, inp);
7203
7204     /* special case: 0 bytes transferred means there is no data
7205        transferred.  A slight departure from SMB_COM_WRITE where this
7206        means that we are supposed to truncate the file at this
7207        position. */
7208
7209     {
7210         cm_key_t key;
7211         LARGE_INTEGER LOffset;
7212         LARGE_INTEGER LLength;
7213
7214         pid = smbp->pid;
7215         key = cm_GenerateKey(vcp->vcID, pid, fd);
7216
7217         LOffset.HighPart = offset.HighPart;
7218         LOffset.LowPart = offset.LowPart;
7219         LLength.HighPart = 0;
7220         LLength.LowPart = count;
7221
7222         lock_ObtainWrite(&scp->rw);
7223         code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7224         lock_ReleaseWrite(&scp->rw);
7225
7226         if (code)
7227             goto done;
7228     }
7229
7230     /*
7231      * Work around bug in NT client
7232      *
7233      * When copying a file, the NT client should first copy the data,
7234      * then copy the last write time.  But sometimes the NT client does
7235      * these in the wrong order, so the data copies would inadvertently
7236      * cause the last write time to be overwritten.  We try to detect this,
7237      * and don't set client mod time if we think that would go against the
7238      * intention.
7239      */
7240     lock_ObtainMutex(&fidp->mx);
7241     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7242         lock_ObtainWrite(&fidp->scp->rw);
7243         scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7244         scp->clientModTime = time(NULL);
7245         lock_ReleaseWrite(&fidp->scp->rw);
7246     }
7247     lock_ReleaseMutex(&fidp->mx);
7248
7249     code = 0;
7250     while ( code == 0 && count > 0 ) {
7251         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7252         if (code == 0 && written == 0)
7253             code = CM_ERROR_PARTIALWRITE;
7254
7255         offset = LargeIntegerAdd(offset,
7256                                  ConvertLongToLargeInteger(written));
7257         count -= written;
7258         total_written += written;
7259         written = 0;
7260     }
7261
7262     /* slots 0 and 1 are reserved for request chaining and will be
7263        filled in when we return. */
7264     smb_SetSMBParm(outp, 2, total_written);
7265     smb_SetSMBParm(outp, 3, 0); /* reserved */
7266     smb_SetSMBParm(outp, 4, 0); /* reserved */
7267     smb_SetSMBParm(outp, 5, 0); /* reserved */
7268     smb_SetSMBDataLength(outp, 0);
7269
7270  done:
7271
7272     cm_ReleaseSCache(scp);
7273     cm_ReleaseUser(userp);
7274     smb_ReleaseFID(fidp);
7275
7276     return code;
7277 }
7278
7279 /* SMB_COM_READ_ANDX */
7280 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7281 {
7282     osi_hyper_t offset;
7283     long count;
7284     long finalCount = 0;
7285     unsigned short fd;
7286     unsigned pid;
7287     smb_fid_t *fidp;
7288     smb_t *smbp = (smb_t*) inp;
7289     long code = 0;
7290     cm_scache_t *scp;
7291     cm_user_t *userp;
7292     cm_key_t key;
7293     char *op;
7294
7295     fd = smb_GetSMBParm(inp, 2); /* File ID */
7296     count = smb_GetSMBParm(inp, 5); /* MaxCount */
7297     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7298
7299     if (*inp->wctp == 12) {
7300         /* a request with 64-bit offsets */
7301         offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
7302
7303         if (LargeIntegerLessThanZero(offset)) {
7304             osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
7305                      offset.HighPart, offset.LowPart);
7306             return CM_ERROR_BADSMB;
7307         }
7308     } else {
7309         offset.HighPart = 0;
7310     }
7311
7312     osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
7313              fd, offset.HighPart, offset.LowPart, count);
7314
7315     fd = smb_ChainFID(fd, inp);
7316     fidp = smb_FindFID(vcp, fd, 0);
7317     if (!fidp) {
7318         osi_Log2(smb_logp, "smb_ReceiveV3Read Unknown SMB Fid vcp 0x%p fid %d",
7319                  vcp, fd);
7320         return CM_ERROR_BADFD;
7321     }
7322
7323     lock_ObtainMutex(&fidp->mx);
7324
7325     if (fidp->flags & SMB_FID_IOCTL) {
7326         lock_ReleaseMutex(&fidp->mx);
7327         inp->fid = fd;
7328         code = smb_IoctlV3Read(fidp, vcp, inp, outp);
7329         smb_ReleaseFID(fidp);
7330         return code;
7331     }
7332
7333     if (fidp->flags & SMB_FID_RPC) {
7334         lock_ReleaseMutex(&fidp->mx);
7335         inp->fid = fd;
7336         code = smb_RPCV3Read(fidp, vcp, inp, outp);
7337         smb_ReleaseFID(fidp);
7338         return code;
7339     }
7340
7341     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7342         lock_ReleaseMutex(&fidp->mx);
7343         smb_CloseFID(vcp, fidp, NULL, 0);
7344         smb_ReleaseFID(fidp);
7345         return CM_ERROR_NOSUCHFILE;
7346     }
7347
7348     if (!fidp->scp) {
7349         lock_ReleaseMutex(&fidp->mx);
7350         smb_ReleaseFID(fidp);
7351         return CM_ERROR_BADFDOP;
7352     }
7353
7354     scp = fidp->scp;
7355     cm_HoldSCache(scp);
7356
7357     lock_ReleaseMutex(&fidp->mx);
7358
7359     pid = smbp->pid;
7360     key = cm_GenerateKey(vcp->vcID, pid, fd);
7361     {
7362         LARGE_INTEGER LOffset, LLength;
7363
7364         LOffset.HighPart = offset.HighPart;
7365         LOffset.LowPart = offset.LowPart;
7366         LLength.HighPart = 0;
7367         LLength.LowPart = count;
7368
7369         lock_ObtainWrite(&scp->rw);
7370         code = cm_LockCheckRead(scp, LOffset, LLength, key);
7371         lock_ReleaseWrite(&scp->rw);
7372     }
7373     cm_ReleaseSCache(scp);
7374
7375     if (code) {
7376         smb_ReleaseFID(fidp);
7377         return code;
7378     }
7379
7380     /* set inp->fid so that later read calls in same msg can find fid */
7381     inp->fid = fd;
7382
7383     userp = smb_GetUserFromVCP(vcp, inp);
7384
7385     /* 0 and 1 are reserved for request chaining, were setup by our caller,
7386      * and will be further filled in after we return.
7387      */
7388     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
7389     smb_SetSMBParm(outp, 3, 0); /* resvd */
7390     smb_SetSMBParm(outp, 4, 0); /* resvd */
7391     smb_SetSMBParm(outp, 5, count);     /* # of bytes we're going to read */
7392     /* fill in #6 when we have all the parameters' space reserved */
7393     smb_SetSMBParm(outp, 7, 0); /* resv'd */
7394     smb_SetSMBParm(outp, 8, 0); /* resv'd */
7395     smb_SetSMBParm(outp, 9, 0); /* resv'd */
7396     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
7397     smb_SetSMBParm(outp, 11, 0);        /* reserved */
7398
7399     /* get op ptr after putting in the parms, since otherwise we don't
7400      * know where the data really is.
7401      */
7402     op = smb_GetSMBData(outp, NULL);
7403
7404     /* now fill in offset from start of SMB header to first data byte (to op) */
7405     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
7406
7407     /* set the packet data length the count of the # of bytes */
7408     smb_SetSMBDataLength(outp, count);
7409
7410     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7411
7412     /* fix some things up */
7413     smb_SetSMBParm(outp, 5, finalCount);
7414     smb_SetSMBDataLength(outp, finalCount);
7415
7416     cm_ReleaseUser(userp);
7417     smb_ReleaseFID(fidp);
7418     return code;
7419 }
7420
7421 /*
7422  * Values for createDisp, copied from NTDDK.H
7423  */
7424 #define  FILE_SUPERSEDE 0       // (???)
7425 #define  FILE_OPEN      1       // (open)
7426 #define  FILE_CREATE    2       // (exclusive)
7427 #define  FILE_OPEN_IF   3       // (non-exclusive)
7428 #define  FILE_OVERWRITE 4       // (open & truncate, but do not create)
7429 #define  FILE_OVERWRITE_IF 5    // (open & truncate, or create)
7430
7431 /* Flags field */
7432 #define REQUEST_OPLOCK 2
7433 #define REQUEST_BATCH_OPLOCK 4
7434 #define OPEN_DIRECTORY 8
7435 #define EXTENDED_RESPONSE_REQUIRED 0x10
7436
7437 /* CreateOptions field. */
7438 #define FILE_DIRECTORY_FILE       0x0001
7439 #define FILE_WRITE_THROUGH        0x0002
7440 #define FILE_SEQUENTIAL_ONLY      0x0004
7441 #define FILE_NON_DIRECTORY_FILE   0x0040
7442 #define FILE_NO_EA_KNOWLEDGE      0x0200
7443 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
7444 #define FILE_RANDOM_ACCESS        0x0800
7445 #define FILE_DELETE_ON_CLOSE      0x1000
7446 #define FILE_OPEN_BY_FILE_ID      0x2000
7447 #define FILE_OPEN_FOR_BACKUP_INTENT             0x00004000
7448 #define FILE_NO_COMPRESSION                     0x00008000
7449 #define FILE_RESERVE_OPFILTER                   0x00100000
7450 #define FILE_OPEN_REPARSE_POINT                 0x00200000
7451 #define FILE_OPEN_NO_RECALL                     0x00400000
7452 #define FILE_OPEN_FOR_FREE_SPACE_QUERY          0x00800000
7453
7454 /* SMB_COM_NT_CREATE_ANDX */
7455 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7456 {
7457     clientchar_t *pathp, *realPathp;
7458     long code = 0;
7459     cm_space_t *spacep;
7460     cm_user_t *userp;
7461     cm_scache_t *dscp;          /* parent dir */
7462     cm_scache_t *scp;           /* file to create or open */
7463     cm_scache_t *targetScp;     /* if scp is a symlink */
7464     cm_attr_t setAttr;
7465     clientchar_t *lastNamep;
7466     clientchar_t *treeStartp;
7467     unsigned short nameLength;
7468     unsigned int flags;
7469     unsigned int requestOpLock;
7470     unsigned int requestBatchOpLock;
7471     unsigned int mustBeDir;
7472     unsigned int extendedRespRequired;
7473     unsigned int treeCreate;
7474     int realDirFlag;
7475     unsigned int desiredAccess;
7476     unsigned int extAttributes;
7477     unsigned int createDisp;
7478     unsigned int createOptions;
7479     unsigned int shareAccess;
7480     unsigned short baseFid;
7481     smb_fid_t *baseFidp;
7482     smb_fid_t *fidp;
7483     cm_scache_t *baseDirp;
7484     unsigned short openAction;
7485     int parmSlot;
7486     long fidflags;
7487     FILETIME ft;
7488     LARGE_INTEGER sz;
7489     clientchar_t *tidPathp;
7490     BOOL foundscp;
7491     cm_req_t req;
7492     int created = 0;
7493     int prefetch = 0;
7494     int checkDoneRequired = 0;
7495     cm_lock_data_t *ldp = NULL;
7496     BOOL is_rpc = FALSE;
7497     BOOL is_ipc = FALSE;
7498
7499     smb_InitReq(&req);
7500
7501     /* This code is very long and has a lot of if-then-else clauses
7502      * scp and dscp get reused frequently and we need to ensure that
7503      * we don't lose a reference.  Start by ensuring that they are NULL.
7504      */
7505     scp = NULL;
7506     dscp = NULL;
7507     treeCreate = FALSE;
7508     foundscp = FALSE;
7509
7510     nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
7511     flags = smb_GetSMBOffsetParm(inp, 3, 1)
7512         | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
7513     requestOpLock = flags & REQUEST_OPLOCK;
7514     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7515     mustBeDir = flags & OPEN_DIRECTORY;
7516     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7517
7518     /*
7519      * Why all of a sudden 32-bit FID?
7520      * We will reject all bits higher than 16.
7521      */
7522     if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
7523         return CM_ERROR_INVAL;
7524     baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
7525     desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
7526         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7527     extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
7528         | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
7529     shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
7530         | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
7531     createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
7532         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
7533     createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
7534         | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
7535
7536     /* mustBeDir is never set; createOptions directory bit seems to be
7537      * more important
7538      */
7539     if (createOptions & FILE_DIRECTORY_FILE)
7540         realDirFlag = 1;
7541     else if (createOptions & FILE_NON_DIRECTORY_FILE)
7542         realDirFlag = 0;
7543     else
7544         realDirFlag = -1;
7545
7546     pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
7547                               NULL, SMB_STRF_ANSIPATH);
7548
7549     /* Sometimes path is not null-terminated, so we make a copy. */
7550     realPathp = malloc(nameLength+sizeof(clientchar_t));
7551     memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
7552     realPathp[nameLength/sizeof(clientchar_t)] = 0;
7553
7554     spacep = inp->spacep;
7555     /* smb_StripLastComponent will strip "::$DATA" if present */
7556     smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7557
7558     osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
7559     osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
7560     osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
7561
7562     if (baseFid == 0) {
7563         baseFidp = NULL;
7564         baseDirp = cm_RootSCachep(cm_rootUserp, &req);
7565         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7566         if (code == CM_ERROR_TIDIPC) {
7567             /* Attempt to use a TID allocated for IPC.  The client
7568              * is probably looking for DCE RPC end points which we
7569              * don't support OR it could be looking to make a DFS
7570              * referral request.
7571              */
7572             osi_Log0(smb_logp, "NTCreateX received IPC TID");
7573             is_ipc = TRUE;
7574         }
7575     }
7576
7577     osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
7578
7579     if (lastNamep &&
7580
7581         ((is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)) ||
7582
7583          /* special case magic file name for receiving IOCTL requests
7584           * (since IOCTL calls themselves aren't getting through).
7585           */
7586          cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0)) {
7587
7588         unsigned short file_type = 0;
7589         unsigned short device_state = 0;
7590
7591         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7592
7593         if (is_rpc) {
7594             code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
7595             osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
7596             if (code) {
7597                 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
7598                 smb_ReleaseFID(fidp);
7599                 free(realPathp);
7600                 return code;
7601             }
7602         } else {
7603             smb_SetupIoctlFid(fidp, spacep);
7604             osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
7605         }
7606
7607         /* set inp->fid so that later read calls in same msg can find fid */
7608         inp->fid = fidp->fid;
7609
7610         /* out parms */
7611         parmSlot = 2;
7612         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
7613         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7614         smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
7615         /* times */
7616         memset(&ft, 0, sizeof(ft));
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_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7621         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
7622         sz.HighPart = 0x7fff; sz.LowPart = 0;
7623         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
7624         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
7625         smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;  /* filetype */
7626         smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;       /* dev state */
7627         smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
7628         smb_SetSMBDataLength(outp, 0);
7629
7630         /* clean up fid reference */
7631         smb_ReleaseFID(fidp);
7632         free(realPathp);
7633         return 0;
7634     }
7635
7636 #ifndef DFS_SUPPORT
7637     if (is_ipc) {
7638         osi_Log0(smb_logp, "NTCreateX rejecting IPC TID");
7639         free(realPathp);
7640         return CM_ERROR_BADFD;
7641     }
7642 #endif
7643
7644     if (!cm_IsValidClientString(realPathp)) {
7645 #ifdef DEBUG
7646         clientchar_t * hexp;
7647
7648         hexp = cm_GetRawCharsAlloc(realPathp, -1);
7649         osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
7650                  osi_LogSaveClientString(smb_logp, hexp));
7651         if (hexp)
7652             free(hexp);
7653 #else
7654         osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
7655 #endif
7656         free(realPathp);
7657         return CM_ERROR_BADNTFILENAME;
7658     }
7659
7660     userp = smb_GetUserFromVCP(vcp, inp);
7661     if (!userp) {
7662         osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
7663         free(realPathp);
7664         return CM_ERROR_INVAL;
7665     }
7666
7667     if (baseFidp != 0) {
7668         baseFidp = smb_FindFID(vcp, baseFid, 0);
7669         if (!baseFidp) {
7670             osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
7671             cm_ReleaseUser(userp);
7672             free(realPathp);
7673             return CM_ERROR_INVAL;
7674         }
7675
7676         if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7677             free(realPathp);
7678             smb_CloseFID(vcp, baseFidp, NULL, 0);
7679             smb_ReleaseFID(baseFidp);
7680             cm_ReleaseUser(userp);
7681             return CM_ERROR_NOSUCHPATH;
7682         }
7683
7684         baseDirp = baseFidp->scp;
7685         tidPathp = NULL;
7686     }
7687
7688     /* compute open mode */
7689     fidflags = 0;
7690     if (desiredAccess & DELETE)
7691         fidflags |= SMB_FID_OPENDELETE;
7692     if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7693         fidflags |= SMB_FID_OPENREAD_LISTDIR;
7694     if (desiredAccess & AFS_ACCESS_WRITE)
7695         fidflags |= SMB_FID_OPENWRITE;
7696     if (createOptions & FILE_DELETE_ON_CLOSE)
7697         fidflags |= SMB_FID_DELONCLOSE;
7698     if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7699         fidflags |= SMB_FID_SEQUENTIAL;
7700     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7701         fidflags |= SMB_FID_RANDOM;
7702     if (createOptions & FILE_OPEN_REPARSE_POINT)
7703         osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7704     if (smb_IsExecutableFileName(lastNamep))
7705         fidflags |= SMB_FID_EXECUTABLE;
7706
7707     /* and the share mode */
7708     if (shareAccess & FILE_SHARE_READ)
7709         fidflags |= SMB_FID_SHARE_READ;
7710     if (shareAccess & FILE_SHARE_WRITE)
7711         fidflags |= SMB_FID_SHARE_WRITE;
7712
7713     osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7714     code = 0;
7715
7716     /* For an exclusive create, we want to do a case sensitive match for the last component. */
7717     if ( createDisp == FILE_CREATE ||
7718          createDisp == FILE_OVERWRITE ||
7719          createDisp == FILE_OVERWRITE_IF) {
7720         code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7721                         userp, tidPathp, &req, &dscp);
7722         if (code == 0) {
7723 #ifdef DFS_SUPPORT
7724             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7725                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7726                                                           spacep->wdata);
7727                 cm_ReleaseSCache(dscp);
7728                 cm_ReleaseUser(userp);
7729                 free(realPathp);
7730                 if (baseFidp)
7731                     smb_ReleaseFID(baseFidp);
7732                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7733                     return CM_ERROR_PATH_NOT_COVERED;
7734                 else
7735                     return CM_ERROR_NOSUCHPATH;
7736             }
7737 #endif /* DFS_SUPPORT */
7738             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7739                              userp, &req, &scp);
7740             if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7741                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7742                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7743                 if (code == 0 && realDirFlag == 1) {
7744                     cm_ReleaseSCache(scp);
7745                     cm_ReleaseSCache(dscp);
7746                     cm_ReleaseUser(userp);
7747                     free(realPathp);
7748                     if (baseFidp)
7749                         smb_ReleaseFID(baseFidp);
7750                     return CM_ERROR_EXISTS;
7751                 }
7752             }
7753             /* we have both scp and dscp */
7754         }
7755     } else {
7756         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7757                         userp, tidPathp, &req, &scp);
7758 #ifdef DFS_SUPPORT
7759         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7760             int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7761             cm_ReleaseSCache(scp);
7762             cm_ReleaseUser(userp);
7763             free(realPathp);
7764             if (baseFidp)
7765                 smb_ReleaseFID(baseFidp);
7766             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7767                 return CM_ERROR_PATH_NOT_COVERED;
7768             else
7769                 return CM_ERROR_NOSUCHPATH;
7770         }
7771 #endif /* DFS_SUPPORT */
7772         /* we might have scp but not dscp */
7773     }
7774
7775     if (code &&
7776         code != CM_ERROR_NOSUCHFILE &&
7777         code != CM_ERROR_NOSUCHPATH &&
7778         code != CM_ERROR_BPLUS_NOMATCH) {
7779         cm_ReleaseUser(userp);
7780         free(realPathp);
7781         if (baseFidp)
7782             smb_ReleaseFID(baseFidp);
7783         return code;
7784     }
7785
7786     if (scp)
7787         foundscp = TRUE;
7788
7789     if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7790         /* look up parent directory */
7791         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7792          * the immediate parent.  We have to work our way up realPathp until we hit something that we
7793          * recognize.
7794          */
7795
7796         /* we might or might not have scp */
7797
7798         if (dscp == NULL) {
7799             do {
7800                 clientchar_t *tp;
7801
7802                 code = cm_NameI(baseDirp, spacep->wdata,
7803                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7804                                 userp, tidPathp, &req, &dscp);
7805
7806 #ifdef DFS_SUPPORT
7807                 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7808                     int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7809                                                               spacep->wdata);
7810                     if (scp)
7811                         cm_ReleaseSCache(scp);
7812                     cm_ReleaseSCache(dscp);
7813                     cm_ReleaseUser(userp);
7814                     free(realPathp);
7815                     if (baseFidp)
7816                         smb_ReleaseFID(baseFidp);
7817                     if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7818                         return CM_ERROR_PATH_NOT_COVERED;
7819                     else
7820                         return CM_ERROR_NOSUCHPATH;
7821                 }
7822 #endif /* DFS_SUPPORT */
7823
7824                 if (code &&
7825                     (code == CM_ERROR_NOSUCHFILE ||
7826                      code == CM_ERROR_NOSUCHPATH ||
7827                      code == CM_ERROR_BPLUS_NOMATCH) &&
7828                     (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7829                     (createDisp == FILE_CREATE) &&
7830                     (realDirFlag == 1)) {
7831                     *tp++ = 0;
7832                     treeCreate = TRUE;
7833                     treeStartp = realPathp + (tp - spacep->wdata);
7834
7835                     if (*tp && !smb_IsLegalFilename(tp)) {
7836                         cm_ReleaseUser(userp);
7837                         if (baseFidp)
7838                             smb_ReleaseFID(baseFidp);
7839                         free(realPathp);
7840                         if (scp)
7841                             cm_ReleaseSCache(scp);
7842                         return CM_ERROR_BADNTFILENAME;
7843                     }
7844                     code = 0;
7845                 }
7846             } while (dscp == NULL && code == 0);
7847         } else
7848             code = 0;
7849
7850         /* we might have scp and we might have dscp */
7851
7852         if (baseFidp)
7853             smb_ReleaseFID(baseFidp);
7854
7855         if (code) {
7856             osi_Log0(smb_logp,"NTCreateX parent not found");
7857             if (scp)
7858                 cm_ReleaseSCache(scp);
7859             if (dscp)
7860                 cm_ReleaseSCache(dscp);
7861             cm_ReleaseUser(userp);
7862             free(realPathp);
7863             return code;
7864         }
7865
7866         if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7867             /* A file exists where we want a directory. */
7868             if (scp)
7869                 cm_ReleaseSCache(scp);
7870             cm_ReleaseSCache(dscp);
7871             cm_ReleaseUser(userp);
7872             free(realPathp);
7873             return CM_ERROR_EXISTS;
7874         }
7875
7876         if (!lastNamep)
7877             lastNamep = realPathp;
7878         else
7879             lastNamep++;
7880
7881         if (!smb_IsLegalFilename(lastNamep)) {
7882             if (scp)
7883                 cm_ReleaseSCache(scp);
7884             if (dscp)
7885                 cm_ReleaseSCache(dscp);
7886             cm_ReleaseUser(userp);
7887             free(realPathp);
7888             return CM_ERROR_BADNTFILENAME;
7889         }
7890
7891         if (!foundscp && !treeCreate) {
7892             if ( createDisp == FILE_CREATE ||
7893                  createDisp == FILE_OVERWRITE ||
7894                  createDisp == FILE_OVERWRITE_IF)
7895             {
7896                 code = cm_Lookup(dscp, lastNamep,
7897                                   CM_FLAG_FOLLOW, userp, &req, &scp);
7898             } else {
7899                 code = cm_Lookup(dscp, lastNamep,
7900                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7901                                  userp, &req, &scp);
7902             }
7903             if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7904                 if (dscp)
7905                     cm_ReleaseSCache(dscp);
7906                 cm_ReleaseUser(userp);
7907                 free(realPathp);
7908                 return code;
7909             }
7910         }
7911         /* we have scp and dscp */
7912     } else {
7913         /* we have scp but not dscp */
7914         if (baseFidp)
7915             smb_ReleaseFID(baseFidp);
7916     }
7917
7918     /* if we get here, if code is 0, the file exists and is represented by
7919      * scp.  Otherwise, we have to create it.  The dir may be represented
7920      * by dscp, or we may have found the file directly.  If code is non-zero,
7921      * scp is NULL.
7922      */
7923
7924     /*
7925      * open the file itself
7926      * allocate the fidp early so the smb fid can be used by cm_CheckNTOpen()
7927      */
7928     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7929     osi_assertx(fidp, "null smb_fid_t");
7930
7931     /* save a reference to the user */
7932     cm_HoldUser(userp);
7933     fidp->userp = userp;
7934
7935     if (code == 0 && !treeCreate) {
7936         code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
7937         if (code) {
7938             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7939             if (dscp)
7940                 cm_ReleaseSCache(dscp);
7941             if (scp)
7942                 cm_ReleaseSCache(scp);
7943             cm_ReleaseUser(userp);
7944             smb_CloseFID(vcp, fidp, NULL, 0);
7945             smb_ReleaseFID(fidp);
7946             free(realPathp);
7947             return code;
7948         }
7949         checkDoneRequired = 1;
7950
7951         if (createDisp == FILE_CREATE) {
7952             /* oops, file shouldn't be there */
7953             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7954             if (dscp)
7955                 cm_ReleaseSCache(dscp);
7956             if (scp)
7957                 cm_ReleaseSCache(scp);
7958             cm_ReleaseUser(userp);
7959             smb_CloseFID(vcp, fidp, NULL, 0);
7960             smb_ReleaseFID(fidp);
7961             free(realPathp);
7962             return CM_ERROR_EXISTS;
7963         }
7964
7965         if ( createDisp == FILE_OVERWRITE ||
7966              createDisp == FILE_OVERWRITE_IF) {
7967
7968             setAttr.mask = CM_ATTRMASK_LENGTH;
7969             setAttr.length.LowPart = 0;
7970             setAttr.length.HighPart = 0;
7971             /* now watch for a symlink */
7972             code = 0;
7973             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7974                 targetScp = 0;
7975                 osi_assertx(dscp != NULL, "null cm_scache_t");
7976                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7977                 if (code == 0) {
7978                     /* we have a more accurate file to use (the
7979                      * target of the symbolic link).  Otherwise,
7980                      * we'll just use the symlink anyway.
7981                      */
7982                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
7983                               scp, targetScp);
7984                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7985                     cm_ReleaseSCache(scp);
7986                     scp = targetScp;
7987                     code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
7988                     if (code) {
7989                         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7990                         if (dscp)
7991                             cm_ReleaseSCache(dscp);
7992                         if (scp)
7993                             cm_ReleaseSCache(scp);
7994                         cm_ReleaseUser(userp);
7995                         smb_CloseFID(vcp, fidp, NULL, 0);
7996                         smb_ReleaseFID(fidp);
7997                         free(realPathp);
7998                         return code;
7999                     }
8000                 }
8001             }
8002             code = cm_SetAttr(scp, &setAttr, userp, &req);
8003             openAction = 3;     /* truncated existing file */
8004         }
8005         else
8006             openAction = 1;     /* found existing file */
8007
8008     } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8009         /* don't create if not found */
8010         if (dscp)
8011             cm_ReleaseSCache(dscp);
8012         if (scp)
8013             cm_ReleaseSCache(scp);
8014         cm_ReleaseUser(userp);
8015         smb_CloseFID(vcp, fidp, NULL, 0);
8016         smb_ReleaseFID(fidp);
8017         free(realPathp);
8018         return CM_ERROR_NOSUCHFILE;
8019     } else if (realDirFlag == 0 || realDirFlag == -1) {
8020         osi_assertx(dscp != NULL, "null cm_scache_t");
8021         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
8022                   osi_LogSaveClientString(smb_logp, lastNamep));
8023         openAction = 2;         /* created file */
8024         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8025         setAttr.clientModTime = time(NULL);
8026         smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
8027
8028         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
8029         if (code == 0) {
8030             created = 1;
8031             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8032                 smb_NotifyChange(FILE_ACTION_ADDED,
8033                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8034                                  dscp, lastNamep, NULL, TRUE);
8035         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8036             /* Not an exclusive create, and someone else tried
8037              * creating it already, then we open it anyway.  We
8038              * don't bother retrying after this, since if this next
8039              * fails, that means that the file was deleted after we
8040              * started this call.
8041              */
8042             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8043                               userp, &req, &scp);
8044             if (code == 0) {
8045                 if (createDisp == FILE_OVERWRITE_IF) {
8046                     setAttr.mask = CM_ATTRMASK_LENGTH;
8047                     setAttr.length.LowPart = 0;
8048                     setAttr.length.HighPart = 0;
8049
8050                     /* now watch for a symlink */
8051                     code = 0;
8052                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8053                         targetScp = 0;
8054                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8055                         if (code == 0) {
8056                             /* we have a more accurate file to use (the
8057                              * target of the symbolic link).  Otherwise,
8058                              * we'll just use the symlink anyway.
8059                              */
8060                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
8061                                       scp, targetScp);
8062                             cm_ReleaseSCache(scp);
8063                             scp = targetScp;
8064                         }
8065                     }
8066                     code = cm_SetAttr(scp, &setAttr, userp, &req);
8067                 }
8068             }   /* lookup succeeded */
8069         }
8070     } else {
8071         clientchar_t *tp, *pp;
8072         clientchar_t *cp; /* This component */
8073         int clen = 0; /* length of component */
8074         cm_scache_t *tscp1, *tscp2;
8075         int isLast = 0;
8076
8077         /* create directory */
8078         if ( !treeCreate )
8079             treeStartp = lastNamep;
8080         osi_assertx(dscp != NULL, "null cm_scache_t");
8081         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
8082                   osi_LogSaveClientString(smb_logp, treeStartp));
8083         openAction = 2;         /* created directory */
8084
8085         /* if the request is to create the root directory
8086          * it will appear as a directory name of the nul-string
8087          * and a code of CM_ERROR_NOSUCHFILE
8088          */
8089         if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
8090             code = CM_ERROR_EXISTS;
8091
8092         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8093         setAttr.clientModTime = time(NULL);
8094         smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
8095
8096         pp = treeStartp;
8097         cp = spacep->wdata;
8098         tscp1 = dscp;
8099         cm_HoldSCache(tscp1);
8100         tscp2 = NULL;
8101
8102         while (pp && *pp) {
8103             tp = cm_ClientStrChr(pp, '\\');
8104             if (!tp) {
8105                 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
8106                 clen = (int)cm_ClientStrLen(cp);
8107                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
8108             } else {
8109                 clen = (int)(tp - pp);
8110                 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
8111                                  pp, clen);
8112                 *(cp + clen) = 0;
8113                 tp++;
8114             }
8115             pp = tp;
8116
8117             if (clen == 0)
8118                 continue; /* the supplied path can't have consecutive slashes either , but */
8119
8120             /* cp is the next component to be created. */
8121             code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
8122             if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
8123                 smb_NotifyChange(FILE_ACTION_ADDED,
8124                                  FILE_NOTIFY_CHANGE_DIR_NAME,
8125                                  tscp1, cp, NULL, TRUE);
8126             if (code == 0 ||
8127                 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8128                 /* Not an exclusive create, and someone else tried
8129                  * creating it already, then we open it anyway.  We
8130                  * don't bother retrying after this, since if this next
8131                  * fails, that means that the file was deleted after we
8132                  * started this call.
8133                  */
8134                 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
8135                                  userp, &req, &tscp2);
8136             }
8137             if (code)
8138                 break;
8139
8140             if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
8141                 cm_ReleaseSCache(tscp1);
8142                 tscp1 = tscp2; /* Newly created directory will be next parent */
8143                 /* the hold is transfered to tscp1 from tscp2 */
8144             }
8145         }
8146
8147         if (dscp)
8148             cm_ReleaseSCache(dscp);
8149         dscp = tscp1;
8150         if (scp)
8151             cm_ReleaseSCache(scp);
8152         scp = tscp2;
8153         /*
8154          * if we get here and code == 0, then scp is the last directory created, and dscp is the
8155          * parent of scp.
8156          */
8157     }
8158
8159     if (code) {
8160         /* something went wrong creating or truncating the file */
8161         if (checkDoneRequired)
8162             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8163         if (scp)
8164             cm_ReleaseSCache(scp);
8165         if (dscp)
8166             cm_ReleaseSCache(dscp);
8167         cm_ReleaseUser(userp);
8168         smb_CloseFID(vcp, fidp, NULL, 0);
8169         smb_ReleaseFID(fidp);
8170         free(realPathp);
8171         return code;
8172     }
8173
8174     /* make sure we have file vs. dir right (only applies for single component case) */
8175     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8176         /* now watch for a symlink */
8177         code = 0;
8178         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8179             cm_scache_t * targetScp = 0;
8180             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8181             if (code == 0) {
8182                 /* we have a more accurate file to use (the
8183                 * target of the symbolic link).  Otherwise,
8184                 * we'll just use the symlink anyway.
8185                 */
8186                 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
8187                 if (checkDoneRequired) {
8188                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8189                     checkDoneRequired = 0;
8190                 }
8191                 cm_ReleaseSCache(scp);
8192                 scp = targetScp;
8193             }
8194         }
8195
8196         if (scp->fileType != CM_SCACHETYPE_FILE) {
8197             if (checkDoneRequired)
8198                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8199             if (dscp)
8200                 cm_ReleaseSCache(dscp);
8201             cm_ReleaseSCache(scp);
8202             cm_ReleaseUser(userp);
8203             smb_CloseFID(vcp, fidp, NULL, 0);
8204             smb_ReleaseFID(fidp);
8205             free(realPathp);
8206             return CM_ERROR_ISDIR;
8207         }
8208     }
8209
8210     /* (only applies to single component case) */
8211     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8212         if (checkDoneRequired)
8213             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8214         cm_ReleaseSCache(scp);
8215         if (dscp)
8216             cm_ReleaseSCache(dscp);
8217         cm_ReleaseUser(userp);
8218         smb_CloseFID(vcp, fidp, NULL, 0);
8219         smb_ReleaseFID(fidp);
8220         free(realPathp);
8221         return CM_ERROR_NOTDIR;
8222     }
8223
8224     /* If we are restricting sharing, we should do so with a suitable
8225        share lock. */
8226     if (scp->fileType == CM_SCACHETYPE_FILE &&
8227         !(fidflags & SMB_FID_SHARE_WRITE)) {
8228         cm_key_t key;
8229         LARGE_INTEGER LOffset, LLength;
8230         int sLockType;
8231
8232         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8233         LOffset.LowPart = SMB_FID_QLOCK_LOW;
8234         LLength.HighPart = 0;
8235         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8236
8237         /* If we are not opening the file for writing, then we don't
8238            try to get an exclusive lock.  No one else should be able to
8239            get an exclusive lock on the file anyway, although someone
8240            else can get a shared lock. */
8241         if ((fidflags & SMB_FID_SHARE_READ) ||
8242             !(fidflags & SMB_FID_OPENWRITE)) {
8243             sLockType = LOCKING_ANDX_SHARED_LOCK;
8244         } else {
8245             sLockType = 0;
8246         }
8247
8248         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8249
8250         lock_ObtainWrite(&scp->rw);
8251         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8252         lock_ReleaseWrite(&scp->rw);
8253
8254         if (code) {
8255             if (checkDoneRequired)
8256                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8257             cm_ReleaseSCache(scp);
8258             if (dscp)
8259                 cm_ReleaseSCache(dscp);
8260             cm_ReleaseUser(userp);
8261             smb_CloseFID(vcp, fidp, NULL, 0);
8262             smb_ReleaseFID(fidp);
8263             free(realPathp);
8264             return CM_ERROR_SHARING_VIOLATION;
8265         }
8266     }
8267
8268     /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
8269     if (checkDoneRequired) {
8270         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8271         checkDoneRequired = 0;
8272     }
8273
8274     lock_ObtainMutex(&fidp->mx);
8275     /* save a pointer to the vnode */
8276     fidp->scp = scp;    /* Hold transfered to fidp->scp and no longer needed */
8277     lock_ObtainWrite(&scp->rw);
8278     scp->flags |= CM_SCACHEFLAG_SMB_FID;
8279     lock_ReleaseWrite(&scp->rw);
8280     osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
8281
8282     fidp->flags = fidflags;
8283
8284     /* remember if the file was newly created */
8285     if (created)
8286         fidp->flags |= SMB_FID_CREATED;
8287
8288     /* save parent dir and pathname for delete or change notification */
8289     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8290         osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
8291         fidp->flags |= SMB_FID_NTOPEN;
8292         fidp->NTopen_dscp = dscp;
8293         dscp = NULL;
8294         fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8295     }
8296     fidp->NTopen_wholepathp = realPathp;
8297     lock_ReleaseMutex(&fidp->mx);
8298
8299     /* we don't need this any longer */
8300     if (dscp) {
8301         cm_ReleaseSCache(dscp);
8302         dscp = NULL;
8303     }
8304
8305     cm_Open(scp, 0, userp);
8306
8307     /* set inp->fid so that later read calls in same msg can find fid */
8308     inp->fid = fidp->fid;
8309
8310     lock_ObtainRead(&scp->rw);
8311
8312     /*
8313      * Always send the standard response.  Sending the extended
8314      * response results in the Explorer Shell being unable to
8315      * access directories at random times.
8316      */
8317     if (1 /*!extendedRespRequired */) {
8318         /* out parms */
8319         parmSlot = 2;
8320         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
8321         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8322         smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8323         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
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_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8328         smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8329         parmSlot += 2;
8330         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8331         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8332         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
8333         smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8334         parmSlot++;     /* dev state */
8335         smb_SetSMBParmByte(outp, parmSlot,
8336                             (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8337                               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8338                               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8339         smb_SetSMBDataLength(outp, 0);
8340     } else {
8341         /* out parms */
8342         parmSlot = 2;
8343         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
8344         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8345         smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8346         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
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_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8351         smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8352         parmSlot += 2;
8353         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8354         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8355         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
8356         smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8357         parmSlot++;     /* dev state */
8358         smb_SetSMBParmByte(outp, parmSlot,
8359                             (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8360                               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8361                               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8362         /* Setting the GUID results in a failure with cygwin */
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         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8369         /* Maxmimal access rights */
8370         smb_SetSMBParmLong(outp, parmSlot, 0x001f01ff); parmSlot += 2;
8371         /* Guest access rights */
8372         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8373         smb_SetSMBDataLength(outp, 0);
8374     }
8375
8376     if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8377         LargeIntegerGreaterThanZero(scp->length) &&
8378         !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8379         prefetch = 1;
8380     }
8381     lock_ReleaseRead(&scp->rw);
8382
8383     if (prefetch)
8384         cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8385                            scp->length.LowPart, scp->length.HighPart,
8386                            userp, &req);
8387
8388
8389     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
8390               osi_LogSaveClientString(smb_logp, realPathp));
8391
8392     cm_ReleaseUser(userp);
8393     smb_ReleaseFID(fidp);
8394
8395     /* Can't free realPathp if we get here since
8396        fidp->NTopen_wholepathp is pointing there */
8397
8398     /* leave scp held since we put it in fidp->scp */
8399     return 0;
8400 }
8401
8402 /*
8403  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
8404  * Instead, ultimately, would like to use a subroutine for common code.
8405  */
8406
8407 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
8408 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8409 {
8410     clientchar_t *pathp, *realPathp;
8411     long code = 0;
8412     cm_space_t *spacep;
8413     cm_user_t *userp;
8414     cm_scache_t *dscp;          /* parent dir */
8415     cm_scache_t *scp;           /* file to create or open */
8416     cm_scache_t *targetScp;     /* if scp is a symlink */
8417     cm_attr_t setAttr;
8418     clientchar_t *lastNamep;
8419     unsigned long nameLength;
8420     unsigned int flags;
8421     unsigned int requestOpLock;
8422     unsigned int requestBatchOpLock;
8423     unsigned int mustBeDir;
8424     unsigned int extendedRespRequired;
8425     int realDirFlag;
8426     unsigned int desiredAccess;
8427     unsigned int allocSize;
8428     unsigned int shareAccess;
8429     unsigned int extAttributes;
8430     unsigned int createDisp;
8431     unsigned int sdLen;
8432     unsigned int eaLen;
8433     unsigned int impLevel;
8434     unsigned int secFlags;
8435     unsigned int createOptions;
8436     unsigned short baseFid;
8437     smb_fid_t *baseFidp;
8438     smb_fid_t *fidp;
8439     cm_scache_t *baseDirp;
8440     unsigned short openAction;
8441     int parmSlot;
8442     long fidflags;
8443     FILETIME ft;
8444     clientchar_t *tidPathp;
8445     BOOL foundscp;
8446     int parmOffset, dataOffset;
8447     char *parmp;
8448     ULONG *lparmp;
8449     char *outData;
8450     cm_req_t req;
8451     int created = 0;
8452     int prefetch = 0;
8453     cm_lock_data_t *ldp = NULL;
8454     int checkDoneRequired = 0;
8455
8456     smb_InitReq(&req);
8457
8458     foundscp = FALSE;
8459     scp = NULL;
8460
8461     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8462         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8463     parmp = inp->data + parmOffset;
8464     lparmp = (ULONG *) parmp;
8465
8466     flags = lparmp[0];
8467     requestOpLock = flags & REQUEST_OPLOCK;
8468     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
8469     mustBeDir = flags & OPEN_DIRECTORY;
8470     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
8471
8472     /*
8473      * Why all of a sudden 32-bit FID?
8474      * We will reject all bits higher than 16.
8475      */
8476     if (lparmp[1] & 0xFFFF0000)
8477         return CM_ERROR_INVAL;
8478     baseFid = (unsigned short)lparmp[1];
8479     desiredAccess = lparmp[2];
8480     allocSize = lparmp[3];
8481     extAttributes = lparmp[5];
8482     shareAccess = lparmp[6];
8483     createDisp = lparmp[7];
8484     createOptions = lparmp[8];
8485     sdLen = lparmp[9];
8486     eaLen = lparmp[10];
8487     nameLength = lparmp[11];    /* spec says chars but appears to be bytes */
8488     impLevel = lparmp[12];
8489     secFlags = lparmp[13];
8490
8491     /* mustBeDir is never set; createOptions directory bit seems to be
8492      * more important
8493      */
8494     if (createOptions & FILE_DIRECTORY_FILE)
8495         realDirFlag = 1;
8496     else if (createOptions & FILE_NON_DIRECTORY_FILE)
8497         realDirFlag = 0;
8498     else
8499         realDirFlag = -1;
8500
8501     pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
8502                                nameLength, NULL, SMB_STRF_ANSIPATH);
8503     /* Sometimes path is not nul-terminated, so we make a copy. */
8504     realPathp = malloc(nameLength+sizeof(clientchar_t));
8505     memcpy(realPathp, pathp, nameLength);
8506     realPathp[nameLength/sizeof(clientchar_t)] = 0;
8507     spacep = cm_GetSpace();
8508     /* smb_StripLastComponent will strip "::$DATA" if present */
8509     smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
8510
8511     osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
8512     osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
8513     osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
8514     osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
8515
8516     if ( realDirFlag == 1 &&
8517          ( createDisp == FILE_SUPERSEDE ||
8518            createDisp == FILE_OVERWRITE ||
8519            createDisp == FILE_OVERWRITE_IF))
8520     {
8521         osi_Log0(smb_logp, "NTTranCreate rejecting invalid readDirFlag and createDisp combination");
8522         cm_FreeSpace(spacep);
8523         free(realPathp);
8524         return CM_ERROR_INVAL;
8525     }
8526
8527     /*
8528      * Nothing here to handle SMB_IOCTL_FILENAME.
8529      * Will add it if necessary.
8530      */
8531
8532     if (!cm_IsValidClientString(realPathp)) {
8533 #ifdef DEBUG
8534         clientchar_t * hexp;
8535
8536         hexp = cm_GetRawCharsAlloc(realPathp, -1);
8537         osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
8538                  osi_LogSaveClientString(smb_logp, hexp));
8539         if (hexp)
8540         free(hexp);
8541 #else
8542         osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
8543 #endif
8544         cm_FreeSpace(spacep);
8545         free(realPathp);
8546         return CM_ERROR_BADNTFILENAME;
8547     }
8548
8549     userp = smb_GetUserFromVCP(vcp, inp);
8550     if (!userp) {
8551         osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
8552         cm_FreeSpace(spacep);
8553         free(realPathp);
8554         return CM_ERROR_INVAL;
8555     }
8556
8557     if (baseFid == 0) {
8558         baseFidp = NULL;
8559         baseDirp = cm_RootSCachep(cm_rootUserp, &req);
8560         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8561         if (code == CM_ERROR_TIDIPC) {
8562             /* Attempt to use a TID allocated for IPC.  The client
8563              * is probably looking for DCE RPC end points which we
8564              * don't support OR it could be looking to make a DFS
8565              * referral request.
8566              */
8567             osi_Log0(smb_logp, "NTTranCreate received IPC TID");
8568 #ifndef DFS_SUPPORT
8569             cm_FreeSpace(spacep);
8570             free(realPathp);
8571             cm_ReleaseUser(userp);
8572             return CM_ERROR_NOSUCHPATH;
8573 #endif
8574         }
8575     } else {
8576         baseFidp = smb_FindFID(vcp, baseFid, 0);
8577         if (!baseFidp) {
8578             osi_Log2(smb_logp, "NTTranCreate Unknown SMB Fid vcp 0x%p fid %d",
8579                       vcp, baseFid);
8580             cm_FreeSpace(spacep);
8581             free(realPathp);
8582             cm_ReleaseUser(userp);
8583             return CM_ERROR_BADFD;
8584         }
8585
8586         if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8587             cm_FreeSpace(spacep);
8588             free(realPathp);
8589             cm_ReleaseUser(userp);
8590             smb_CloseFID(vcp, baseFidp, NULL, 0);
8591             smb_ReleaseFID(baseFidp);
8592             return CM_ERROR_NOSUCHPATH;
8593         }
8594
8595         baseDirp = baseFidp->scp;
8596         tidPathp = NULL;
8597     }
8598
8599     /* compute open mode */
8600     fidflags = 0;
8601     if (desiredAccess & DELETE)
8602         fidflags |= SMB_FID_OPENDELETE;
8603     if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
8604         fidflags |= SMB_FID_OPENREAD_LISTDIR;
8605     if (desiredAccess & AFS_ACCESS_WRITE)
8606         fidflags |= SMB_FID_OPENWRITE;
8607     if (createOptions & FILE_DELETE_ON_CLOSE)
8608         fidflags |= SMB_FID_DELONCLOSE;
8609     if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
8610         fidflags |= SMB_FID_SEQUENTIAL;
8611     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
8612         fidflags |= SMB_FID_RANDOM;
8613     if (createOptions & FILE_OPEN_REPARSE_POINT)
8614         osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
8615     if (smb_IsExecutableFileName(lastNamep))
8616         fidflags |= SMB_FID_EXECUTABLE;
8617
8618     /* And the share mode */
8619     if (shareAccess & FILE_SHARE_READ)
8620         fidflags |= SMB_FID_SHARE_READ;
8621     if (shareAccess & FILE_SHARE_WRITE)
8622         fidflags |= SMB_FID_SHARE_WRITE;
8623
8624     dscp = NULL;
8625     code = 0;
8626
8627     code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8628                     userp, tidPathp, &req, &dscp);
8629     if (code == 0) {
8630 #ifdef DFS_SUPPORT
8631         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8632             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8633             cm_ReleaseSCache(dscp);
8634             cm_ReleaseUser(userp);
8635             cm_FreeSpace(spacep);
8636             free(realPathp);
8637             if (baseFidp)
8638                 smb_ReleaseFID(baseFidp);
8639             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8640                 return CM_ERROR_PATH_NOT_COVERED;
8641             else
8642                 return CM_ERROR_NOSUCHPATH;
8643         }
8644 #endif /* DFS_SUPPORT */
8645         code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
8646                          userp, &req, &scp);
8647         if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
8648
8649             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
8650                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
8651             if (code == 0 && realDirFlag == 1 &&
8652                 (createDisp == FILE_OPEN ||
8653                  createDisp == FILE_OVERWRITE ||
8654                  createDisp == FILE_OVERWRITE_IF)) {
8655                 cm_ReleaseSCache(scp);
8656                 cm_ReleaseSCache(dscp);
8657                 cm_ReleaseUser(userp);
8658                 cm_FreeSpace(spacep);
8659                 free(realPathp);
8660                 if (baseFidp)
8661                     smb_ReleaseFID(baseFidp);
8662                 return CM_ERROR_EXISTS;
8663             }
8664         }
8665     } else {
8666         cm_ReleaseUser(userp);
8667         if (baseFidp)
8668             smb_ReleaseFID(baseFidp);
8669         cm_FreeSpace(spacep);
8670         free(realPathp);
8671         return CM_ERROR_NOSUCHPATH;
8672     }
8673
8674     if (code == 0)
8675         foundscp = TRUE;
8676
8677     if (code == CM_ERROR_NOSUCHFILE ||
8678         code == CM_ERROR_NOSUCHPATH ||
8679         code == CM_ERROR_BPLUS_NOMATCH ||
8680         (code == 0 && (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)))) {
8681         code = 0;
8682
8683         cm_FreeSpace(spacep);
8684
8685         if (baseFidp)
8686             smb_ReleaseFID(baseFidp);
8687
8688         if (code) {
8689             cm_ReleaseSCache(dscp);
8690             cm_ReleaseUser(userp);
8691             free(realPathp);
8692             return code;
8693         }
8694
8695         if (!lastNamep)
8696             lastNamep = realPathp;
8697         else
8698             lastNamep++;
8699
8700         if (!smb_IsLegalFilename(lastNamep)) {
8701             cm_ReleaseSCache(dscp);
8702             cm_ReleaseUser(userp);
8703             free(realPathp);
8704             return CM_ERROR_BADNTFILENAME;
8705         }
8706
8707         if (!foundscp) {
8708             if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF || createDisp == FILE_OPEN_IF) {
8709                 code = cm_Lookup(dscp, lastNamep,
8710                                   CM_FLAG_FOLLOW, userp, &req, &scp);
8711             } else {
8712                 code = cm_Lookup(dscp, lastNamep,
8713                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8714                                  userp, &req, &scp);
8715             }
8716             if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8717                 cm_ReleaseSCache(dscp);
8718                 cm_ReleaseUser(userp);
8719                 free(realPathp);
8720                 return code;
8721             }
8722         }
8723     } else {
8724         if (baseFidp)
8725             smb_ReleaseFID(baseFidp);
8726         cm_FreeSpace(spacep);
8727     }
8728
8729     /* if we get here, if code is 0, the file exists and is represented by
8730      * scp.  Otherwise, we have to create it.  The dir may be represented
8731      * by dscp, or we may have found the file directly.  If code is non-zero,
8732      * scp is NULL.
8733      */
8734     if (code == 0) {
8735         code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
8736         if (code) {
8737             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8738             cm_ReleaseSCache(dscp);
8739             cm_ReleaseSCache(scp);
8740             cm_ReleaseUser(userp);
8741             free(realPathp);
8742             return code;
8743         }
8744         checkDoneRequired = 1;
8745
8746         if (createDisp == FILE_CREATE) {
8747             /* oops, file shouldn't be there */
8748             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8749             cm_ReleaseSCache(dscp);
8750             cm_ReleaseSCache(scp);
8751             cm_ReleaseUser(userp);
8752             free(realPathp);
8753             return CM_ERROR_EXISTS;
8754         }
8755
8756         if (createDisp == FILE_OVERWRITE ||
8757             createDisp == FILE_OVERWRITE_IF) {
8758             setAttr.mask = CM_ATTRMASK_LENGTH;
8759             setAttr.length.LowPart = 0;
8760             setAttr.length.HighPart = 0;
8761
8762             /* now watch for a symlink */
8763             code = 0;
8764             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8765                 targetScp = 0;
8766                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8767                 if (code == 0) {
8768                     /* we have a more accurate file to use (the
8769                     * target of the symbolic link).  Otherwise,
8770                     * we'll just use the symlink anyway.
8771                     */
8772                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
8773                               scp, targetScp);
8774                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8775                     cm_ReleaseSCache(scp);
8776                     scp = targetScp;
8777                     code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
8778                     if (code) {
8779                         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8780                         cm_ReleaseSCache(dscp);
8781                         if (scp)
8782                             cm_ReleaseSCache(scp);
8783                         cm_ReleaseUser(userp);
8784                         free(realPathp);
8785                         return code;
8786                     }
8787                 }
8788             }
8789             code = cm_SetAttr(scp, &setAttr, userp, &req);
8790             openAction = 3;     /* truncated existing file */
8791         }
8792         else openAction = 1;    /* found existing file */
8793     }
8794     else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8795         /* don't create if not found */
8796         cm_ReleaseSCache(dscp);
8797         cm_ReleaseUser(userp);
8798         free(realPathp);
8799         return CM_ERROR_NOSUCHFILE;
8800     }
8801     else if (realDirFlag == 0 || realDirFlag == -1) {
8802         /* createDisp: FILE_SUPERSEDE, FILE_CREATE, FILE_OPEN_IF, FILE_OVERWRITE_IF */
8803         osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8804                   osi_LogSaveClientString(smb_logp, lastNamep));
8805         openAction = 2;         /* created file */
8806         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8807         setAttr.clientModTime = time(NULL);
8808         smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
8809
8810         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8811                           &req);
8812         if (code == 0) {
8813             created = 1;
8814             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8815                 smb_NotifyChange(FILE_ACTION_ADDED,
8816                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8817                                  dscp, lastNamep, NULL, TRUE);
8818         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8819             /* Not an exclusive create, and someone else tried
8820              * creating it already, then we open it anyway.  We
8821              * don't bother retrying after this, since if this next
8822              * fails, that means that the file was deleted after we
8823              * started this call.
8824              */
8825             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8826                               userp, &req, &scp);
8827             if (code == 0) {
8828                 if (createDisp == FILE_OVERWRITE_IF) {
8829                     setAttr.mask = CM_ATTRMASK_LENGTH;
8830                     setAttr.length.LowPart = 0;
8831                     setAttr.length.HighPart = 0;
8832
8833                     /* now watch for a symlink */
8834                     code = 0;
8835                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8836                         targetScp = 0;
8837                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8838                         if (code == 0) {
8839                             /* we have a more accurate file to use (the
8840                             * target of the symbolic link).  Otherwise,
8841                             * we'll just use the symlink anyway.
8842                             */
8843                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
8844                                       scp, targetScp);
8845                             cm_ReleaseSCache(scp);
8846                             scp = targetScp;
8847                         }
8848                     }
8849                     code = cm_SetAttr(scp, &setAttr, userp, &req);
8850                 }
8851             }   /* lookup succeeded */
8852         }
8853     } else {
8854         /* create directory; createDisp: FILE_CREATE, FILE_OPEN_IF */
8855         osi_Log1(smb_logp,
8856                   "smb_ReceiveNTTranCreate creating directory %S",
8857                   osi_LogSaveClientString(smb_logp, lastNamep));
8858         openAction = 2;         /* created directory */
8859         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8860         setAttr.clientModTime = time(NULL);
8861         smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
8862
8863         code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8864         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8865             smb_NotifyChange(FILE_ACTION_ADDED,
8866                               FILE_NOTIFY_CHANGE_DIR_NAME,
8867                               dscp, lastNamep, NULL, TRUE);
8868         if (code == 0 ||
8869             (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8870             /* Not an exclusive create, and someone else tried
8871              * creating it already, then we open it anyway.  We
8872              * don't bother retrying after this, since if this next
8873              * fails, that means that the file was deleted after we
8874              * started this call.
8875              */
8876             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8877                               userp, &req, &scp);
8878         }
8879     }
8880
8881     if (code) {
8882         /* something went wrong creating or truncating the file */
8883         if (checkDoneRequired)
8884             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8885         if (scp)
8886             cm_ReleaseSCache(scp);
8887         cm_ReleaseUser(userp);
8888         free(realPathp);
8889         return code;
8890     }
8891
8892     /* make sure we have file vs. dir right */
8893     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8894         /* now watch for a symlink */
8895         code = 0;
8896         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8897             targetScp = 0;
8898             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8899             if (code == 0) {
8900                 /* we have a more accurate file to use (the
8901                 * target of the symbolic link).  Otherwise,
8902                 * we'll just use the symlink anyway.
8903                 */
8904                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8905                           scp, targetScp);
8906                 if (checkDoneRequired) {
8907                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8908                     checkDoneRequired = 0;
8909                 }
8910                 cm_ReleaseSCache(scp);
8911                 scp = targetScp;
8912             }
8913         }
8914
8915         if (scp->fileType != CM_SCACHETYPE_FILE) {
8916             if (checkDoneRequired)
8917                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8918             cm_ReleaseSCache(scp);
8919             cm_ReleaseUser(userp);
8920             free(realPathp);
8921             return CM_ERROR_ISDIR;
8922         }
8923     }
8924
8925     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8926         if (checkDoneRequired)
8927             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8928         cm_ReleaseSCache(scp);
8929         cm_ReleaseUser(userp);
8930         free(realPathp);
8931         return CM_ERROR_NOTDIR;
8932     }
8933
8934     /* open the file itself */
8935     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8936     osi_assertx(fidp, "null smb_fid_t");
8937
8938     /* save a reference to the user */
8939     cm_HoldUser(userp);
8940     fidp->userp = userp;
8941
8942     /* If we are restricting sharing, we should do so with a suitable
8943        share lock. */
8944     if (scp->fileType == CM_SCACHETYPE_FILE &&
8945         !(fidflags & SMB_FID_SHARE_WRITE)) {
8946         cm_key_t key;
8947         LARGE_INTEGER LOffset, LLength;
8948         int sLockType;
8949
8950         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8951         LOffset.LowPart = SMB_FID_QLOCK_LOW;
8952         LLength.HighPart = 0;
8953         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8954
8955         /* Similar to what we do in handling NTCreateX.  We get a
8956            shared lock if we are only opening the file for reading. */
8957         if ((fidflags & SMB_FID_SHARE_READ) ||
8958             !(fidflags & SMB_FID_OPENWRITE)) {
8959             sLockType = LOCKING_ANDX_SHARED_LOCK;
8960         } else {
8961             sLockType = 0;
8962         }
8963
8964         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8965
8966         lock_ObtainWrite(&scp->rw);
8967         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8968         lock_ReleaseWrite(&scp->rw);
8969
8970         if (code) {
8971             if (checkDoneRequired)
8972                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8973             cm_ReleaseSCache(scp);
8974             cm_ReleaseUser(userp);
8975             /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
8976             smb_CloseFID(vcp, fidp, NULL, 0);
8977             smb_ReleaseFID(fidp);
8978             free(realPathp);
8979             return CM_ERROR_SHARING_VIOLATION;
8980         }
8981     }
8982
8983     /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8984     if (checkDoneRequired) {
8985         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8986         checkDoneRequired = 0;
8987     }
8988
8989     lock_ObtainMutex(&fidp->mx);
8990     /* save a pointer to the vnode */
8991     fidp->scp = scp;
8992     lock_ObtainWrite(&scp->rw);
8993     scp->flags |= CM_SCACHEFLAG_SMB_FID;
8994     lock_ReleaseWrite(&scp->rw);
8995     osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8996
8997     fidp->flags = fidflags;
8998
8999     /* remember if the file was newly created */
9000     if (created)
9001         fidp->flags |= SMB_FID_CREATED;
9002
9003     /* save parent dir and pathname for deletion or change notification */
9004     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
9005         fidp->flags |= SMB_FID_NTOPEN;
9006         fidp->NTopen_dscp = dscp;
9007         osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
9008         dscp = NULL;
9009         fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
9010     }
9011     fidp->NTopen_wholepathp = realPathp;
9012     lock_ReleaseMutex(&fidp->mx);
9013
9014     /* we don't need this any longer */
9015     if (dscp)
9016         cm_ReleaseSCache(dscp);
9017
9018     cm_Open(scp, 0, userp);
9019
9020     /* set inp->fid so that later read calls in same msg can find fid */
9021     inp->fid = fidp->fid;
9022
9023     /* check whether we are required to send an extended response */
9024     if (!extendedRespRequired) {
9025         /* out parms */
9026         parmOffset = 8*4 + 39;
9027         parmOffset += 1;        /* pad to 4 */
9028         dataOffset = parmOffset + 70;
9029
9030         parmSlot = 1;
9031         outp->oddByte = 1;
9032         /* Total Parameter Count */
9033         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
9034         /* Total Data Count */
9035         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9036         /* Parameter Count */
9037         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
9038         /* Parameter Offset */
9039         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
9040         /* Parameter Displacement */
9041         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9042         /* Data Count */
9043         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9044         /* Data Offset */
9045         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
9046         /* Data Displacement */
9047         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9048         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
9049         smb_SetSMBDataLength(outp, 70);
9050
9051         lock_ObtainRead(&scp->rw);
9052         outData = smb_GetSMBData(outp, NULL);
9053         outData++;                      /* round to get to parmOffset */
9054         *outData = 0; outData++;        /* oplock */
9055         *outData = 0; outData++;        /* reserved */
9056         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
9057         *((ULONG *)outData) = openAction; outData += 4;
9058         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
9059         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
9060         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
9061         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
9062         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
9063         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
9064         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
9065         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
9066         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
9067         *((USHORT *)outData) = 0; outData += 2; /* filetype */
9068         *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
9069         outData += 2;   /* dev state */
9070         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
9071                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
9072                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
9073         outData += 2;   /* is a dir? */
9074     } else {
9075         /* out parms */
9076         parmOffset = 8*4 + 39;
9077         parmOffset += 1;        /* pad to 4 */
9078         dataOffset = parmOffset + 104;
9079
9080         parmSlot = 1;
9081         outp->oddByte = 1;
9082         /* Total Parameter Count */
9083         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
9084         /* Total Data Count */
9085         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9086         /* Parameter Count */
9087         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
9088         /* Parameter Offset */
9089         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
9090         /* Parameter Displacement */
9091         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9092         /* Data Count */
9093         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9094         /* Data Offset */
9095         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
9096         /* Data Displacement */
9097         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9098         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
9099         smb_SetSMBDataLength(outp, 105);
9100
9101         lock_ObtainRead(&scp->rw);
9102         outData = smb_GetSMBData(outp, NULL);
9103         outData++;                      /* round to get to parmOffset */
9104         *outData = 0; outData++;        /* oplock */
9105         *outData = 1; outData++;        /* response type */
9106         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
9107         *((ULONG *)outData) = openAction; outData += 4;
9108         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
9109         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
9110         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
9111         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
9112         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
9113         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
9114         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
9115         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
9116         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
9117         *((USHORT *)outData) = 0; outData += 2; /* filetype */
9118         *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
9119         outData += 2;   /* dev state */
9120         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
9121                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
9122                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
9123         outData += 1;   /* is a dir? */
9124         /* Setting the GUID results in failures with cygwin */
9125         memset(outData,0,24); outData += 24; /* GUID */
9126         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
9127         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
9128     }
9129
9130     if ((fidp->flags & SMB_FID_EXECUTABLE) &&
9131          LargeIntegerGreaterThanZero(scp->length) &&
9132          !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
9133         prefetch = 1;
9134     }
9135     lock_ReleaseRead(&scp->rw);
9136
9137     if (prefetch)
9138         cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
9139                            scp->length.LowPart, scp->length.HighPart,
9140                            userp, &req);
9141
9142     osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
9143
9144     cm_ReleaseUser(userp);
9145     smb_ReleaseFID(fidp);
9146
9147     /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
9148     /* leave scp held since we put it in fidp->scp */
9149     return 0;
9150 }
9151
9152 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
9153 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
9154         smb_packet_t *outp)
9155 {
9156     smb_packet_t *savedPacketp;
9157     ULONG filter;
9158     USHORT fid, watchtree;
9159     smb_fid_t *fidp;
9160     cm_scache_t *scp;
9161
9162     filter = smb_GetSMBParm(inp, 19) |
9163              (smb_GetSMBParm(inp, 20) << 16);
9164     fid = smb_GetSMBParm(inp, 21);
9165     watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
9166
9167     fidp = smb_FindFID(vcp, fid, 0);
9168     if (!fidp) {
9169         osi_Log2(smb_logp, "NotifyChange Unknown SMB Fid vcp 0x%p fid %d",
9170                  vcp, fid);
9171         return CM_ERROR_BADFD;
9172     }
9173
9174     lock_ObtainMutex(&fidp->mx);
9175     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
9176         lock_ReleaseMutex(&fidp->mx);
9177         smb_CloseFID(vcp, fidp, NULL, 0);
9178         smb_ReleaseFID(fidp);
9179         return CM_ERROR_NOSUCHFILE;
9180     }
9181     scp = fidp->scp;
9182     cm_HoldSCache(scp);
9183     lock_ReleaseMutex(&fidp->mx);
9184
9185     /* Create a copy of the Directory Watch Packet to use when sending the
9186      * notification if in the future a matching change is detected.
9187      */
9188     savedPacketp = smb_CopyPacket(inp);
9189     if (vcp != savedPacketp->vcp) {
9190         smb_HoldVC(vcp);
9191         if (savedPacketp->vcp)
9192             smb_ReleaseVC(savedPacketp->vcp);
9193         savedPacketp->vcp = vcp;
9194     }
9195
9196     /* Add the watch to the list of events to send notifications for */
9197     lock_ObtainMutex(&smb_Dir_Watch_Lock);
9198     savedPacketp->nextp = smb_Directory_Watches;
9199     smb_Directory_Watches = savedPacketp;
9200     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9201
9202     osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
9203               fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
9204     osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
9205              filter, fid, watchtree);
9206     if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9207         osi_Log0(smb_logp, "      Notify Change File Name");
9208     if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9209         osi_Log0(smb_logp, "      Notify Change Directory Name");
9210     if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9211         osi_Log0(smb_logp, "      Notify Change Attributes");
9212     if (filter & FILE_NOTIFY_CHANGE_SIZE)
9213         osi_Log0(smb_logp, "      Notify Change Size");
9214     if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9215         osi_Log0(smb_logp, "      Notify Change Last Write");
9216     if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9217         osi_Log0(smb_logp, "      Notify Change Last Access");
9218     if (filter & FILE_NOTIFY_CHANGE_CREATION)
9219         osi_Log0(smb_logp, "      Notify Change Creation");
9220     if (filter & FILE_NOTIFY_CHANGE_EA)
9221         osi_Log0(smb_logp, "      Notify Change Extended Attributes");
9222     if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9223         osi_Log0(smb_logp, "      Notify Change Security");
9224     if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9225         osi_Log0(smb_logp, "      Notify Change Stream Name");
9226     if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9227         osi_Log0(smb_logp, "      Notify Change Stream Size");
9228     if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9229         osi_Log0(smb_logp, "      Notify Change Stream Write");
9230
9231     lock_ObtainWrite(&scp->rw);
9232     if (watchtree)
9233         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
9234     else
9235         scp->flags |= CM_SCACHEFLAG_WATCHED;
9236     lock_ReleaseWrite(&scp->rw);
9237     cm_ReleaseSCache(scp);
9238     smb_ReleaseFID(fidp);
9239
9240     outp->flags |= SMB_PACKETFLAG_NOSEND;
9241     return 0;
9242 }
9243
9244 unsigned char nullSecurityDesc[] = {
9245     0x01,                               /* security descriptor revision */
9246     0x00,                               /* reserved, should be zero */
9247     0x04, 0x80,                         /* security descriptor control;
9248                                          * 0x0004 : null-DACL present - everyone has full access
9249                                          * 0x8000 : relative format */
9250     0x14, 0x00, 0x00, 0x00,             /* offset of owner SID */
9251     0x20, 0x00, 0x00, 0x00,             /* offset of group SID */
9252     0x00, 0x00, 0x00, 0x00,             /* offset of DACL would go here */
9253     0x00, 0x00, 0x00, 0x00,             /* offset of SACL would go here */
9254     0x01, 0x01, 0x00, 0x00,             /* "everyone SID" owner SID */
9255     0x00, 0x00, 0x00, 0x01,
9256     0x00, 0x00, 0x00, 0x00,
9257     0x01, 0x01, 0x00, 0x00,             /* "everyone SID" owner SID */
9258     0x00, 0x00, 0x00, 0x01,
9259     0x00, 0x00, 0x00, 0x00
9260 };
9261
9262 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
9263 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9264 {
9265     int parmOffset, parmCount, dataOffset, dataCount;
9266     int totalParmCount, totalDataCount;
9267     int parmSlot;
9268     int maxData, maxParm;
9269     int inTotalParm, inTotalData;
9270     int inParm, inData;
9271     int inParmOffset, inDataOffset;
9272     char *outData;
9273     char *parmp;
9274     USHORT *sparmp;
9275     ULONG *lparmp;
9276     USHORT fid;
9277     ULONG securityInformation;
9278     smb_fid_t *fidp;
9279     long code = 0;
9280     DWORD dwLength;
9281
9282     /*
9283      * For details on the meanings of the various
9284      * SMB_COM_TRANSACTION fields, see sections 2.2.4.33
9285      * of http://msdn.microsoft.com/en-us/library/ee442092%28PROT.13%29.aspx
9286      */
9287
9288     inTotalParm = smb_GetSMBOffsetParm(inp, 1, 1)
9289         | (smb_GetSMBOffsetParm(inp, 2, 1) << 16);
9290
9291     inTotalData = smb_GetSMBOffsetParm(inp, 3, 1)
9292         | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
9293
9294     maxParm = smb_GetSMBOffsetParm(inp, 5, 1)
9295         | (smb_GetSMBOffsetParm(inp, 6, 1) << 16);
9296
9297     maxData = smb_GetSMBOffsetParm(inp, 7, 1)
9298         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
9299
9300     inParm = smb_GetSMBOffsetParm(inp, 9, 1)
9301         | (smb_GetSMBOffsetParm(inp, 10, 1) << 16);
9302
9303     inParmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
9304         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
9305
9306     inData = smb_GetSMBOffsetParm(inp, 13, 1)
9307         | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
9308
9309     inDataOffset = smb_GetSMBOffsetParm(inp, 15, 1)
9310         | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
9311
9312     parmp = inp->data + inParmOffset;
9313     sparmp = (USHORT *) parmp;
9314     lparmp = (ULONG *) parmp;
9315
9316     fid = sparmp[0];
9317     securityInformation = lparmp[1];
9318
9319     fidp = smb_FindFID(vcp, fid, 0);
9320     if (!fidp) {
9321         osi_Log2(smb_logp, "smb_ReceiveNTTranQuerySecurityDesc Unknown SMB Fid vcp 0x%p fid %d",
9322                  vcp, fid);
9323         return CM_ERROR_BADFD;
9324     }
9325
9326     lock_ObtainMutex(&fidp->mx);
9327     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
9328         lock_ReleaseMutex(&fidp->mx);
9329         smb_CloseFID(vcp, fidp, NULL, 0);
9330         smb_ReleaseFID(fidp);
9331         return CM_ERROR_NOSUCHFILE;
9332     }
9333     lock_ReleaseMutex(&fidp->mx);
9334
9335     osi_Log4(smb_logp,"smb_ReceiveNTTranQuerySecurityDesc fidp 0x%p scp 0x%p file \"%S\" Info=0x%x",
9336               fidp, fidp->scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp),
9337               securityInformation);
9338
9339     smb_ReleaseFID(fidp);
9340
9341     if ( securityInformation & ~(OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION) )
9342     {
9343         code = CM_ERROR_BAD_LEVEL;
9344         goto done;
9345     }
9346
9347     dwLength = sizeof( nullSecurityDesc);
9348
9349     totalDataCount = dwLength;
9350     totalParmCount = 4;
9351
9352     if (maxData >= totalDataCount) {
9353         dataCount = totalDataCount;
9354         parmCount = min(totalParmCount, maxParm);
9355     } else if (maxParm >= totalParmCount) {
9356         totalDataCount = dataCount = 0;
9357         parmCount = totalParmCount;
9358     } else {
9359         totalDataCount = dataCount = 0;
9360         totalParmCount = parmCount = 0;
9361     }
9362
9363     /* out parms */
9364     parmOffset = 8*4 + 39;
9365     parmOffset += 1;    /* pad to 4 */
9366
9367     dataOffset = parmOffset + parmCount;
9368
9369     parmSlot = 1;
9370     outp->oddByte = 1;
9371     /* Total Parameter Count */
9372     smb_SetSMBParmLong(outp, parmSlot, totalParmCount); parmSlot += 2;
9373     /* Total Data Count */
9374     smb_SetSMBParmLong(outp, parmSlot, totalDataCount); parmSlot += 2;
9375     /* Parameter Count */
9376     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
9377     /* Parameter Offset */
9378     smb_SetSMBParmLong(outp, parmSlot, parmCount ? parmOffset : 0); parmSlot += 2;
9379     /* Parameter Displacement */
9380     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9381     /* Data Count */
9382     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
9383     /* Data Offset */
9384     smb_SetSMBParmLong(outp, parmSlot, dataCount ? dataOffset : 0); parmSlot += 2;
9385     /* Data Displacement */
9386     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9387     /* Setup Count */
9388     smb_SetSMBParmByte(outp, parmSlot, 0);
9389
9390     if (parmCount == totalParmCount && dwLength == dataCount) {
9391         smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
9392
9393         /* Data */
9394         outData = smb_GetSMBData(outp, NULL);
9395         outData++;                      /* round to get to dataOffset */
9396
9397         *((ULONG *)outData) = dataCount; outData += 4;  /* SD Length (4 bytes) */
9398         memcpy(outData, nullSecurityDesc, dataCount);
9399         outData += dataCount;
9400
9401         code = 0;
9402     } else if (parmCount >= 4) {
9403         smb_SetSMBDataLength(outp, 1 + parmCount);
9404
9405         /* Data */
9406         outData = smb_GetSMBData(outp, NULL);
9407         outData++;                      /* round to get to dataOffset */
9408
9409         *((ULONG *)outData) = dwLength; outData += 4;   /* SD Length (4 bytes) */
9410         code = CM_ERROR_BUFFERTOOSMALL;
9411     } else {
9412         smb_SetSMBDataLength(outp, 0);
9413         code = CM_ERROR_BUFFER_OVERFLOW;
9414     }
9415
9416   done:
9417     return code;
9418 }
9419
9420 /* SMB_COM_NT_TRANSACT
9421
9422    SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
9423  */
9424 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9425 {
9426     unsigned short function;
9427
9428     function = smb_GetSMBParm(inp, 18);
9429
9430     osi_Log1(smb_logp, "SMB NT Transact function %d", function);
9431
9432     /* We can handle long names */
9433     if (vcp->flags & SMB_VCFLAG_USENT)
9434         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
9435
9436     switch (function) {
9437     case 1:                     /* NT_TRANSACT_CREATE */
9438         return smb_ReceiveNTTranCreate(vcp, inp, outp);
9439     case 2:                     /* NT_TRANSACT_IOCTL */
9440         osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
9441         break;
9442     case 3:                     /* NT_TRANSACT_SET_SECURITY_DESC */
9443         osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
9444         break;
9445     case 4:                     /* NT_TRANSACT_NOTIFY_CHANGE */
9446         return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
9447     case 5:                     /* NT_TRANSACT_RENAME */
9448         osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
9449         break;
9450     case 6:                     /* NT_TRANSACT_QUERY_SECURITY_DESC */
9451         return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
9452     case 7:
9453         osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
9454         break;
9455     case 8:
9456         osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
9457         break;
9458     }
9459     return CM_ERROR_BADOP;
9460 }
9461
9462 /*
9463  * smb_NotifyChange -- find relevant change notification messages and
9464  *                     reply to them
9465  *
9466  * If we don't know the file name (i.e. a callback break), filename is
9467  * NULL, and we return a zero-length list.
9468  *
9469  * At present there is not a single call to smb_NotifyChange that
9470  * has the isDirectParent parameter set to FALSE.
9471  */
9472 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
9473         cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
9474         BOOL isDirectParent)
9475 {
9476     smb_packet_t *watch, *lastWatch, *nextWatch;
9477     ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
9478     char *outData, *oldOutData;
9479     ULONG filter;
9480     USHORT fid, wtree;
9481     ULONG maxLen;
9482     BOOL twoEntries = FALSE;
9483     ULONG otherNameLen, oldParmCount = 0;
9484     DWORD otherAction;
9485     smb_fid_t *fidp;
9486
9487     /* Get ready for rename within directory */
9488     if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
9489         twoEntries = TRUE;
9490         otherAction = FILE_ACTION_RENAMED_NEW_NAME;
9491     }
9492
9493     osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
9494              osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
9495     if (action == 0)
9496         osi_Log0(smb_logp,"      FILE_ACTION_NONE");
9497     if (action == FILE_ACTION_ADDED)
9498         osi_Log0(smb_logp,"      FILE_ACTION_ADDED");
9499     if (action == FILE_ACTION_REMOVED)
9500         osi_Log0(smb_logp,"      FILE_ACTION_REMOVED");
9501     if (action == FILE_ACTION_MODIFIED)
9502         osi_Log0(smb_logp,"      FILE_ACTION_MODIFIED");
9503     if (action == FILE_ACTION_RENAMED_OLD_NAME)
9504         osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_OLD_NAME");
9505     if (action == FILE_ACTION_RENAMED_NEW_NAME)
9506         osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_NEW_NAME");
9507
9508     lock_ObtainMutex(&smb_Dir_Watch_Lock);
9509     watch = smb_Directory_Watches;
9510     while (watch) {
9511         filter = smb_GetSMBParm(watch, 19)
9512             | (smb_GetSMBParm(watch, 20) << 16);
9513         fid = smb_GetSMBParm(watch, 21);
9514         wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
9515
9516         maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
9517             | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
9518
9519         /*
9520          * Strange hack - bug in NT Client and NT Server that we must emulate?
9521          */
9522         if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
9523             filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
9524
9525         fidp = smb_FindFID(watch->vcp, fid, 0);
9526         if (!fidp) {
9527             osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
9528             lastWatch = watch;
9529             watch = watch->nextp;
9530             continue;
9531         }
9532
9533         if (fidp->scp != dscp ||
9534             fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
9535             (filter & notifyFilter) == 0 ||
9536             (!isDirectParent && !wtree))
9537         {
9538             osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
9539             lastWatch = watch;
9540             watch = watch->nextp;
9541             smb_ReleaseFID(fidp);
9542             continue;
9543         }
9544
9545         osi_Log4(smb_logp,
9546                   "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
9547                   fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
9548         if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9549             osi_Log0(smb_logp, "      Notify Change File Name");
9550         if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9551             osi_Log0(smb_logp, "      Notify Change Directory Name");
9552         if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9553             osi_Log0(smb_logp, "      Notify Change Attributes");
9554         if (filter & FILE_NOTIFY_CHANGE_SIZE)
9555             osi_Log0(smb_logp, "      Notify Change Size");
9556         if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9557             osi_Log0(smb_logp, "      Notify Change Last Write");
9558         if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9559             osi_Log0(smb_logp, "      Notify Change Last Access");
9560         if (filter & FILE_NOTIFY_CHANGE_CREATION)
9561             osi_Log0(smb_logp, "      Notify Change Creation");
9562         if (filter & FILE_NOTIFY_CHANGE_EA)
9563             osi_Log0(smb_logp, "      Notify Change Extended Attributes");
9564         if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9565             osi_Log0(smb_logp, "      Notify Change Security");
9566         if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9567             osi_Log0(smb_logp, "      Notify Change Stream Name");
9568         if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9569             osi_Log0(smb_logp, "      Notify Change Stream Size");
9570         if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9571             osi_Log0(smb_logp, "      Notify Change Stream Write");
9572
9573         /* A watch can only be notified once.  Remove it from the list */
9574         nextWatch = watch->nextp;
9575         if (watch == smb_Directory_Watches)
9576             smb_Directory_Watches = nextWatch;
9577         else
9578             lastWatch->nextp = nextWatch;
9579
9580         /* Turn off WATCHED flag in dscp */
9581         lock_ObtainWrite(&dscp->rw);
9582         if (wtree)
9583             dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9584         else
9585             dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
9586         lock_ReleaseWrite(&dscp->rw);
9587
9588         /* Convert to response packet */
9589         ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
9590 #ifdef SEND_CANONICAL_PATHNAMES
9591         ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
9592 #endif
9593         ((smb_t *) watch)->wct = 0;
9594
9595         /* out parms */
9596         if (filename == NULL) {
9597             parmCount = 0;
9598         } else {
9599             nameLen = (ULONG)cm_ClientStrLen(filename);
9600             parmCount = 3*4 + nameLen*2;
9601             parmCount = (parmCount + 3) & ~3;   /* pad to 4 */
9602             if (twoEntries) {
9603                 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
9604                 oldParmCount = parmCount;
9605                 parmCount += 3*4 + otherNameLen*2;
9606                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9607             }
9608             if (maxLen < parmCount)
9609                 parmCount = 0;  /* not enough room */
9610         }
9611         parmOffset = 8*4 + 39;
9612         parmOffset += 1;                        /* pad to 4 */
9613         dataOffset = parmOffset + parmCount;
9614
9615         parmSlot = 1;
9616         watch->oddByte = 1;
9617         /* Total Parameter Count */
9618         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9619         /* Total Data Count */
9620         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9621         /* Parameter Count */
9622         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9623         /* Parameter Offset */
9624         smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
9625         /* Parameter Displacement */
9626         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9627         /* Data Count */
9628         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9629         /* Data Offset */
9630         smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
9631         /* Data Displacement */
9632         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9633         smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
9634         smb_SetSMBDataLength(watch, parmCount + 1);
9635
9636         if (parmCount != 0) {
9637             outData = smb_GetSMBData(watch, NULL);
9638             outData++;  /* round to get to parmOffset */
9639             oldOutData = outData;
9640             *((DWORD *)outData) = oldParmCount; outData += 4;
9641             /* Next Entry Offset */
9642             *((DWORD *)outData) = action; outData += 4;
9643             /* Action */
9644             *((DWORD *)outData) = nameLen*2; outData += 4;
9645             /* File Name Length */
9646
9647             smb_UnparseString(watch, outData, filename, NULL, 0);
9648             /* File Name */
9649
9650             if (twoEntries) {
9651                 outData = oldOutData + oldParmCount;
9652                 *((DWORD *)outData) = 0; outData += 4;
9653                 /* Next Entry Offset */
9654                 *((DWORD *)outData) = otherAction; outData += 4;
9655                 /* Action */
9656                 *((DWORD *)outData) = otherNameLen*2;
9657                 outData += 4;   /* File Name Length */
9658                 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
9659             }
9660         }
9661
9662         /*
9663          * If filename is null, we don't know the cause of the
9664          * change notification.  We return zero data (see above),
9665          * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
9666          * (= 0x010C).  We set the error code here by hand, without
9667          * modifying wct and bcc.
9668          */
9669         if (filename == NULL) {
9670             ((smb_t *) watch)->rcls = 0x0C;
9671             ((smb_t *) watch)->reh = 0x01;
9672             ((smb_t *) watch)->errLow = 0;
9673             ((smb_t *) watch)->errHigh = 0;
9674             /* Set NT Status codes flag */
9675             ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9676         }
9677
9678         smb_SendPacket(watch->vcp, watch);
9679         smb_FreePacket(watch);
9680
9681         smb_ReleaseFID(fidp);
9682         watch = nextWatch;
9683     }
9684     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9685 }
9686
9687 /* SMB_COM_NT_CANCEL */
9688 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9689 {
9690     unsigned char *replyWctp;
9691     smb_packet_t *watch, *lastWatch;
9692     USHORT fid, watchtree;
9693     smb_fid_t *fidp;
9694     cm_scache_t *scp;
9695
9696     osi_Log0(smb_logp, "SMB3 receive NT cancel");
9697
9698     lock_ObtainMutex(&smb_Dir_Watch_Lock);
9699     watch = smb_Directory_Watches;
9700     while (watch) {
9701         if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
9702              && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
9703              && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
9704              && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
9705             if (watch == smb_Directory_Watches)
9706                 smb_Directory_Watches = watch->nextp;
9707             else
9708                 lastWatch->nextp = watch->nextp;
9709             lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9710
9711             /* Turn off WATCHED flag in scp */
9712             fid = smb_GetSMBParm(watch, 21);
9713             watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
9714
9715             if (vcp != watch->vcp)
9716                 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
9717                           vcp, watch->vcp);
9718
9719             fidp = smb_FindFID(vcp, fid, 0);
9720             if (fidp) {
9721                 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
9722                          fid, watchtree,
9723                          (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
9724
9725                 scp = fidp->scp;
9726                 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
9727                 if (scp) {
9728                     lock_ObtainWrite(&scp->rw);
9729                     if (watchtree)
9730                         scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9731                     else
9732                         scp->flags &= ~CM_SCACHEFLAG_WATCHED;
9733                     lock_ReleaseWrite(&scp->rw);
9734                 }
9735                 smb_ReleaseFID(fidp);
9736             } else {
9737                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
9738             }
9739
9740             /* assume STATUS32; return 0xC0000120 (CANCELED) */
9741             replyWctp = watch->wctp;
9742             *replyWctp++ = 0;
9743             *replyWctp++ = 0;
9744             *replyWctp++ = 0;
9745             ((smb_t *)watch)->rcls = 0x20;
9746             ((smb_t *)watch)->reh = 0x1;
9747             ((smb_t *)watch)->errLow = 0;
9748             ((smb_t *)watch)->errHigh = 0xC0;
9749             ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9750             smb_SendPacket(vcp, watch);
9751             smb_FreePacket(watch);
9752             return 0;
9753         }
9754         lastWatch = watch;
9755         watch = watch->nextp;
9756     }
9757     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9758
9759     return 0;
9760 }
9761
9762 /*
9763  * NT rename also does hard links.
9764  */
9765
9766 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
9767 #define RENAME_FLAG_HARD_LINK                0x103
9768 #define RENAME_FLAG_RENAME                   0x104
9769 #define RENAME_FLAG_COPY                     0x105
9770
9771 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9772 {
9773     clientchar_t *oldPathp, *newPathp;
9774     long code = 0;
9775     char * tp;
9776     int attrs;
9777     int rename_type;
9778
9779     attrs = smb_GetSMBParm(inp, 0);
9780     rename_type = smb_GetSMBParm(inp, 1);
9781
9782     if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
9783         osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
9784         return CM_ERROR_NOACCESS;
9785     }
9786
9787     tp = smb_GetSMBData(inp, NULL);
9788     oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9789     if (!oldPathp)
9790         return CM_ERROR_BADSMB;
9791     newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9792     if (!newPathp)
9793         return CM_ERROR_BADSMB;
9794
9795     osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
9796              osi_LogSaveClientString(smb_logp, oldPathp),
9797              osi_LogSaveClientString(smb_logp, newPathp),
9798              ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
9799
9800     if (rename_type == RENAME_FLAG_RENAME) {
9801         code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
9802     } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
9803         code = smb_Link(vcp,inp,oldPathp,newPathp);
9804     } else
9805         code = CM_ERROR_BADOP;
9806     return code;
9807 }
9808
9809 void smb3_Init()
9810 {
9811     lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
9812 }
9813
9814 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9815 {
9816     smb_username_t *unp;
9817     cm_user_t *     userp;
9818
9819     unp = smb_FindUserByName(usern, machine, flags);
9820     if (!unp->userp) {
9821         lock_ObtainMutex(&unp->mx);
9822         unp->userp = cm_NewUser();
9823         lock_ReleaseMutex(&unp->mx);
9824         osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9825     }  else     {
9826         osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9827     }
9828     userp = unp->userp;
9829     cm_HoldUser(userp);
9830     smb_ReleaseUsername(unp);
9831     return userp;
9832 }
9833
9834 cm_user_t *smb_FindCMUserBySID(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9835 {
9836     smb_username_t *unp;
9837     cm_user_t *     userp;
9838
9839     unp = smb_FindUserByName(usern, machine, flags);
9840     if (!unp->userp) {
9841         lock_ObtainMutex(&unp->mx);
9842         unp->flags |= SMB_USERNAMEFLAG_SID;
9843         unp->userp = cm_NewUser();
9844         lock_ReleaseMutex(&unp->mx);
9845         osi_Log2(smb_logp,"smb_FindCMUserBySID New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9846     }  else     {
9847         osi_Log2(smb_logp,"smb_FindCMUserBySID Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9848     }
9849     userp = unp->userp;
9850     cm_HoldUser(userp);
9851     smb_ReleaseUsername(unp);
9852     return userp;
9853 }