d8a956b7af370e1b34dcc329bcf9a1fbd5bb1ec2
[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_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
4070     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
4071         if (fidp->flags & SMB_FID_IOCTL) {
4072             cm_LargeSearchTimeFromUnixTime(&ft, 0);
4073             attributes = SMB_ATTR_SYSTEM | SMB_ATTR_HIDDEN;
4074         } else {
4075             cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4076             attributes = smb_ExtAttributes(scp);
4077         }
4078         qfi.u.QFbasicInfo.creationTime = ft;
4079         qfi.u.QFbasicInfo.lastAccessTime = ft;
4080         qfi.u.QFbasicInfo.lastWriteTime = ft;
4081         qfi.u.QFbasicInfo.lastChangeTime = ft;
4082         qfi.u.QFbasicInfo.attributes = attributes;
4083     }
4084     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
4085         if (fidp->flags & SMB_FID_IOCTL) {
4086             qfi.u.QFstandardInfo.allocationSize.QuadPart = 0;
4087             qfi.u.QFstandardInfo.endOfFile.QuadPart = 0;
4088             qfi.u.QFstandardInfo.numberOfLinks = 1;
4089             qfi.u.QFstandardInfo.deletePending = 0;
4090             qfi.u.QFstandardInfo.directory = 0;
4091         } else {
4092             qfi.u.QFstandardInfo.allocationSize = scp->length;
4093             qfi.u.QFstandardInfo.endOfFile = scp->length;
4094             qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
4095             qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
4096             qfi.u.QFstandardInfo.directory =
4097                 ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
4098                    scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4099                    scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
4100         }
4101     }
4102     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
4103         qfi.u.QFeaInfo.eaSize = 0;
4104     }
4105     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4106         size_t len = 0;
4107         clientchar_t *name;
4108
4109         lock_ReleaseRead(&scp->rw);
4110         lock_ObtainMutex(&fidp->mx);
4111         lock_ObtainRead(&scp->rw);
4112         if (fidp->NTopen_wholepathp)
4113             name = fidp->NTopen_wholepathp;
4114         else
4115             name = _C("\\");    /* probably can't happen */
4116         lock_ReleaseMutex(&fidp->mx);
4117
4118         smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
4119         responseSize = len + 4; /* this is actually what we want to return */
4120         qfi.u.QFfileNameInfo.fileNameLength = len;
4121     }
4122     else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
4123         size_t len = 0;
4124
4125         if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
4126             scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4127             scp->fileType == CM_SCACHETYPE_INVALID) {
4128             /* Do not return the alternate streams for directories */
4129             responseSize = 0;
4130         } else {
4131             /* For now we have no alternate streams */
4132             qfi.u.QFfileStreamInfo.nextEntryOffset = 0;
4133
4134             if (fidp->flags & SMB_FID_IOCTL) {
4135                 qfi.u.QFfileStreamInfo.streamSize.QuadPart = 0;
4136                 qfi.u.QFfileStreamInfo.streamAllocationSize.QuadPart = 0;
4137             } else {
4138                 qfi.u.QFfileStreamInfo.streamSize = scp->length;
4139                 qfi.u.QFfileStreamInfo.streamAllocationSize = scp->length;
4140             }
4141
4142             smb_UnparseString(opx, qfi.u.QFfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
4143             qfi.u.QFfileStreamInfo.streamNameLength = len;
4144             responseSize -= (sizeof(qfi.u.QFfileStreamInfo.fileName) - len);
4145         }
4146     }
4147     outp->totalData = responseSize;
4148
4149     /* send and free the packets */
4150   done:
4151     if (readlock)
4152         lock_ReleaseRead(&scp->rw);
4153     else
4154         lock_ReleaseWrite(&scp->rw);
4155     cm_ReleaseSCache(scp);
4156     cm_ReleaseUser(userp);
4157     smb_ReleaseFID(fidp);
4158     if (code == 0) {
4159         memcpy(outp->datap, &qfi, responseSize);
4160         smb_SendTran2Packet(vcp, outp, opx);
4161     } else {
4162         smb_SendTran2Error(vcp, p, opx, code);
4163     }
4164     smb_FreeTran2Packet(outp);
4165
4166     return 0;
4167 }
4168
4169
4170 /* TRANS2_SET_FILE_INFORMATION */
4171 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4172 {
4173     long code = 0;
4174     unsigned short fid;
4175     smb_fid_t *fidp;
4176     unsigned short infoLevel;
4177     smb_tran2Packet_t *outp;
4178     cm_user_t *userp = NULL;
4179     cm_scache_t *scp = NULL;
4180     cm_req_t req;
4181
4182     smb_InitReq(&req);
4183
4184     fid = p->parmsp[0];
4185     fidp = smb_FindFID(vcp, fid, 0);
4186
4187     if (fidp == NULL) {
4188         osi_Log2(smb_logp, "Tran2SetFileInfo Unknown SMB Fid vcp 0x%p fid %d",
4189                  vcp, fid);
4190         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
4191         return 0;
4192     }
4193
4194     infoLevel = p->parmsp[1];
4195     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
4196     if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
4197         osi_Log2(smb_logp, "Bad Tran2SetFileInfo op 0x%x infolevel 0x%x",
4198                   p->opcode, infoLevel);
4199         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
4200         smb_ReleaseFID(fidp);
4201         return 0;
4202     }
4203
4204     lock_ObtainMutex(&fidp->mx);
4205     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
4206         lock_ReleaseMutex(&fidp->mx);
4207         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
4208         smb_CloseFID(vcp, fidp, NULL, 0);
4209         smb_ReleaseFID(fidp);
4210         return 0;
4211     }
4212
4213     if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
4214         !(fidp->flags & SMB_FID_OPENDELETE)) {
4215         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
4216                   fidp, fidp->scp, fidp->flags);
4217         lock_ReleaseMutex(&fidp->mx);
4218         smb_ReleaseFID(fidp);
4219         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
4220         return 0;
4221     }
4222     if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4223          infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
4224          && !(fidp->flags & SMB_FID_OPENWRITE)) {
4225         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
4226                   fidp, fidp->scp, fidp->flags);
4227         lock_ReleaseMutex(&fidp->mx);
4228         smb_ReleaseFID(fidp);
4229         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
4230         return 0;
4231     }
4232
4233     scp = fidp->scp;
4234     osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
4235     cm_HoldSCache(scp);
4236     lock_ReleaseMutex(&fidp->mx);
4237
4238     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
4239
4240     outp->totalParms = 2;
4241     outp->totalData = 0;
4242
4243     userp = smb_GetTran2User(vcp, p);
4244     if (!userp) {
4245         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
4246         code = CM_ERROR_BADSMB;
4247         goto done;
4248     }
4249
4250     if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
4251         FILETIME lastMod;
4252         unsigned int attribute;
4253         cm_attr_t attr;
4254         smb_tran2QFileInfo_t *sfi;
4255
4256         sfi = (smb_tran2QFileInfo_t *)p->datap;
4257
4258         /* lock the vnode with a callback; we need the current status
4259          * to determine what the new status is, in some cases.
4260          */
4261         lock_ObtainWrite(&scp->rw);
4262         code = cm_SyncOp(scp, NULL, userp, &req, 0,
4263                           CM_SCACHESYNC_GETSTATUS
4264                          | CM_SCACHESYNC_NEEDCALLBACK);
4265         if (code) {
4266             lock_ReleaseWrite(&scp->rw);
4267             goto done;
4268         }
4269
4270         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4271
4272         lock_ReleaseWrite(&scp->rw);
4273         lock_ObtainMutex(&fidp->mx);
4274         lock_ObtainRead(&scp->rw);
4275
4276         /* prepare for setattr call */
4277         attr.mask = 0;
4278
4279         lastMod = sfi->u.QFbasicInfo.lastWriteTime;
4280         /* when called as result of move a b, lastMod is (-1, -1).
4281          * If the check for -1 is not present, timestamp
4282          * of the resulting file will be 1969 (-1)
4283          */
4284         if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
4285              lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
4286             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4287             cm_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
4288             fidp->flags |= SMB_FID_MTIMESETDONE;
4289         }
4290
4291         attribute = sfi->u.QFbasicInfo.attributes;
4292         if (attribute != 0) {
4293             if ((scp->unixModeBits & 0200)
4294                  && (attribute & SMB_ATTR_READONLY) != 0) {
4295                 /* make a writable file read-only */
4296                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4297                 attr.unixModeBits = scp->unixModeBits & ~0222;
4298             }
4299             else if ((scp->unixModeBits & 0200) == 0
4300                       && (attribute & SMB_ATTR_READONLY) == 0) {
4301                 /* make a read-only file writable */
4302                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4303                 attr.unixModeBits = scp->unixModeBits | 0222;
4304             }
4305         }
4306         lock_ReleaseRead(&scp->rw);
4307         lock_ReleaseMutex(&fidp->mx);
4308
4309         /* call setattr */
4310         if (attr.mask)
4311             code = cm_SetAttr(scp, &attr, userp, &req);
4312         else
4313             code = 0;
4314     }
4315     else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
4316         int delflag = *((char *)(p->datap));
4317         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
4318                  delflag, fidp, scp);
4319         if (*((char *)(p->datap))) {    /* File is Deleted */
4320             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
4321                                      &req);
4322             if (code == 0) {
4323                 lock_ObtainMutex(&fidp->mx);
4324                 fidp->flags |= SMB_FID_DELONCLOSE;
4325                 lock_ReleaseMutex(&fidp->mx);
4326             } else {
4327                 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
4328                          fidp, scp, code);
4329             }
4330         }
4331         else {
4332             code = 0;
4333             lock_ObtainMutex(&fidp->mx);
4334             fidp->flags &= ~SMB_FID_DELONCLOSE;
4335             lock_ReleaseMutex(&fidp->mx);
4336         }
4337     }
4338     else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4339              infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
4340         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
4341         cm_attr_t attr;
4342
4343         attr.mask = CM_ATTRMASK_LENGTH;
4344         attr.length.LowPart = size.LowPart;
4345         attr.length.HighPart = size.HighPart;
4346         code = cm_SetAttr(scp, &attr, userp, &req);
4347     }
4348
4349   done:
4350     cm_ReleaseSCache(scp);
4351     cm_ReleaseUser(userp);
4352     smb_ReleaseFID(fidp);
4353     if (code == 0)
4354         smb_SendTran2Packet(vcp, outp, opx);
4355     else
4356         smb_SendTran2Error(vcp, p, opx, code);
4357     smb_FreeTran2Packet(outp);
4358
4359     return 0;
4360 }
4361
4362 /* TRANS2_FSCTL */
4363 long
4364 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4365 {
4366     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
4367     return CM_ERROR_BADOP;
4368 }
4369
4370 /* TRANS2_IOCTL2 */
4371 long
4372 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4373 {
4374     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
4375     return CM_ERROR_BADOP;
4376 }
4377
4378 /* TRANS2_FIND_NOTIFY_FIRST */
4379 long
4380 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4381 {
4382     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
4383     return CM_ERROR_BADOP;
4384 }
4385
4386 /* TRANS2_FIND_NOTIFY_NEXT */
4387 long
4388 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4389 {
4390     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
4391     return CM_ERROR_BADOP;
4392 }
4393
4394 /* TRANS2_CREATE_DIRECTORY */
4395 long
4396 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4397 {
4398     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
4399     return CM_ERROR_BADOP;
4400 }
4401
4402 /* TRANS2_SESSION_SETUP */
4403 long
4404 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4405 {
4406     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
4407     return CM_ERROR_BADOP;
4408 }
4409
4410 struct smb_v2_referral {
4411     USHORT ServerType;
4412     USHORT ReferralFlags;
4413     ULONG  Proximity;
4414     ULONG  TimeToLive;
4415     USHORT DfsPathOffset;
4416     USHORT DfsAlternativePathOffset;
4417     USHORT NetworkAddressOffset;
4418 };
4419
4420 /* TRANS2_GET_DFS_REFERRAL */
4421 long
4422 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
4423 {
4424     /* This is a UNICODE only request (bit15 of Flags2) */
4425     /* The TID must be IPC$ */
4426
4427     /* The documentation for the Flags response field is contradictory */
4428
4429     /* Use Version 1 Referral Element Format */
4430     /* ServerType = 0; indicates the next server should be queried for the file */
4431     /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
4432     /* Node = UnicodeString of UNC path of the next share name */
4433 #ifdef DFS_SUPPORT
4434     long code = 0;
4435     int maxReferralLevel = 0;
4436     clientchar_t requestFileName[1024] = _C("");
4437     clientchar_t referralPath[1024] = _C("");
4438     smb_tran2Packet_t *outp = 0;
4439     cm_user_t *userp = 0;
4440     cm_scache_t *scp = 0;
4441     cm_scache_t *dscp = 0;
4442     cm_req_t req;
4443     CPINFO CodePageInfo;
4444     int i, nbnLen, reqLen, refLen;
4445     int idx;
4446
4447     smb_InitReq(&req);
4448
4449     maxReferralLevel = p->parmsp[0];
4450
4451     GetCPInfo(CP_ACP, &CodePageInfo);
4452     cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
4453
4454     osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
4455              maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
4456
4457     nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
4458     reqLen = (int)cm_ClientStrLen(requestFileName);
4459
4460     if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
4461         !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
4462         requestFileName[nbnLen+1] == '\\')
4463     {
4464         int found = 0;
4465
4466         if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
4467             !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
4468             found = 1;
4469             cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4470             refLen = reqLen;
4471         } else {
4472             userp = smb_GetTran2User(vcp, p);
4473             if (!userp) {
4474                 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
4475                 code = CM_ERROR_BADSMB;
4476                 goto done;
4477             }
4478
4479             /*
4480              * We have a requested path.  Check to see if it is something
4481              * we know about.
4482              *
4483              * But be careful because the name that we might be searching
4484              * for might be a known name with the final character stripped
4485              * off.
4486              */
4487             code = cm_NameI(cm_RootSCachep(userp, &req), &requestFileName[nbnLen+2],
4488                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
4489                             userp, NULL, &req, &scp);
4490             if (code == 0 ||
4491                 code == CM_ERROR_ALLDOWN ||
4492                 code == CM_ERROR_ALLBUSY ||
4493                 code == CM_ERROR_ALLOFFLINE ||
4494                 code == CM_ERROR_NOSUCHCELL ||
4495                 code == CM_ERROR_NOSUCHVOLUME ||
4496                 code == CM_ERROR_NOACCESS) {
4497                 /* Yes it is. */
4498                 found = 1;
4499                 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4500                 refLen = reqLen;
4501             } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
4502                 clientchar_t temp[1024];
4503                 clientchar_t pathName[1024];
4504                 clientchar_t *lastComponent;
4505                 /*
4506                  * we have a msdfs link somewhere in the path
4507                  * we should figure out where in the path the link is.
4508                  * and return it.
4509                  */
4510                 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
4511
4512                 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
4513
4514                 do {
4515                     if (dscp) {
4516                         cm_ReleaseSCache(dscp);
4517                         dscp = 0;
4518                     }
4519                     if (scp) {
4520                         cm_ReleaseSCache(scp);
4521                         scp = 0;
4522                     }
4523                     /* smb_StripLastComponent will strip "::$DATA" if present */
4524                     smb_StripLastComponent(pathName, &lastComponent, temp);
4525
4526                     code = cm_NameI(cm_RootSCachep(userp, &req), pathName,
4527                                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4528                                     userp, NULL, &req, &dscp);
4529                     if (code == 0) {
4530                         code = cm_NameI(dscp, ++lastComponent,
4531                                         CM_FLAG_CASEFOLD,
4532                                         userp, NULL, &req, &scp);
4533                         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
4534                             break;
4535                     }
4536                 } while (code == CM_ERROR_PATH_NOT_COVERED);
4537
4538                 /* scp should now be the DfsLink we are looking for */
4539                 if (scp) {
4540                     /* figure out how much of the input path was used */
4541                     reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
4542
4543                     cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
4544                                               referralPath, lengthof(referralPath));
4545                     refLen = (int)cm_ClientStrLen(referralPath);
4546                     found = 1;
4547                 }
4548             } else {
4549                 clientchar_t shareName[MAX_PATH + 1];
4550                 clientchar_t *p, *q;
4551                 /* we may have a sharename that is a volume reference */
4552
4553                 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
4554                 {
4555                     *q = *p;
4556                 }
4557                 *q = '\0';
4558
4559                 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
4560                     code = cm_NameI(cm_RootSCachep(userp, &req), _C(""),
4561                                     CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
4562                                     userp, p, &req, &scp);
4563                     free(p);
4564
4565                     if (code == 0) {
4566                         found = 1;
4567                         cm_ClientStrCpy(referralPath, lengthof(referralPath),
4568                                         requestFileName);
4569                         refLen = reqLen;
4570                     }
4571                 }
4572             }
4573         }
4574
4575         if (found)
4576         {
4577             USHORT * sp;
4578             struct smb_v2_referral * v2ref;
4579             outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
4580
4581             sp = (USHORT *)outp->datap;
4582             idx = 0;
4583             sp[idx++] = reqLen;   /* path consumed */
4584             sp[idx++] = 1;        /* number of referrals */
4585             sp[idx++] = 0x03;     /* flags */
4586 #ifdef DFS_VERSION_1
4587             sp[idx++] = 1;        /* Version Number */
4588             sp[idx++] = refLen + 4;  /* Referral Size */
4589             sp[idx++] = 1;        /* Type = SMB Server */
4590             sp[idx++] = 0;        /* Do not strip path consumed */
4591             for ( i=0;i<=refLen; i++ )
4592                 sp[i+idx] = referralPath[i];
4593 #else /* DFS_VERSION_2 */
4594             sp[idx++] = 2;      /* Version Number */
4595             sp[idx++] = sizeof(struct smb_v2_referral);     /* Referral Size */
4596             idx += (sizeof(struct smb_v2_referral) / 2);
4597             v2ref = (struct smb_v2_referral *) &sp[5];
4598             v2ref->ServerType = 1;  /* SMB Server */
4599             v2ref->ReferralFlags = 0x03;
4600             v2ref->Proximity = 0;   /* closest */
4601             v2ref->TimeToLive = 3600; /* seconds */
4602             v2ref->DfsPathOffset = idx * 2;
4603             v2ref->DfsAlternativePathOffset = idx * 2;
4604             v2ref->NetworkAddressOffset = 0;
4605             for ( i=0;i<=refLen; i++ )
4606                 sp[i+idx] = referralPath[i];
4607 #endif
4608         } else {
4609             code = CM_ERROR_NOSUCHPATH;
4610         }
4611     } else {
4612         code = CM_ERROR_NOSUCHPATH;
4613     }
4614
4615   done:
4616     if (dscp)
4617         cm_ReleaseSCache(dscp);
4618     if (scp)
4619         cm_ReleaseSCache(scp);
4620     if (userp)
4621         cm_ReleaseUser(userp);
4622     if (code == 0)
4623         smb_SendTran2Packet(vcp, outp, op);
4624     else
4625         smb_SendTran2Error(vcp, p, op, code);
4626     if (outp)
4627         smb_FreeTran2Packet(outp);
4628
4629     return 0;
4630 #else /* DFS_SUPPORT */
4631     osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4632     return CM_ERROR_NOSUCHDEVICE;
4633 #endif /* DFS_SUPPORT */
4634 }
4635
4636 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4637 long
4638 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4639 {
4640     /* This is a UNICODE only request (bit15 of Flags2) */
4641
4642     /* There is nothing we can do about this operation.  The client is going to
4643      * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4644      * Unfortunately, there is really nothing we can do about it other then log it
4645      * somewhere.  Even then I don't think there is anything for us to do.
4646      * So let's return an error value.
4647      */
4648
4649     osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4650     return CM_ERROR_BADOP;
4651 }
4652
4653 static long
4654 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4655                           clientchar_t * tidPathp, clientchar_t * relPathp,
4656                           int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4657 {
4658     long code = 0;
4659     cm_scache_t *scp;
4660     cm_scache_t *targetScp;                     /* target if scp is a symlink */
4661     afs_uint32 dosTime;
4662     FILETIME ft;
4663     unsigned short attr;
4664     unsigned long lattr;
4665     smb_dirListPatch_t *patchp;
4666     smb_dirListPatch_t *npatchp;
4667     afs_uint32 rights;
4668     afs_int32 mustFake = 0;
4669     afs_int32 nobulkstat = 0;
4670     clientchar_t path[AFSPATHMAX];
4671
4672     lock_ObtainWrite(&dscp->rw);
4673     code = cm_FindACLCache(dscp, userp, &rights);
4674     if (code == -1) {
4675         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4676                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4677         if (code == 0)
4678             cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4679         if (code == CM_ERROR_NOACCESS) {
4680             mustFake = 1;
4681             code = 0;
4682         }
4683     }
4684     lock_ReleaseWrite(&dscp->rw);
4685     if (code)
4686         goto cleanup;
4687
4688     if (!mustFake) {    /* Bulk Stat */
4689         afs_uint32 count;
4690         cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4691
4692         memset(bsp, 0, sizeof(cm_bulkStat_t));
4693         bsp->userp = userp;
4694
4695       restart_patchset:
4696         for (patchp = *dirPatchespp, count=0;
4697              patchp;
4698              patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4699             cm_scache_t *tscp = NULL;
4700             int i;
4701
4702             /* Do not look for a cm_scache_t or bulkstat an ioctl entry */
4703             if (patchp->flags & SMB_DIRLISTPATCH_IOCTL)
4704                 continue;
4705
4706             code = cm_GetSCache(&patchp->fid, &dscp->fid, &tscp, userp, reqp);
4707             if (code == 0) {
4708                 if (lock_TryWrite(&tscp->rw)) {
4709                     /* we have an entry that we can look at */
4710 #ifdef AFS_FREELANCE_CLIENT
4711                     if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4712                         code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4713                                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4714                         if (code == 0)
4715                             cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4716
4717                         lock_ReleaseWrite(&tscp->rw);
4718                         cm_ReleaseSCache(tscp);
4719                         continue;
4720                     }
4721 #endif /* AFS_FREELANCE_CLIENT */
4722                     if (!cm_EAccesFindEntry(userp, &tscp->fid) && cm_HaveCallback(tscp)) {
4723                         /* we have a callback on it.  Don't bother
4724                         * fetching this stat entry, since we're happy
4725                         * with the info we have.
4726                         */
4727                         lock_ReleaseWrite(&tscp->rw);
4728                         cm_ReleaseSCache(tscp);
4729                         continue;
4730                     }
4731
4732                     if (nobulkstat) {
4733                         code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4734                                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4735                         lock_ReleaseWrite(&tscp->rw);
4736                         cm_ReleaseSCache(tscp);
4737                         continue;
4738                     }
4739
4740                     lock_ReleaseWrite(&tscp->rw);
4741                 } /* got lock */
4742                 cm_ReleaseSCache(tscp);
4743             }   /* found entry */
4744
4745             i = bsp->counter++;
4746             bsp->fids[i].Volume = patchp->fid.volume;
4747             bsp->fids[i].Vnode = patchp->fid.vnode;
4748             bsp->fids[i].Unique = patchp->fid.unique;
4749
4750             if (bsp->counter == AFSCBMAX) {
4751                 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4752                 memset(bsp, 0, sizeof(cm_bulkStat_t));
4753                 bsp->userp = userp;
4754
4755                 if (code == CM_ERROR_BULKSTAT_FAILURE) {
4756                     /*
4757                     * If bulk stat cannot be used for this directory
4758                     * we must perform individual fetch status calls.
4759                     * Restart from the beginning of the patch series.
4760                     */
4761                     nobulkstat = 1;
4762                     goto restart_patchset;
4763                 }
4764             }
4765         }
4766
4767         if (bsp->counter > 0)
4768             code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4769
4770         free(bsp);
4771     }
4772
4773     for( patchp = *dirPatchespp;
4774          patchp;
4775          patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4776         cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4777                             relPathp ? relPathp : _C(""), patchp->dep->name);
4778         reqp->relPathp = path;
4779         reqp->tidPathp = tidPathp;
4780
4781         if (patchp->flags & SMB_DIRLISTPATCH_IOCTL) {
4782             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4783                errors in the client. */
4784             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4785                 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4786
4787                 /* 1969-12-31 23:59:59 +00 */
4788                 ft.dwHighDateTime = 0x19DB200;
4789                 ft.dwLowDateTime = 0x5BB78980;
4790
4791                 /* copy to Creation Time */
4792                 fa->creationTime = ft;
4793                 fa->lastAccessTime = ft;
4794                 fa->lastWriteTime = ft;
4795                 fa->lastChangeTime = ft;
4796                 fa->extFileAttributes = SMB_ATTR_SYSTEM | SMB_ATTR_HIDDEN;
4797             } else {
4798                 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4799
4800                 /* 1969-12-31 23:59:58 +00*/
4801                 dosTime = 0xEBBFBF7D;
4802
4803                 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4804                 fa->lastAccessDateTime = fa->creationDateTime;
4805                 fa->lastWriteDateTime = fa->creationDateTime;
4806                 fa->attributes = SMB_ATTR_SYSTEM|SMB_ATTR_HIDDEN;
4807             }
4808             continue;
4809         }
4810
4811         code = cm_GetSCache(&patchp->fid, &dscp->fid, &scp, userp, reqp);
4812         reqp->relPathp = reqp->tidPathp = NULL;
4813         if (code)
4814             continue;
4815
4816         lock_ObtainWrite(&scp->rw);
4817         if (mustFake || cm_EAccesFindEntry(userp, &scp->fid) || !cm_HaveCallback(scp)) {
4818             lock_ReleaseWrite(&scp->rw);
4819
4820             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4821                errors in the client. */
4822             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4823                 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4824
4825                 /* 1969-12-31 23:59:59 +00 */
4826                 ft.dwHighDateTime = 0x19DB200;
4827                 ft.dwLowDateTime = 0x5BB78980;
4828
4829                 /* copy to Creation Time */
4830                 fa->creationTime = ft;
4831                 fa->lastAccessTime = ft;
4832                 fa->lastWriteTime = ft;
4833                 fa->lastChangeTime = ft;
4834
4835                 switch (scp->fileType) {
4836                 case CM_SCACHETYPE_DIRECTORY:
4837                 case CM_SCACHETYPE_MOUNTPOINT:
4838                 case CM_SCACHETYPE_INVALID:
4839                     fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4840                     break;
4841                 case CM_SCACHETYPE_SYMLINK:
4842                     if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4843                         fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4844                     else
4845                         fa->extFileAttributes = SMB_ATTR_NORMAL;
4846                     break;
4847                 default:
4848                     /* if we get here we either have a normal file
4849                      * or we have a file for which we have never
4850                      * received status info.  In this case, we can
4851                      * check the even/odd value of the entry's vnode.
4852                      * odd means it is to be treated as a directory
4853                      * and even means it is to be treated as a file.
4854                      */
4855                     if (mustFake && (scp->fid.vnode & 0x1))
4856                         fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4857                     else
4858                         fa->extFileAttributes = SMB_ATTR_NORMAL;
4859                 }
4860                 /* merge in hidden attribute */
4861                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4862                     fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4863                 }
4864             } else {
4865                 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4866
4867                 /* 1969-12-31 23:59:58 +00*/
4868                 dosTime = 0xEBBFBF7D;
4869
4870                 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4871                 fa->lastAccessDateTime = fa->creationDateTime;
4872                 fa->lastWriteDateTime = fa->creationDateTime;
4873
4874                 /* set the attribute */
4875                 switch (scp->fileType) {
4876                 case CM_SCACHETYPE_DIRECTORY:
4877                 case CM_SCACHETYPE_MOUNTPOINT:
4878                 case CM_SCACHETYPE_INVALID:
4879                     fa->attributes = SMB_ATTR_DIRECTORY;
4880                     break;
4881                 case CM_SCACHETYPE_SYMLINK:
4882                     if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4883                         fa->attributes = SMB_ATTR_DIRECTORY;
4884                     else
4885                         fa->attributes = SMB_ATTR_NORMAL;
4886                     break;
4887                 default:
4888                     /* if we get here we either have a normal file
4889                      * or we have a file for which we have never
4890                      * received status info.  In this case, we can
4891                      * check the even/odd value of the entry's vnode.
4892                      * even means it is to be treated as a directory
4893                      * and odd means it is to be treated as a file.
4894                      */
4895                     if (mustFake && (scp->fid.vnode & 0x1))
4896                         fa->attributes = SMB_ATTR_DIRECTORY;
4897                     else
4898                         fa->attributes = SMB_ATTR_NORMAL;
4899                 }
4900
4901                 /* merge in hidden (dot file) attribute */
4902                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4903                     fa->attributes |= SMB_ATTR_HIDDEN;
4904                 }
4905             }
4906
4907             cm_ReleaseSCache(scp);
4908             continue;
4909         }
4910
4911         /* now watch for a symlink */
4912         code = 0;
4913         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4914             lock_ReleaseWrite(&scp->rw);
4915             cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4916                                 relPathp ? relPathp : _C(""), patchp->dep->name);
4917             reqp->relPathp = path;
4918             reqp->tidPathp = tidPathp;
4919             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4920             reqp->relPathp = reqp->tidPathp = NULL;
4921             if (code == 0) {
4922                 /* we have a more accurate file to use (the
4923                  * target of the symbolic link).  Otherwise,
4924                  * we'll just use the symlink anyway.
4925                  */
4926                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4927                           scp, targetScp);
4928                 cm_ReleaseSCache(scp);
4929                 scp = targetScp;
4930             }
4931             lock_ObtainWrite(&scp->rw);
4932         }
4933
4934         lock_ConvertWToR(&scp->rw);
4935
4936         if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4937             smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4938
4939             /* get filetime */
4940             cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4941
4942             fa->creationTime = ft;
4943             fa->lastAccessTime = ft;
4944             fa->lastWriteTime = ft;
4945             fa->lastChangeTime = ft;
4946
4947             /* Use length for both file length and alloc length */
4948             fa->endOfFile = scp->length;
4949             fa->allocationSize = scp->length;
4950
4951             /* Copy attributes */
4952             lattr = smb_ExtAttributes(scp);
4953             if ((code == CM_ERROR_NOSUCHPATH &&
4954                 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4955                 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4956                 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4957                 if (lattr == SMB_ATTR_NORMAL)
4958                     lattr = SMB_ATTR_DIRECTORY;
4959                 else
4960                     lattr |= SMB_ATTR_DIRECTORY;
4961             }
4962             /* merge in hidden (dot file) attribute */
4963             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4964                 if (lattr == SMB_ATTR_NORMAL)
4965                     lattr = SMB_ATTR_HIDDEN;
4966                 else
4967                     lattr |= SMB_ATTR_HIDDEN;
4968             }
4969
4970             fa->extFileAttributes = lattr;
4971         } else {
4972             smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4973
4974             /* get dos time */
4975             cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4976
4977             fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4978             fa->lastAccessDateTime = fa->creationDateTime;
4979             fa->lastWriteDateTime = fa->creationDateTime;
4980
4981             /* copy out file length and alloc length,
4982              * using the same for both
4983              */
4984             fa->dataSize = scp->length.LowPart;
4985             fa->allocationSize = scp->length.LowPart;
4986
4987             /* finally copy out attributes as short */
4988             attr = smb_Attributes(scp);
4989             /* merge in hidden (dot file) attribute */
4990             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4991                 if (lattr == SMB_ATTR_NORMAL)
4992                     lattr = SMB_ATTR_HIDDEN;
4993                 else
4994                     lattr |= SMB_ATTR_HIDDEN;
4995             }
4996             fa->attributes = attr;
4997         }
4998
4999         lock_ReleaseRead(&scp->rw);
5000         cm_ReleaseSCache(scp);
5001     }
5002
5003     /* now free the patches */
5004     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
5005         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
5006         free(patchp);
5007     }
5008
5009     /* and mark the list as empty */
5010     *dirPatchespp = NULL;
5011
5012   cleanup:
5013     return code;
5014 }
5015
5016 /* smb_ReceiveTran2SearchDir implements both
5017  * Tran2_Find_First and Tran2_Find_Next
5018  */
5019 #define TRAN2_FIND_FLAG_CLOSE_SEARCH            0x01
5020 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END     0x02
5021 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS      0x04
5022 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH         0x08
5023 #define TRAN2_FIND_FLAG_BACKUP_INTENT           0x10
5024
5025 /* this is an optimized handler for T2SearchDir that handles the case
5026    where there are no wildcards in the search path.  I.e. an
5027    application is using FindFirst(Ex) to get information about a
5028    single file or directory.  It will attempt to do a single lookup.
5029    If that fails, then smb_ReceiveTran2SearchDir() will fall back to
5030    the usual mechanism.
5031
5032    This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
5033
5034    TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
5035    */
5036 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
5037 {
5038     int attribute;
5039     long nextCookie;
5040     long code = 0, code2 = 0;
5041     clientchar_t *pathp = 0;
5042     int maxCount;
5043     smb_dirListPatch_t *dirListPatchesp;
5044     smb_dirListPatch_t *curPatchp;
5045     size_t orbytes;                     /* # of bytes in this output record */
5046     size_t ohbytes;                     /* # of bytes, except file name */
5047     size_t onbytes;                     /* # of bytes in name, incl. term. null */
5048     cm_scache_t *scp = NULL;
5049     cm_scache_t *targetScp = NULL;
5050     cm_user_t *userp = NULL;
5051     char *op;                           /* output data ptr */
5052     char *origOp;                       /* original value of op */
5053     cm_space_t *spacep;                 /* for pathname buffer */
5054     unsigned long maxReturnData;        /* max # of return data */
5055     long maxReturnParms;                /* max # of return parms */
5056     long bytesInBuffer;                 /* # data bytes in the output buffer */
5057     clientchar_t *maskp;                        /* mask part of path */
5058     int infoLevel;
5059     int searchFlags;
5060     int eos;
5061     smb_tran2Packet_t *outp;            /* response packet */
5062     clientchar_t *tidPathp = 0;
5063     int align;
5064     clientchar_t shortName[13];         /* 8.3 name if needed */
5065     int NeedShortName;
5066     clientchar_t *shortNameEnd;
5067     cm_dirEntry_t * dep = NULL;
5068     cm_req_t req;
5069     char * s;
5070     void * attrp = NULL;
5071     smb_tran2Find_t * fp;
5072     int afs_ioctl = 0;                  /* is this query for _._AFS_IOCTL_._? */
5073     cm_dirFid_t dfid;
5074
5075     smb_InitReq(&req);
5076
5077     eos = 0;
5078     osi_assertx(p->opcode == 1, "invalid opcode");
5079
5080     /* find first; obtain basic parameters from request */
5081
5082     /* note that since we are going to failover to regular
5083      * processing at smb_ReceiveTran2SearchDir(), we shouldn't
5084      * modify any of the input parameters here. */
5085     attribute = p->parmsp[0];
5086     maxCount = p->parmsp[1];
5087     infoLevel = p->parmsp[3];
5088     searchFlags = p->parmsp[2];
5089     pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
5090     nextCookie = 0;
5091     maskp = cm_ClientStrRChr(pathp,  '\\');
5092     if (maskp == NULL)
5093         maskp = pathp;
5094     else
5095         maskp++;        /* skip over backslash */
5096     /* track if this is likely to match a lot of entries */
5097
5098     osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
5099              osi_LogSaveClientString(smb_logp, pathp),
5100              osi_LogSaveClientString(smb_logp, maskp));
5101
5102     switch ( infoLevel ) {
5103     case SMB_INFO_STANDARD:
5104         s = "InfoStandard";
5105         ohbytes = sizeof(fp->u.FstandardInfo);
5106         break;
5107
5108     case SMB_INFO_QUERY_EA_SIZE:
5109         ohbytes = sizeof(fp->u.FeaSizeInfo);
5110         s = "InfoQueryEaSize";
5111         break;
5112
5113     case SMB_INFO_QUERY_EAS_FROM_LIST:
5114         ohbytes = sizeof(fp->u.FeasFromListInfo);
5115         s = "InfoQueryEasFromList";
5116         break;
5117
5118     case SMB_FIND_FILE_DIRECTORY_INFO:
5119         s = "FindFileDirectoryInfo";
5120         ohbytes = sizeof(fp->u.FfileDirectoryInfo);
5121         break;
5122
5123     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5124         s = "FindFileFullDirectoryInfo";
5125         ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
5126         break;
5127
5128     case SMB_FIND_FILE_NAMES_INFO:
5129         s = "FindFileNamesInfo";
5130         ohbytes = sizeof(fp->u.FfileNamesInfo);
5131         break;
5132
5133     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5134         s = "FindFileBothDirectoryInfo";
5135         ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5136         break;
5137
5138     default:
5139         s = "unknownInfoLevel";
5140         ohbytes = 0;
5141     }
5142
5143     osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
5144
5145     osi_Log4(smb_logp,
5146              "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5147              attribute, infoLevel, maxCount, searchFlags);
5148
5149     if (ohbytes == 0) {
5150         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5151         return CM_ERROR_INVAL;
5152     }
5153
5154     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5155         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;     /* no resume keys */
5156
5157     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5158         ohbytes += 4;
5159
5160     dirListPatchesp = NULL;
5161
5162     maxReturnData = p->maxReturnData;
5163     maxReturnParms = 10;        /* return params for findfirst, which
5164                                    is the only one we handle.*/
5165
5166     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5167                                       maxReturnData);
5168
5169     osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
5170              maxCount, osi_LogSaveClientString(smb_logp, pathp));
5171
5172     /* bail out if request looks bad */
5173     if (!pathp) {
5174         smb_FreeTran2Packet(outp);
5175         return CM_ERROR_BADSMB;
5176     }
5177
5178     userp = smb_GetTran2User(vcp, p);
5179     if (!userp) {
5180         osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
5181         smb_FreeTran2Packet(outp);
5182         return CM_ERROR_BADSMB;
5183     }
5184
5185     /* try to get the vnode for the path name next */
5186     spacep = cm_GetSpace();
5187     /* smb_StripLastComponent will strip "::$DATA" if present */
5188     smb_StripLastComponent(spacep->wdata, NULL, pathp);
5189     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5190     if (code) {
5191         cm_ReleaseUser(userp);
5192         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5193         smb_FreeTran2Packet(outp);
5194         return 0;
5195     }
5196
5197     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
5198                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5199                     userp, tidPathp, &req, &scp);
5200     cm_FreeSpace(spacep);
5201
5202     if (code) {
5203         cm_ReleaseUser(userp);
5204         smb_SendTran2Error(vcp, p, opx, code);
5205         smb_FreeTran2Packet(outp);
5206         return 0;
5207     }
5208
5209 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5210     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5211         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5212         cm_ReleaseSCache(scp);
5213         cm_ReleaseUser(userp);
5214         if ( WANTS_DFS_PATHNAMES(p) || pnc )
5215             code = CM_ERROR_PATH_NOT_COVERED;
5216         else
5217             code = CM_ERROR_NOSUCHPATH;
5218         smb_SendTran2Error(vcp, p, opx, code);
5219         smb_FreeTran2Packet(outp);
5220         return 0;
5221     }
5222 #endif /* DFS_SUPPORT */
5223     osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
5224
5225     afs_ioctl = (cm_ClientStrCmpI(maskp, CM_IOCTL_FILENAME_NOSLASH_W) == 0);
5226
5227     /*
5228      * If we are not searching for _._AFS_IOCTL_._, then we need to obtain
5229      * the target scp.
5230      */
5231     if (!afs_ioctl) {
5232         /* now do a single case sensitive lookup for the file in question */
5233         code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetScp);
5234
5235         /*
5236          * if a case sensitive match failed, we try a case insensitive
5237          * one next.
5238          */
5239         if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)
5240             code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetScp);
5241
5242         if (code == 0 && targetScp->fid.vnode == 0) {
5243             cm_ReleaseSCache(targetScp);
5244             code = CM_ERROR_NOSUCHFILE;
5245         }
5246
5247         if (code) {
5248             /*
5249              * if we can't find the directory entry, this block will
5250              * return CM_ERROR_NOSUCHFILE, which we will pass on to
5251              * smb_ReceiveTran2SearchDir().
5252              */
5253             cm_ReleaseSCache(scp);
5254             cm_ReleaseUser(userp);
5255             if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5256                 smb_SendTran2Error(vcp, p, opx, code);
5257                 code = 0;
5258             }
5259             smb_FreeTran2Packet(outp);
5260             return code;
5261         }
5262     }
5263
5264     /* now that we have the target in sight, we proceed with filling
5265        up the return data. */
5266
5267     op = origOp = outp->datap;
5268     bytesInBuffer = 0;
5269
5270     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5271         /* skip over resume key */
5272         op += 4;
5273     }
5274
5275     fp = (smb_tran2Find_t *) op;
5276
5277     if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5278         cm_shortNames && !cm_Is8Dot3(maskp)) {
5279
5280         /*
5281          * Since the _._AFS_IOCTL_._ file does not actually exist
5282          * we will make up a per directory FID equivalent to the
5283          * directory vnode and the uniqifier 0.
5284          */
5285         if (afs_ioctl) {
5286             dfid.vnode = htonl(scp->fid.vnode);
5287             dfid.unique = htonl(0);
5288         } else {
5289             dfid.vnode = htonl(targetScp->fid.vnode);
5290             dfid.unique = htonl(targetScp->fid.unique);
5291         }
5292
5293         cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
5294         NeedShortName = 1;
5295     } else {
5296         NeedShortName = 0;
5297     }
5298
5299     osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
5300              ntohl(dfid.vnode),
5301              ntohl(dfid.unique),
5302              osi_LogSaveClientString(smb_logp, pathp),
5303              (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5304
5305     /* Eliminate entries that don't match requested attributes */
5306     if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
5307         smb_IsDotFile(maskp)) {
5308
5309         code = CM_ERROR_NOSUCHFILE;
5310         osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
5311         goto skip_file;
5312
5313     }
5314
5315     if (!(attribute & SMB_ATTR_DIRECTORY) &&
5316         !afs_ioctl &&
5317         (targetScp->fileType == CM_SCACHETYPE_DIRECTORY ||
5318          targetScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
5319          targetScp->fileType == CM_SCACHETYPE_DFSLINK ||
5320          targetScp->fileType == CM_SCACHETYPE_INVALID)) {
5321
5322         code = CM_ERROR_NOSUCHFILE;
5323         osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
5324         goto skip_file;
5325
5326     }
5327
5328     /* add header to name & term. null */
5329     onbytes = 0;
5330     smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5331     orbytes = ohbytes + onbytes;
5332
5333     /* now, we round up the record to a 4 byte alignment, and we make
5334      * sure that we have enough room here for even the aligned version
5335      * (so we don't have to worry about an * overflow when we pad
5336      * things out below).  That's the reason for the alignment
5337      * arithmetic below.
5338      */
5339     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5340         align = (4 - (orbytes & 3)) & 3;
5341     else
5342         align = 0;
5343
5344     if (orbytes + align > maxReturnData) {
5345
5346         /* even though this request is unlikely to succeed with a
5347            failover, we do it anyway. */
5348         code = CM_ERROR_NOSUCHFILE;
5349         osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5350                  maxReturnData);
5351         goto skip_file;
5352     }
5353
5354     /* this is one of the entries to use: it is not deleted and it
5355      * matches the star pattern we're looking for.  Put out the name,
5356      * preceded by its length.
5357      */
5358     /* First zero everything else */
5359     memset(origOp, 0, orbytes);
5360
5361     onbytes = 0;
5362     smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5363
5364     switch (infoLevel) {
5365     case SMB_INFO_STANDARD:
5366         fp->u.FstandardInfo.fileNameLength = onbytes;
5367         attrp = &fp->u.FstandardInfo.fileAttrs;
5368         break;
5369
5370     case SMB_INFO_QUERY_EA_SIZE:
5371         fp->u.FeaSizeInfo.fileNameLength = onbytes;
5372         attrp = &fp->u.FeaSizeInfo.fileAttrs;
5373         fp->u.FeaSizeInfo.eaSize = 0;
5374         break;
5375
5376     case SMB_INFO_QUERY_EAS_FROM_LIST:
5377         fp->u.FeasFromListInfo.fileNameLength = onbytes;
5378         attrp = &fp->u.FeasFromListInfo.fileAttrs;
5379         fp->u.FeasFromListInfo.eaSize = 0;
5380         break;
5381
5382     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5383         if (NeedShortName) {
5384 #ifdef SMB_UNICODE
5385             int nchars;
5386
5387             nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5388                                             fp->u.FfileBothDirectoryInfo.shortName,
5389                                             sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5390             if (nchars > 0)
5391                 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5392             else
5393                 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5394             fp->u.FfileBothDirectoryInfo.reserved = 0;
5395 #else
5396             strcpy(fp->u.FfileBothDirectoryInfo.shortName,
5397                    shortName);
5398             fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5399 #endif
5400     }
5401         /* Fallthrough */
5402
5403     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5404         fp->u.FfileFullDirectoryInfo.eaSize = 0;
5405         /* Fallthrough */
5406
5407     case SMB_FIND_FILE_DIRECTORY_INFO:
5408         fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
5409         fp->u.FfileDirectoryInfo.fileIndex = 0;
5410         attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5411         fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5412         break;
5413
5414     case SMB_FIND_FILE_NAMES_INFO:
5415         fp->u.FfileNamesInfo.nextEntryOffset = 0;
5416         fp->u.FfileNamesInfo.fileIndex = 0;
5417         fp->u.FfileNamesInfo.fileNameLength = onbytes;
5418         break;
5419
5420     default:
5421         /* we shouldn't hit this case */
5422         osi_assertx(FALSE, "Unknown query type");
5423     }
5424
5425     if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5426         osi_assert(attrp != NULL);
5427
5428         curPatchp = malloc(sizeof(*curPatchp));
5429         osi_QAdd((osi_queue_t **) &dirListPatchesp,
5430                  &curPatchp->q);
5431         curPatchp->dptr = attrp;
5432
5433         if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
5434             curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5435         } else {
5436             curPatchp->flags = 0;
5437         }
5438
5439         /* temp */
5440         {
5441             int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
5442             dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
5443             cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
5444         }
5445
5446         if (afs_ioctl) {
5447             cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, scp->fid.vnode, 0);
5448             dep->fid.vnode = scp->fid.vnode;
5449             dep->fid.unique = 0;
5450             curPatchp->flags |= SMB_DIRLISTPATCH_IOCTL;
5451         } else {
5452             cm_SetFid(&curPatchp->fid, targetScp->fid.cell, targetScp->fid.volume, targetScp->fid.vnode, targetScp->fid.unique);
5453             dep->fid.vnode = targetScp->fid.vnode;
5454             dep->fid.unique = targetScp->fid.unique;
5455         }
5456
5457         curPatchp->dep = dep;
5458     }
5459
5460     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5461         /* put out resume key */
5462         *((u_long *)origOp) = 0;
5463     }
5464
5465     /* Adjust byte ptr and count */
5466     origOp += orbytes;  /* skip entire record */
5467     bytesInBuffer += orbytes;
5468
5469     /* and pad the record out */
5470     while (--align >= 0) {
5471         *origOp++ = 0;
5472         bytesInBuffer++;
5473     }
5474
5475     /* apply the patches */
5476     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
5477
5478     outp->parmsp[0] = 0;
5479     outp->parmsp[1] = 1;        /* number of names returned */
5480     outp->parmsp[2] = 1;        /* end of search */
5481     outp->parmsp[3] = 0;        /* nothing wrong with EAS */
5482     outp->parmsp[4] = 0;
5483
5484     outp->totalParms = 10;      /* in bytes */
5485
5486     outp->totalData = bytesInBuffer;
5487
5488     osi_Log0(smb_logp, "T2SDSingle done.");
5489
5490     if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5491         if (code)
5492             smb_SendTran2Error(vcp, p, opx, code);
5493         else
5494             smb_SendTran2Packet(vcp, outp, opx);
5495         code = 0;
5496     }
5497
5498  skip_file:
5499     smb_FreeTran2Packet(outp);
5500     if (dep)
5501         free(dep);
5502     if (scp)
5503         cm_ReleaseSCache(scp);
5504     if (targetScp)
5505         cm_ReleaseSCache(targetScp);
5506     cm_ReleaseUser(userp);
5507
5508     return code;
5509 }
5510
5511
5512 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
5513 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
5514 {
5515     int attribute;
5516     long nextCookie;
5517     char *tp;
5518     long code = 0, code2 = 0;
5519     clientchar_t *pathp;
5520     cm_dirEntry_t *dep = 0;
5521     int maxCount;
5522     smb_dirListPatch_t *dirListPatchesp = 0;
5523     smb_dirListPatch_t *curPatchp = 0;
5524     cm_buf_t *bufferp;
5525     long temp;
5526     size_t orbytes;                     /* # of bytes in this output record */
5527     size_t ohbytes;                     /* # of bytes, except file name */
5528     size_t onbytes;                     /* # of bytes in name, incl. term. null */
5529     osi_hyper_t dirLength;
5530     osi_hyper_t bufferOffset;
5531     osi_hyper_t curOffset;
5532     osi_hyper_t thyper;
5533     smb_dirSearch_t *dsp;
5534     cm_scache_t *scp;
5535     long entryInDir;
5536     long entryInBuffer;
5537     cm_pageHeader_t *pageHeaderp;
5538     cm_user_t *userp = NULL;
5539     int slotInPage;
5540     int returnedNames;
5541     long nextEntryCookie;
5542     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
5543     char *op;                   /* output data ptr */
5544     char *origOp;                       /* original value of op */
5545     cm_space_t *spacep;         /* for pathname buffer */
5546     unsigned long maxReturnData;                /* max # of return data */
5547     unsigned long maxReturnParms;               /* max # of return parms */
5548     long bytesInBuffer;         /* # data bytes in the output buffer */
5549     int starPattern;
5550     clientchar_t *maskp;                        /* mask part of path */
5551     int infoLevel;
5552     int searchFlags;
5553     int eos;
5554     smb_tran2Packet_t *outp;    /* response packet */
5555     clientchar_t *tidPathp;
5556     unsigned int align;
5557     clientchar_t shortName[13];         /* 8.3 name if needed */
5558     int NeedShortName;
5559     int foundInexact;
5560     clientchar_t *shortNameEnd;
5561     int fileType;
5562     cm_fid_t fid;
5563     cm_req_t req;
5564     void * attrp;
5565     char * s;
5566     smb_tran2Find_t * fp;
5567
5568     smb_InitReq(&req);
5569
5570     eos = 0;
5571     if (p->opcode == 1) {
5572         /* find first; obtain basic parameters from request */
5573         attribute = p->parmsp[0];
5574         maxCount = p->parmsp[1];
5575         infoLevel = p->parmsp[3];
5576         searchFlags = p->parmsp[2];
5577         pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
5578         nextCookie = 0;
5579         maskp = cm_ClientStrRChr(pathp,  '\\');
5580         if (maskp == NULL)
5581             maskp = pathp;
5582         else
5583             maskp++;    /* skip over backslash */
5584
5585         /* track if this is likely to match a lot of entries */
5586         starPattern = smb_V3IsStarMask(maskp);
5587
5588 #ifndef NOFINDFIRSTOPTIMIZE
5589         if (!starPattern) {
5590             /* if this is for a single directory or file, we let the
5591                optimized routine handle it.  The only error it
5592                returns is CM_ERROR_NOSUCHFILE.  The  */
5593             code = smb_T2SearchDirSingle(vcp, p, opx);
5594
5595             /* we only failover if we see a CM_ERROR_NOSUCHFILE */
5596             if (code != CM_ERROR_NOSUCHFILE) {
5597 #ifdef USE_BPLUS
5598                 /* unless we are using the BPlusTree */
5599                 if (code == CM_ERROR_BPLUS_NOMATCH)
5600                     code = CM_ERROR_NOSUCHFILE;
5601 #endif /* USE_BPLUS */
5602                 return code;
5603             }
5604         }
5605 #endif  /* NOFINDFIRSTOPTIMIZE */
5606         dir_enums++;
5607
5608         dsp = smb_NewDirSearch(1);
5609         dsp->attribute = attribute;
5610         cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask),  maskp);        /* and save mask */
5611     }
5612     else {
5613         osi_assertx(p->opcode == 2, "invalid opcode");
5614         /* find next; obtain basic parameters from request or open dir file */
5615         dsp = smb_FindDirSearch(p->parmsp[0]);
5616         maxCount = p->parmsp[1];
5617         infoLevel = p->parmsp[2];
5618         nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
5619         searchFlags = p->parmsp[5];
5620         if (!dsp) {
5621             osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
5622                      p->parmsp[0], nextCookie);
5623             return CM_ERROR_BADFD;
5624         }
5625         attribute = dsp->attribute;
5626         pathp = NULL;
5627         maskp = dsp->mask;
5628         starPattern = 1;        /* assume, since required a Find Next */
5629     }
5630
5631     switch ( infoLevel ) {
5632     case SMB_INFO_STANDARD:
5633         s = "InfoStandard";
5634         ohbytes = sizeof(fp->u.FstandardInfo);
5635         break;
5636
5637     case SMB_INFO_QUERY_EA_SIZE:
5638         ohbytes = sizeof(fp->u.FeaSizeInfo);
5639         s = "InfoQueryEaSize";
5640         break;
5641
5642     case SMB_INFO_QUERY_EAS_FROM_LIST:
5643         ohbytes = sizeof(fp->u.FeasFromListInfo);
5644         s = "InfoQueryEasFromList";
5645         break;
5646
5647     case SMB_FIND_FILE_DIRECTORY_INFO:
5648         s = "FindFileDirectoryInfo";
5649         ohbytes = sizeof(fp->u.FfileDirectoryInfo);
5650         break;
5651
5652     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5653         s = "FindFileFullDirectoryInfo";
5654         ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
5655         break;
5656
5657     case SMB_FIND_FILE_NAMES_INFO:
5658         s = "FindFileNamesInfo";
5659         ohbytes = sizeof(fp->u.FfileNamesInfo);
5660         break;
5661
5662     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5663         s = "FindFileBothDirectoryInfo";
5664         ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5665         break;
5666
5667     default:
5668         s = "unknownInfoLevel";
5669         ohbytes = 0;
5670     }
5671
5672     osi_Log1(smb_logp, "T2 search dir info level: %s", s);
5673
5674     osi_Log4(smb_logp,
5675               "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5676               attribute, infoLevel, maxCount, searchFlags);
5677
5678     osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
5679               p->opcode, dsp->cookie, nextCookie);
5680
5681     if (ohbytes == 0) {
5682         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5683         smb_ReleaseDirSearch(dsp);
5684         return CM_ERROR_INVAL;
5685     }
5686
5687     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5688         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;     /* no resume keys */
5689
5690     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5691         ohbytes += 4;
5692
5693     dirListPatchesp = NULL;
5694
5695     maxReturnData = p->maxReturnData;
5696     if (p->opcode == 1) /* find first */
5697         maxReturnParms = 10;    /* bytes */
5698     else
5699         maxReturnParms = 8;     /* bytes */
5700
5701     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5702                                       maxReturnData);
5703
5704     if (maxCount > 500)
5705         maxCount = 500;
5706
5707     osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5708              maxCount, osi_LogSaveClientString(smb_logp, pathp));
5709
5710     /* bail out if request looks bad */
5711     if (p->opcode == 1 && !pathp) {
5712         smb_ReleaseDirSearch(dsp);
5713         smb_FreeTran2Packet(outp);
5714         return CM_ERROR_BADSMB;
5715     }
5716
5717     osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5718              dsp->cookie, nextCookie, attribute);
5719
5720     userp = smb_GetTran2User(vcp, p);
5721     if (!userp) {
5722         osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5723         smb_ReleaseDirSearch(dsp);
5724         smb_FreeTran2Packet(outp);
5725         return CM_ERROR_BADSMB;
5726     }
5727
5728     /* try to get the vnode for the path name next */
5729     lock_ObtainMutex(&dsp->mx);
5730     if (dsp->scp) {
5731         scp = dsp->scp;
5732         osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5733         cm_HoldSCache(scp);
5734         code = 0;
5735     } else {
5736         spacep = cm_GetSpace();
5737         /* smb_StripLastComponent will strip "::$DATA" if present */
5738         smb_StripLastComponent(spacep->wdata, NULL, pathp);
5739         code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5740         if (code) {
5741             cm_ReleaseUser(userp);
5742             smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5743             smb_FreeTran2Packet(outp);
5744             lock_ReleaseMutex(&dsp->mx);
5745             smb_DeleteDirSearch(dsp);
5746             smb_ReleaseDirSearch(dsp);
5747             return 0;
5748         }
5749
5750         cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5751         cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5752
5753         code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
5754                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5755                         userp, tidPathp, &req, &scp);
5756         cm_FreeSpace(spacep);
5757
5758         if (code == 0) {
5759 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5760             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5761                 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5762                 cm_ReleaseSCache(scp);
5763                 cm_ReleaseUser(userp);
5764                 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5765                     code = CM_ERROR_PATH_NOT_COVERED;
5766                 else
5767                     code = CM_ERROR_NOSUCHPATH;
5768                 smb_SendTran2Error(vcp, p, opx, code);
5769                 smb_FreeTran2Packet(outp);
5770                 lock_ReleaseMutex(&dsp->mx);
5771                 smb_DeleteDirSearch(dsp);
5772                 smb_ReleaseDirSearch(dsp);
5773                 return 0;
5774             }
5775 #endif /* DFS_SUPPORT */
5776             dsp->scp = scp;
5777             osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5778             /* we need one hold for the entry we just stored into,
5779              * and one for our own processing.  When we're done
5780              * with this function, we'll drop the one for our own
5781              * processing.  We held it once from the namei call,
5782              * and so we do another hold now.
5783              */
5784             cm_HoldSCache(scp);
5785             dsp->flags |= SMB_DIRSEARCH_BULKST;
5786         }
5787     }
5788     lock_ReleaseMutex(&dsp->mx);
5789     if (code) {
5790         cm_ReleaseUser(userp);
5791         smb_FreeTran2Packet(outp);
5792         smb_DeleteDirSearch(dsp);
5793         smb_ReleaseDirSearch(dsp);
5794         return code;
5795     }
5796
5797     /* get the directory size */
5798     lock_ObtainWrite(&scp->rw);
5799     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5800                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5801     if (code) {
5802         lock_ReleaseWrite(&scp->rw);
5803         cm_ReleaseSCache(scp);
5804         cm_ReleaseUser(userp);
5805         smb_FreeTran2Packet(outp);
5806         smb_DeleteDirSearch(dsp);
5807         smb_ReleaseDirSearch(dsp);
5808         return code;
5809     }
5810
5811     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5812
5813   startsearch:
5814     dirLength = scp->length;
5815     bufferp = NULL;
5816     bufferOffset.LowPart = bufferOffset.HighPart = 0;
5817     curOffset.HighPart = 0;
5818     curOffset.LowPart = nextCookie;
5819     origOp = outp->datap;
5820
5821     foundInexact = 0;
5822     code = 0;
5823     returnedNames = 0;
5824     bytesInBuffer = 0;
5825     while (1) {
5826         normchar_t normName[MAX_PATH]; /* Normalized name */
5827         clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5828
5829         op = origOp;
5830         if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5831             /* skip over resume key */
5832             op += 4;
5833
5834         fp = (smb_tran2Find_t *) op;
5835
5836         /* make sure that curOffset.LowPart doesn't point to the first
5837          * 32 bytes in the 2nd through last dir page, and that it doesn't
5838          * point at the first 13 32-byte chunks in the first dir page,
5839          * since those are dir and page headers, and don't contain useful
5840          * information.
5841          */
5842         temp = curOffset.LowPart & (2048-1);
5843         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5844             /* we're in the first page */
5845             if (temp < 13*32) temp = 13*32;
5846         }
5847         else {
5848             /* we're in a later dir page */
5849             if (temp < 32) temp = 32;
5850         }
5851
5852         /* make sure the low order 5 bits are zero */
5853         temp &= ~(32-1);
5854
5855         /* now put temp bits back ito curOffset.LowPart */
5856         curOffset.LowPart &= ~(2048-1);
5857         curOffset.LowPart |= temp;
5858
5859         /* check if we've passed the dir's EOF */
5860         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5861             osi_Log0(smb_logp, "T2 search dir passed eof");
5862             eos = 1;
5863             break;
5864         }
5865
5866         /* check if we've returned all the names that will fit in the
5867          * response packet; we check return count as well as the number
5868          * of bytes requested.  We check the # of bytes after we find
5869          * the dir entry, since we'll need to check its size.
5870          */
5871         if (returnedNames >= maxCount) {
5872             osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5873                       returnedNames, maxCount);
5874             break;
5875         }
5876
5877         /* when we have obtained as many entries as can be processed in
5878          * a single Bulk Status call to the file server, apply the dir listing
5879          * patches.
5880          */
5881         if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5882             lock_ReleaseWrite(&scp->rw);
5883             code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5884                                                dsp->relPath, infoLevel, userp, &req);
5885             lock_ObtainWrite(&scp->rw);
5886         }
5887         /* Then check to see if we have time left to process more entries */
5888         if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5889             osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5890             break;
5891         }
5892
5893         /* see if we can use the bufferp we have now; compute in which
5894          * page the current offset would be, and check whether that's
5895          * the offset of the buffer we have.  If not, get the buffer.
5896          */
5897         thyper.HighPart = curOffset.HighPart;
5898         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5899         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5900             /* wrong buffer */
5901             if (bufferp) {
5902                 buf_Release(bufferp);
5903                 bufferp = NULL;
5904             }
5905             lock_ReleaseWrite(&scp->rw);
5906             code = buf_Get(scp, &thyper, &req, &bufferp);
5907             lock_ObtainWrite(&scp->rw);
5908             if (code) {
5909                 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5910                 break;
5911             }
5912
5913             bufferOffset = thyper;
5914
5915             /* now get the data in the cache */
5916             while (1) {
5917                 code = cm_SyncOp(scp, bufferp, userp, &req,
5918                                  PRSFS_LOOKUP,
5919                                  CM_SCACHESYNC_NEEDCALLBACK
5920                                  | CM_SCACHESYNC_READ);
5921                 if (code) {
5922                     osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5923                     break;
5924                 }
5925
5926                 if (cm_HaveBuffer(scp, bufferp, 0)) {
5927                     osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5928                     cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5929                     break;
5930                 }
5931
5932                 /* otherwise, load the buffer and try again */
5933                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5934                                     &req);
5935                 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5936                 if (code) {
5937                     osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5938                               scp, bufferp, code);
5939                     break;
5940                 }
5941             }
5942             if (code) {
5943                 buf_Release(bufferp);
5944                 bufferp = NULL;
5945                 break;
5946             }
5947         }       /* if (wrong buffer) ... */
5948
5949         /* now we have the buffer containing the entry we're interested
5950          * in; copy it out if it represents a non-deleted entry.
5951          */
5952         entryInDir = curOffset.LowPart & (2048-1);
5953         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5954
5955         /* page header will help tell us which entries are free.  Page
5956          * header can change more often than once per buffer, since
5957          * AFS 3 dir page size may be less than (but not more than)
5958          * a buffer package buffer.
5959          */
5960         /* only look intra-buffer */
5961         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5962         temp &= ~(2048 - 1);    /* turn off intra-page bits */
5963         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5964
5965         /* now determine which entry we're looking at in the page.
5966          * If it is free (there's a free bitmap at the start of the
5967          * dir), we should skip these 32 bytes.
5968          */
5969         slotInPage = (entryInDir & 0x7e0) >> 5;
5970         if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5971             (1 << (slotInPage & 0x7)))) {
5972             /* this entry is free */
5973             numDirChunks = 1;   /* only skip this guy */
5974             goto nextEntry;
5975         }
5976
5977         tp = bufferp->datap + entryInBuffer;
5978         dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
5979
5980         /* while we're here, compute the next entry's location, too,
5981          * since we'll need it when writing out the cookie into the dir
5982          * listing stream.
5983          *
5984          * XXXX Probably should do more sanity checking.
5985          */
5986         numDirChunks = cm_NameEntries(dep->name, &onbytes);
5987
5988         /* compute offset of cookie representing next entry */
5989         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5990
5991         if (dep->fid.vnode == 0)
5992             goto nextEntry;             /* This entry is not in use */
5993
5994         if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5995             cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5996
5997             osi_Log1(smb_logp, "Skipping entry [%s].  Can't convert or normalize FS String",
5998                      osi_LogSaveString(smb_logp, dep->name));
5999             goto nextEntry;
6000         }
6001
6002         /* Need 8.3 name? */
6003         NeedShortName = 0;
6004         if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
6005             cm_shortNames &&
6006             !cm_Is8Dot3(cfileName)) {
6007             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
6008             NeedShortName = 1;
6009         }
6010
6011         osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
6012                  dep->fid.vnode, dep->fid.unique,
6013                  osi_LogSaveClientString(smb_logp, cfileName),
6014                  NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
6015
6016         /* When matching, we are using doing a case fold if we have a wildcard mask.
6017          * If we get a non-wildcard match, it's a lookup for a specific file.
6018          */
6019         if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
6020             (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
6021         {
6022             /* Eliminate entries that don't match requested attributes */
6023             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
6024                 smb_IsDotFile(cfileName)) {
6025                 osi_Log0(smb_logp, "T2 search dir skipping hidden");
6026                 goto nextEntry; /* no hidden files */
6027             }
6028
6029             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
6030             {
6031                 /* We have already done the cm_TryBulkStat above */
6032                 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
6033                           ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
6034                 fileType = cm_FindFileType(&fid);
6035                 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
6036                  * "has filetype %d", dep->name, fileType);
6037                  */
6038                 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
6039                      fileType == CM_SCACHETYPE_MOUNTPOINT ||
6040                      fileType == CM_SCACHETYPE_DFSLINK ||
6041                      fileType == CM_SCACHETYPE_INVALID)
6042                     osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
6043                 goto nextEntry;
6044             }
6045
6046             /* finally check if this name will fit */
6047             onbytes = 0;
6048             smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
6049             orbytes = ohbytes + onbytes;
6050
6051             /* now, we round up the record to a 4 byte alignment,
6052              * and we make sure that we have enough room here for
6053              * even the aligned version (so we don't have to worry
6054              * about an overflow when we pad things out below).
6055              * That's the reason for the alignment arithmetic below.
6056              */
6057             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
6058                 align = (4 - (orbytes & 3)) & 3;
6059             else
6060                 align = 0;
6061
6062             if (orbytes + bytesInBuffer + align > maxReturnData) {
6063                 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
6064                          maxReturnData);
6065                 break;
6066             }
6067
6068             /* this is one of the entries to use: it is not deleted
6069              * and it matches the star pattern we're looking for.
6070              * Put out the name, preceded by its length.
6071              */
6072             /* First zero everything else */
6073             memset(origOp, 0, orbytes);
6074
6075             onbytes = 0;
6076             smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
6077
6078             switch (infoLevel) {
6079             case SMB_INFO_STANDARD:
6080                 fp->u.FstandardInfo.fileNameLength = onbytes;
6081                 attrp = &fp->u.FstandardInfo.fileAttrs;
6082                 break;
6083
6084             case SMB_INFO_QUERY_EA_SIZE:
6085                 fp->u.FeaSizeInfo.fileNameLength = onbytes;
6086                 attrp = &fp->u.FeaSizeInfo.fileAttrs;
6087                 fp->u.FeaSizeInfo.eaSize = 0;
6088                 break;
6089
6090             case SMB_INFO_QUERY_EAS_FROM_LIST:
6091                 fp->u.FeasFromListInfo.fileNameLength = onbytes;
6092                 attrp = &fp->u.FeasFromListInfo.fileAttrs;
6093                 fp->u.FeasFromListInfo.eaSize = 0;
6094                 break;
6095
6096             case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
6097                 if (NeedShortName) {
6098 #ifdef SMB_UNICODE
6099                     int nchars;
6100
6101                     nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
6102                                                     fp->u.FfileBothDirectoryInfo.shortName,
6103                                                     sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
6104                     if (nchars > 0)
6105                         fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
6106                     else
6107                         fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
6108                     fp->u.FfileBothDirectoryInfo.reserved = 0;
6109 #else
6110                     cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
6111                                     lengthof(fp->u.FfileBothDirectoryInfo.shortName),
6112                                     shortName);
6113                     fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
6114 #endif
6115                 }
6116                 /* Fallthrough */
6117
6118             case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
6119                 fp->u.FfileFullDirectoryInfo.eaSize = 0;
6120                 /* Fallthrough */
6121
6122             case SMB_FIND_FILE_DIRECTORY_INFO:
6123                 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
6124                 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
6125                 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
6126                 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
6127                 break;
6128
6129             case SMB_FIND_FILE_NAMES_INFO:
6130                 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
6131                 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
6132                 fp->u.FfileNamesInfo.fileNameLength = onbytes;
6133                 attrp = NULL;
6134                 break;
6135
6136             default:
6137                 /* we shouldn't hit this case */
6138                 osi_assertx(FALSE, "Unknown query type");
6139             }
6140
6141             /* now, adjust the # of entries copied */
6142             returnedNames++;
6143
6144             /* now we emit the attribute.  This is tricky, since
6145              * we need to really stat the file to find out what
6146              * type of entry we've got.  Right now, we're copying
6147              * out data from a buffer, while holding the scp
6148              * locked, so it isn't really convenient to stat
6149              * something now.  We'll put in a place holder
6150              * now, and make a second pass before returning this
6151              * to get the real attributes.  So, we just skip the
6152              * data for now, and adjust it later.  We allocate a
6153              * patch record to make it easy to find this point
6154              * later.  The replay will happen at a time when it is
6155              * safe to unlock the directory.
6156              */
6157             if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
6158                 osi_assert(attrp != NULL);
6159                 curPatchp = malloc(sizeof(*curPatchp));
6160                 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
6161                 curPatchp->dptr = attrp;
6162
6163                 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
6164                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
6165                 } else {
6166                     curPatchp->flags = 0;
6167                 }
6168
6169                 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
6170
6171                 /* temp */
6172                 curPatchp->dep = dep;
6173             }
6174
6175             if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
6176                 /* put out resume key */
6177                 *((u_long *)origOp) = nextEntryCookie;
6178
6179             /* Adjust byte ptr and count */
6180             origOp += orbytes;  /* skip entire record */
6181             bytesInBuffer += orbytes;
6182
6183             /* and pad the record out */
6184             while (align-- > 0) {
6185                 *origOp++ = 0;
6186                 bytesInBuffer++;
6187             }
6188         }       /* if we're including this name */
6189         else if (!starPattern &&
6190                  !foundInexact &&
6191                  cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
6192             /* We were looking for exact matches, but here's an inexact one*/
6193             foundInexact = 1;
6194         }
6195
6196       nextEntry:
6197         /* and adjust curOffset to be where the new cookie is */
6198         thyper.HighPart = 0;
6199         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
6200         curOffset = LargeIntegerAdd(thyper, curOffset);
6201     } /* while copying data for dir listing */
6202
6203     /* If we didn't get a star pattern, we did an exact match during the first pass.
6204      * If there were no exact matches found, we fail over to inexact matches by
6205      * marking the query as a star pattern (matches all case permutations), and
6206      * re-running the query.
6207      */
6208     if (returnedNames == 0 && !starPattern && foundInexact) {
6209         osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
6210         starPattern = 1;
6211         goto startsearch;
6212     }
6213
6214     /* release the mutex */
6215     lock_ReleaseWrite(&scp->rw);
6216     if (bufferp) {
6217         buf_Release(bufferp);
6218         bufferp = NULL;
6219     }
6220
6221     /*
6222      * Finally, process whatever entries we have left.
6223      */
6224     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
6225                                       dsp->relPath, infoLevel, userp, &req);
6226
6227     /* now put out the final parameters */
6228     if (returnedNames == 0)
6229         eos = 1;
6230     if (p->opcode == 1) {
6231         /* find first */
6232         outp->parmsp[0] = (unsigned short) dsp->cookie;
6233         outp->parmsp[1] = returnedNames;
6234         outp->parmsp[2] = eos;
6235         outp->parmsp[3] = 0;            /* nothing wrong with EAS */
6236         outp->parmsp[4] = 0;
6237         /* don't need last name to continue
6238          * search, cookie is enough.  Normally,
6239          * this is the offset of the file name
6240          * of the last entry returned.
6241          */
6242         outp->totalParms = 10;  /* in bytes */
6243     }
6244     else {
6245         /* find next */
6246         outp->parmsp[0] = returnedNames;
6247         outp->parmsp[1] = eos;
6248         outp->parmsp[2] = 0;    /* EAS error */
6249         outp->parmsp[3] = 0;    /* last name, as above */
6250         outp->totalParms = 8;   /* in bytes */
6251     }
6252
6253     /* return # of bytes in the buffer */
6254     outp->totalData = bytesInBuffer;
6255
6256     /* Return error code if unsuccessful on first request */
6257     if (code == 0 && p->opcode == 1 && returnedNames == 0)
6258         code = CM_ERROR_NOSUCHFILE;
6259
6260     osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
6261              p->opcode, dsp->cookie, returnedNames, code);
6262
6263     /* if we're supposed to close the search after this request, or if
6264      * we're supposed to close the search if we're done, and we're done,
6265      * or if something went wrong, close the search.
6266      */
6267     if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
6268         (returnedNames == 0) ||
6269         ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
6270         code != 0)
6271         smb_DeleteDirSearch(dsp);
6272
6273     if (code)
6274         smb_SendTran2Error(vcp, p, opx, code);
6275     else
6276         smb_SendTran2Packet(vcp, outp, opx);
6277
6278     smb_FreeTran2Packet(outp);
6279     smb_ReleaseDirSearch(dsp);
6280     cm_ReleaseSCache(scp);
6281     cm_ReleaseUser(userp);
6282     return 0;
6283 }
6284
6285 /* SMB_COM_FIND_CLOSE2 */
6286 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6287 {
6288     int dirHandle;
6289     smb_dirSearch_t *dsp;
6290
6291     dirHandle = smb_GetSMBParm(inp, 0);
6292
6293     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
6294
6295     dsp = smb_FindDirSearch(dirHandle);
6296
6297     if (!dsp)
6298         return CM_ERROR_BADFD;
6299
6300     /* otherwise, we have an FD to destroy */
6301     smb_DeleteDirSearch(dsp);
6302     smb_ReleaseDirSearch(dsp);
6303
6304     /* and return results */
6305     smb_SetSMBDataLength(outp, 0);
6306
6307     return 0;
6308 }
6309
6310
6311 /* SMB_COM_FIND_NOTIFY_CLOSE */
6312 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6313 {
6314     smb_SetSMBDataLength(outp, 0);
6315     return 0;
6316 }
6317
6318 /* SMB_COM_OPEN_ANDX */
6319 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6320 {
6321     clientchar_t *pathp;
6322     long code = 0;
6323     cm_space_t *spacep;
6324     int excl;
6325     cm_user_t *userp;
6326     cm_scache_t *dscp;          /* dir we're dealing with */
6327     cm_scache_t *scp;           /* file we're creating */
6328     cm_attr_t setAttr;
6329     smb_fid_t *fidp;
6330     int attributes;
6331     clientchar_t *lastNamep;
6332     unsigned long dosTime;
6333     int openFun;
6334     int trunc;
6335     int openMode;
6336     int extraInfo;
6337     int openAction;
6338     int parmSlot;                       /* which parm we're dealing with */
6339     clientchar_t *tidPathp;
6340     cm_req_t req;
6341     int created = 0;
6342     BOOL is_rpc = FALSE;
6343     BOOL is_ipc = FALSE;
6344
6345     smb_InitReq(&req);
6346
6347     scp = NULL;
6348
6349     extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
6350     openFun = smb_GetSMBParm(inp, 8); /* open function */
6351     excl = ((openFun & 3) == 0);
6352     trunc = ((openFun & 3) == 2); /* truncate it */
6353     openMode = (smb_GetSMBParm(inp, 3) & 0x7);
6354     openAction = 0;             /* tracks what we did */
6355
6356     attributes = smb_GetSMBParm(inp, 5);
6357     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
6358
6359     pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
6360                                 SMB_STRF_ANSIPATH);
6361     if (!pathp)
6362         return CM_ERROR_BADSMB;
6363
6364     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6365     if (code) {
6366         if (code == CM_ERROR_TIDIPC) {
6367             is_ipc = TRUE;
6368         } else {
6369             return CM_ERROR_NOSUCHPATH;
6370         }
6371     }
6372
6373     spacep = inp->spacep;
6374     /* smb_StripLastComponent will strip "::$DATA" if present */
6375     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6376
6377     if (lastNamep &&
6378
6379         /* special case magic file name for receiving IOCTL requests
6380          * (since IOCTL calls themselves aren't getting through).
6381          */
6382         (cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
6383
6384          /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional) */
6385          (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
6386
6387         unsigned short file_type = 0;
6388         unsigned short device_state = 0;
6389
6390         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6391         if (is_rpc) {
6392             code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
6393             osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
6394             if (code) {
6395                 osi_Log1(smb_logp, "smb_SetupRPCFid failure code [%d]", code);
6396                 smb_ReleaseFID(fidp);
6397                 return code;
6398             }
6399         } else {
6400             smb_SetupIoctlFid(fidp, spacep);
6401             osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
6402         }
6403
6404         /* set inp->fid so that later read calls in same msg can find fid */
6405         inp->fid = fidp->fid;
6406
6407         /* copy out remainder of the parms */
6408         parmSlot = 2;
6409         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6410         if (extraInfo) {
6411             smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
6412             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* mod time */
6413             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6414             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* len */
6415             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
6416             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6417             smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
6418             smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
6419         }
6420         /* and the final "always present" stuff */
6421         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
6422         /* next write out the "unique" ID */
6423         smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
6424         smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
6425         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6426         smb_SetSMBDataLength(outp, 0);
6427
6428         /* and clean up fid reference */
6429         smb_ReleaseFID(fidp);
6430         return 0;
6431     }
6432
6433 #ifndef DFS_SUPPORT
6434     if (is_ipc) {
6435         osi_Log0(smb_logp, "NTOpenX rejecting IPC TID");
6436         return CM_ERROR_BADFD;
6437     }
6438 #endif
6439
6440     if (!cm_IsValidClientString(pathp)) {
6441 #ifdef DEBUG
6442         clientchar_t * hexp;
6443
6444         hexp = cm_GetRawCharsAlloc(pathp, -1);
6445         osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
6446                  osi_LogSaveClientString(smb_logp, hexp));
6447         if (hexp)
6448             free(hexp);
6449 #else
6450         osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
6451 #endif
6452         return CM_ERROR_BADNTFILENAME;
6453     }
6454
6455 #ifdef DEBUG_VERBOSE
6456     {
6457         char *hexp, *asciip;
6458         asciip = (lastNamep ? lastNamep : pathp );
6459         hexp = osi_HexifyString(asciip);
6460         DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
6461         free(hexp);
6462     }
6463 #endif
6464     userp = smb_GetUserFromVCP(vcp, inp);
6465
6466     dscp = NULL;
6467     code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
6468                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6469                     userp, tidPathp, &req, &scp);
6470
6471 #ifdef DFS_SUPPORT
6472     if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6473         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
6474         cm_ReleaseSCache(scp);
6475         cm_ReleaseUser(userp);
6476         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6477             return CM_ERROR_PATH_NOT_COVERED;
6478         else
6479             return CM_ERROR_NOSUCHPATH;
6480     }
6481 #endif /* DFS_SUPPORT */
6482
6483     if (code != 0) {
6484         if (code == CM_ERROR_NOSUCHFILE ||
6485             code == CM_ERROR_NOSUCHPATH ||
6486             code == CM_ERROR_BPLUS_NOMATCH)
6487             code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
6488                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6489                             userp, tidPathp, &req, &dscp);
6490         if (code) {
6491             cm_ReleaseUser(userp);
6492             return code;
6493         }
6494
6495 #ifdef DFS_SUPPORT
6496         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6497             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6498                                                       spacep->wdata);
6499             cm_ReleaseSCache(dscp);
6500             cm_ReleaseUser(userp);
6501             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6502                 return CM_ERROR_PATH_NOT_COVERED;
6503             else
6504                 return CM_ERROR_NOSUCHPATH;
6505         }
6506 #endif /* DFS_SUPPORT */
6507         /* otherwise, scp points to the parent directory.  Do a lookup,
6508          * and truncate the file if we find it, otherwise we create the
6509          * file.
6510          */
6511         if (!lastNamep)
6512             lastNamep = pathp;
6513         else
6514             lastNamep++;
6515         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
6516                           &req, &scp);
6517         if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6518             cm_ReleaseSCache(dscp);
6519             cm_ReleaseUser(userp);
6520             return code;
6521         }
6522     }
6523
6524     /* if we get here, if code is 0, the file exists and is represented by
6525      * scp.  Otherwise, we have to create it.  The dir may be represented
6526      * by dscp, or we may have found the file directly.  If code is non-zero,
6527      * scp is NULL.
6528      */
6529     if (code == 0) {
6530         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
6531         if (code) {
6532             if (dscp) cm_ReleaseSCache(dscp);
6533             cm_ReleaseSCache(scp);
6534             cm_ReleaseUser(userp);
6535             return code;
6536         }
6537
6538         if (excl) {
6539             /* oops, file shouldn't be there */
6540             if (dscp)
6541                 cm_ReleaseSCache(dscp);
6542             cm_ReleaseSCache(scp);
6543             cm_ReleaseUser(userp);
6544             return CM_ERROR_EXISTS;
6545         }
6546
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             openAction = 3;     /* truncated existing file */
6553         }
6554         else openAction = 1;    /* found existing file */
6555     }
6556     else if (!(openFun & SMB_ATTR_DIRECTORY)) {
6557         /* don't create if not found */
6558         if (dscp) cm_ReleaseSCache(dscp);
6559         cm_ReleaseUser(userp);
6560         return CM_ERROR_NOSUCHFILE;
6561     }
6562     else {
6563         osi_assertx(dscp != NULL, "null cm_scache_t");
6564         osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
6565                  osi_LogSaveClientString(smb_logp, lastNamep));
6566         openAction = 2; /* created file */
6567         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6568         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6569         smb_SetInitialModeBitsForFile(attributes, &setAttr);
6570
6571         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6572                          &req);
6573         if (code == 0) {
6574             created = 1;
6575             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6576                 smb_NotifyChange(FILE_ACTION_ADDED,
6577                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6578                                  dscp, lastNamep, NULL, TRUE);
6579         } else if (!excl && code == CM_ERROR_EXISTS) {
6580             /* not an exclusive create, and someone else tried
6581              * creating it already, then we open it anyway.  We
6582              * don't bother retrying after this, since if this next
6583              * fails, that means that the file was deleted after we
6584              * started this call.
6585              */
6586             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6587                              userp, &req, &scp);
6588             if (code == 0) {
6589                 if (trunc) {
6590                     setAttr.mask = CM_ATTRMASK_LENGTH;
6591                     setAttr.length.LowPart = 0;
6592                     setAttr.length.HighPart = 0;
6593                     code = cm_SetAttr(scp, &setAttr, userp, &req);
6594                 }
6595             }   /* lookup succeeded */
6596         }
6597     }
6598
6599     /* we don't need this any longer */
6600     if (dscp)
6601         cm_ReleaseSCache(dscp);
6602
6603     if (code) {
6604         /* something went wrong creating or truncating the file */
6605         if (scp)
6606             cm_ReleaseSCache(scp);
6607         cm_ReleaseUser(userp);
6608         return code;
6609     }
6610
6611     /* make sure we're about to open a file */
6612     if (scp->fileType != CM_SCACHETYPE_FILE) {
6613         cm_ReleaseSCache(scp);
6614         cm_ReleaseUser(userp);
6615         return CM_ERROR_ISDIR;
6616     }
6617
6618     /* now all we have to do is open the file itself */
6619     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6620     osi_assertx(fidp, "null smb_fid_t");
6621
6622     cm_HoldUser(userp);
6623     lock_ObtainMutex(&fidp->mx);
6624     /* save a pointer to the vnode */
6625     fidp->scp = scp;
6626     lock_ObtainWrite(&scp->rw);
6627     scp->flags |= CM_SCACHEFLAG_SMB_FID;
6628     lock_ReleaseWrite(&scp->rw);
6629     osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
6630     /* also the user */
6631     fidp->userp = userp;
6632
6633     /* compute open mode */
6634     if (openMode != 1)
6635         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
6636     if (openMode == 1 || openMode == 2)
6637         fidp->flags |= SMB_FID_OPENWRITE;
6638
6639     /* remember if the file was newly created */
6640     if (created)
6641         fidp->flags |= SMB_FID_CREATED;
6642
6643     lock_ReleaseMutex(&fidp->mx);
6644     smb_ReleaseFID(fidp);
6645
6646     cm_Open(scp, 0, userp);
6647
6648     /* set inp->fid so that later read calls in same msg can find fid */
6649     inp->fid = fidp->fid;
6650
6651     /* copy out remainder of the parms */
6652     parmSlot = 2;
6653     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6654     lock_ObtainRead(&scp->rw);
6655     if (extraInfo) {
6656         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
6657         smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
6658         smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
6659         smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
6660         smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
6661         smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
6662         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6663         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
6664         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
6665     }
6666     /* and the final "always present" stuff */
6667     smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
6668     /* next write out the "unique" ID */
6669     smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
6670     smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
6671     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6672     lock_ReleaseRead(&scp->rw);
6673     smb_SetSMBDataLength(outp, 0);
6674
6675     osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
6676
6677     cm_ReleaseUser(userp);
6678     /* leave scp held since we put it in fidp->scp */
6679     return 0;
6680 }
6681
6682 static void smb_GetLockParams(unsigned char LockType,
6683                               char ** buf,
6684                               unsigned int * ppid,
6685                               LARGE_INTEGER * pOffset,
6686                               LARGE_INTEGER * pLength)
6687 {
6688     if (LockType & LOCKING_ANDX_LARGE_FILES) {
6689         /* Large Files */
6690         *ppid = *((USHORT *) *buf);
6691         pOffset->HighPart = *((LONG *)(*buf + 4));
6692         pOffset->LowPart = *((DWORD *)(*buf + 8));
6693         pLength->HighPart = *((LONG *)(*buf + 12));
6694         pLength->LowPart = *((DWORD *)(*buf + 16));
6695         *buf += 20;
6696     }
6697     else {
6698         /* Not Large Files */
6699         *ppid = *((USHORT *) *buf);
6700         pOffset->HighPart = 0;
6701         pOffset->LowPart = *((DWORD *)(*buf + 2));
6702         pLength->HighPart = 0;
6703         pLength->LowPart = *((DWORD *)(*buf + 6));
6704         *buf += 10;
6705     }
6706 }
6707
6708 /* SMB_COM_LOCKING_ANDX */
6709 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6710 {
6711     cm_req_t req;
6712     cm_user_t *userp;
6713     unsigned short fid;
6714     smb_fid_t *fidp;
6715     cm_scache_t *scp;
6716     unsigned char LockType;
6717     unsigned short NumberOfUnlocks, NumberOfLocks;
6718     afs_uint32 Timeout;
6719     char *op;
6720     char *op_locks;
6721     LARGE_INTEGER LOffset, LLength;
6722     smb_waitingLockRequest_t *wlRequest = NULL;
6723     cm_file_lock_t *lockp;
6724     long code = 0;
6725     int i;
6726     cm_key_t key;
6727     unsigned int pid;
6728     afs_uint32 smb_vc_hold_required = 0;
6729
6730     smb_InitReq(&req);
6731
6732     fid = smb_GetSMBParm(inp, 2);
6733     fid = smb_ChainFID(fid, inp);
6734
6735     fidp = smb_FindFID(vcp, fid, 0);
6736     if (!fidp) {
6737         osi_Log2(smb_logp, "V3LockingX Unknown SMB Fid vcp 0x%p fid %d",
6738                  vcp, fid);
6739         return CM_ERROR_BADFD;
6740     }
6741     lock_ObtainMutex(&fidp->mx);
6742     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6743         lock_ReleaseMutex(&fidp->mx);
6744         smb_CloseFID(vcp, fidp, NULL, 0);
6745         smb_ReleaseFID(fidp);
6746         return CM_ERROR_NOSUCHFILE;
6747     }
6748
6749     if (fidp->flags & SMB_FID_IOCTL) {
6750         osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6751         lock_ReleaseMutex(&fidp->mx);
6752         smb_ReleaseFID(fidp);
6753         return CM_ERROR_BADFD;
6754     }
6755     scp = fidp->scp;
6756     osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6757     cm_HoldSCache(scp);
6758     lock_ReleaseMutex(&fidp->mx);
6759
6760     /* set inp->fid so that later read calls in same msg can find fid */
6761     inp->fid = fid;
6762
6763     userp = smb_GetUserFromVCP(vcp, inp);
6764     smb_HoldVC(vcp);
6765
6766     lock_ObtainWrite(&scp->rw);
6767     code = cm_SyncOp(scp, NULL, userp, &req, 0,
6768                       CM_SCACHESYNC_NEEDCALLBACK
6769                          | CM_SCACHESYNC_GETSTATUS
6770                          | CM_SCACHESYNC_LOCK);
6771     if (code) {
6772         osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6773         goto doneSync;
6774     }
6775
6776     LockType = smb_GetSMBParm(inp, 3) & 0xff;
6777     Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6778     NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6779     NumberOfLocks = smb_GetSMBParm(inp, 7);
6780
6781     if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6782         !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6783         /* somebody wants exclusive locks on a file that they only
6784            opened for reading.  We downgrade this to a shared lock. */
6785         osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6786         LockType |= LOCKING_ANDX_SHARED_LOCK;
6787     }
6788
6789     if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6790         /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6791         osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6792         code = CM_ERROR_BADOP;
6793         goto done;
6794
6795     }
6796
6797     op = smb_GetSMBData(inp, NULL);
6798
6799     if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6800         /* Cancel outstanding lock requests */
6801         smb_waitingLock_t * wl;
6802
6803         for (i=0; i<NumberOfLocks; i++) {
6804             smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6805
6806             key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6807
6808             lock_ObtainWrite(&smb_globalLock);
6809             for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6810             {
6811                 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6812                     if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6813                         LargeIntegerEqualTo(wl->LLength, LLength)) {
6814                         wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6815                         goto found_lock_request;
6816                     }
6817                 }
6818             }
6819           found_lock_request:
6820             lock_ReleaseWrite(&smb_globalLock);
6821         }
6822         code = 0;
6823         smb_SetSMBDataLength(outp, 0);
6824         goto done;
6825     }
6826
6827
6828     for (i=0; i<NumberOfUnlocks; i++) {
6829         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6830
6831         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6832
6833         code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6834
6835         if (code)
6836             goto done;
6837     }
6838
6839     op_locks = op;
6840
6841     for (i=0; i<NumberOfLocks; i++) {
6842         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6843
6844         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6845
6846         code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6847                         userp, &req, &lockp);
6848
6849         if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6850             (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6851         {
6852             code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6853                             userp, &req, &lockp);
6854         }
6855
6856         if (code == CM_ERROR_LOCK_NOT_GRANTED && Timeout != 0) {
6857             smb_waitingLock_t * wLock;
6858
6859             /* Put on waiting list */
6860             if(wlRequest == NULL) {
6861                 int j;
6862                 char * opt;
6863                 cm_key_t tkey;
6864                 LARGE_INTEGER tOffset, tLength;
6865
6866                 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6867
6868                 osi_assertx(wlRequest != NULL, "null wlRequest");
6869
6870                 wlRequest->vcp = vcp;
6871                 smb_vc_hold_required = 1;
6872                 wlRequest->scp = scp;
6873                 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6874                 cm_HoldSCache(scp);
6875                 wlRequest->inp = smb_CopyPacket(inp);
6876                 wlRequest->outp = smb_CopyPacket(outp);
6877                 wlRequest->lockType = LockType;
6878                 wlRequest->msTimeout = Timeout;
6879                 wlRequest->start_t = osi_Time();
6880                 wlRequest->locks = NULL;
6881
6882                 /* The waiting lock request needs to have enough
6883                    information to undo all the locks in the request.
6884                    We do the following to store info about locks that
6885                    have already been granted.  Sure, we can get most
6886                    of the info from the packet, but the packet doesn't
6887                    hold the result of cm_Lock call.  In practice we
6888                    only receive packets with one or two locks, so we
6889                    are only wasting a few bytes here and there and
6890                    only for a limited period of time until the waiting
6891                    lock times out or is freed. */
6892
6893                 for(opt = op_locks, j=i; j > 0; j--) {
6894                     smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6895
6896                     tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6897
6898                     wLock = malloc(sizeof(smb_waitingLock_t));
6899
6900                     osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6901
6902                     wLock->key = tkey;
6903                     wLock->LOffset = tOffset;
6904                     wLock->LLength = tLength;
6905                     wLock->lockp = NULL;
6906                     wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6907                     osi_QAdd((osi_queue_t **) &wlRequest->locks,
6908                              &wLock->q);
6909                 }
6910             }
6911
6912             wLock = malloc(sizeof(smb_waitingLock_t));
6913
6914             osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6915
6916             wLock->key = key;
6917             wLock->LOffset = LOffset;
6918             wLock->LLength = LLength;
6919             wLock->lockp = lockp;
6920             wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6921             osi_QAdd((osi_queue_t **) &wlRequest->locks,
6922                      &wLock->q);
6923
6924             osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6925                      wLock);
6926
6927             code = 0;
6928             continue;
6929         }
6930
6931         if (code) {
6932             osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6933             break;
6934         }
6935     }
6936
6937     if (code) {
6938
6939         /* Since something went wrong with the lock number i, we now
6940            have to go ahead and release any locks acquired before the
6941            failure.  All locks before lock number i (of which there
6942            are i of them) have either been successful or are waiting.
6943            Either case requires calling cm_Unlock(). */
6944
6945         /* And purge the waiting lock */
6946         if(wlRequest != NULL) {
6947             smb_waitingLock_t * wl;
6948             smb_waitingLock_t * wlNext;
6949             long ul_code;
6950
6951             for(wl = wlRequest->locks; wl; wl = wlNext) {
6952
6953                 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6954
6955                 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6956
6957                 if(ul_code != 0) {
6958                     osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6959                 } else {
6960                     osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6961                 }
6962
6963                 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6964                 free(wl);
6965
6966             }
6967
6968             smb_ReleaseVC(wlRequest->vcp);
6969             cm_ReleaseSCache(wlRequest->scp);
6970             smb_FreePacket(wlRequest->inp);
6971             smb_FreePacket(wlRequest->outp);
6972
6973             free(wlRequest);
6974
6975             wlRequest = NULL;
6976         }
6977
6978     } else {
6979
6980         if (wlRequest != NULL) {
6981
6982             lock_ObtainWrite(&smb_globalLock);
6983             osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6984                      &wlRequest->q);
6985             osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6986             lock_ReleaseWrite(&smb_globalLock);
6987
6988             /* don't send reply immediately */
6989             outp->flags |= SMB_PACKETFLAG_NOSEND;
6990         }
6991
6992         smb_SetSMBDataLength(outp, 0);
6993     }
6994
6995   done:
6996     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6997
6998   doneSync:
6999     lock_ReleaseWrite(&scp->rw);
7000     cm_ReleaseSCache(scp);
7001     cm_ReleaseUser(userp);
7002     smb_ReleaseFID(fidp);
7003     if (!smb_vc_hold_required)
7004         smb_HoldVC(vcp);
7005
7006     return code;
7007 }
7008
7009 /* SMB_COM_QUERY_INFORMATION2 */
7010 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7011 {
7012     unsigned short fid;
7013     smb_fid_t *fidp;
7014     cm_scache_t *scp;
7015     long code = 0;
7016     afs_uint32 searchTime;
7017     cm_user_t *userp;
7018     cm_req_t req;
7019     int readlock = 0;
7020
7021     smb_InitReq(&req);
7022
7023     fid = smb_GetSMBParm(inp, 0);
7024     fid = smb_ChainFID(fid, inp);
7025
7026     fidp = smb_FindFID(vcp, fid, 0);
7027     if (!fidp) {
7028         osi_Log2(smb_logp, "V3GetAttributes Unknown SMB Fid vcp 0x%p fid %d",
7029                  vcp, fid);
7030         return CM_ERROR_BADFD;
7031     }
7032     lock_ObtainMutex(&fidp->mx);
7033     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7034         lock_ReleaseMutex(&fidp->mx);
7035         smb_CloseFID(vcp, fidp, NULL, 0);
7036         smb_ReleaseFID(fidp);
7037         return CM_ERROR_NOSUCHFILE;
7038     }
7039
7040     if (fidp->flags & SMB_FID_IOCTL) {
7041         lock_ReleaseMutex(&fidp->mx);
7042         smb_ReleaseFID(fidp);
7043         return CM_ERROR_BADFD;
7044     }
7045     scp = fidp->scp;
7046     osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
7047     cm_HoldSCache(scp);
7048     lock_ReleaseMutex(&fidp->mx);
7049
7050     userp = smb_GetUserFromVCP(vcp, inp);
7051
7052
7053     /* otherwise, stat the file */
7054     lock_ObtainWrite(&scp->rw);
7055     code = cm_SyncOp(scp, NULL, userp, &req, 0,
7056                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7057     if (code)
7058         goto done;
7059
7060     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7061
7062     lock_ConvertWToR(&scp->rw);
7063     readlock = 1;
7064
7065     /* decode times.  We need a search time, but the response to this
7066      * call provides the date first, not the time, as returned in the
7067      * searchTime variable.  So we take the high-order bits first.
7068      */
7069     cm_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
7070     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);       /* ctime */
7071     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
7072     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);       /* atime */
7073     smb_SetSMBParm(outp, 3, searchTime & 0xffff);
7074     smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);       /* mtime */
7075     smb_SetSMBParm(outp, 5, searchTime & 0xffff);
7076
7077     /* now handle file size and allocation size */
7078     smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);              /* file size */
7079     smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
7080     smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);              /* alloc size */
7081     smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
7082
7083     /* file attribute */
7084     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
7085
7086     /* and finalize stuff */
7087     smb_SetSMBDataLength(outp, 0);
7088     code = 0;
7089
7090   done:
7091     if (readlock)
7092         lock_ReleaseRead(&scp->rw);
7093     else
7094         lock_ReleaseWrite(&scp->rw);
7095     cm_ReleaseSCache(scp);
7096     cm_ReleaseUser(userp);
7097     smb_ReleaseFID(fidp);
7098     return code;
7099 }
7100
7101 /* SMB_COM_SET_INFORMATION2 */
7102 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7103 {
7104     unsigned short fid;
7105     smb_fid_t *fidp;
7106     cm_scache_t *scp;
7107     long code = 0;
7108     afs_uint32 searchTime;
7109     time_t unixTime;
7110     cm_user_t *userp;
7111     cm_attr_t attrs;
7112     cm_req_t req;
7113
7114     smb_InitReq(&req);
7115
7116     fid = smb_GetSMBParm(inp, 0);
7117     fid = smb_ChainFID(fid, inp);
7118
7119     fidp = smb_FindFID(vcp, fid, 0);
7120     if (!fidp) {
7121         osi_Log2(smb_logp, "V3SetAttributes Unknown SMB Fid vcp 0x%p fid %d",
7122                  vcp, fid);
7123         return CM_ERROR_BADFD;
7124     }
7125     lock_ObtainMutex(&fidp->mx);
7126     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7127         lock_ReleaseMutex(&fidp->mx);
7128         smb_CloseFID(vcp, fidp, NULL, 0);
7129         smb_ReleaseFID(fidp);
7130         return CM_ERROR_NOSUCHFILE;
7131     }
7132
7133     if (fidp->flags & SMB_FID_IOCTL) {
7134         lock_ReleaseMutex(&fidp->mx);
7135         smb_ReleaseFID(fidp);
7136         return CM_ERROR_BADFD;
7137     }
7138     scp = fidp->scp;
7139     osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
7140     cm_HoldSCache(scp);
7141     lock_ReleaseMutex(&fidp->mx);
7142
7143     userp = smb_GetUserFromVCP(vcp, inp);
7144
7145     /* now prepare to call cm_setattr.  This message only sets various times,
7146      * and AFS only implements mtime, and we'll set the mtime if that's
7147      * requested.  The others we'll ignore.
7148      */
7149     searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
7150
7151     if (searchTime != 0) {
7152         cm_UnixTimeFromSearchTime(&unixTime, searchTime);
7153
7154         if ( unixTime != -1 ) {
7155             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
7156             attrs.clientModTime = unixTime;
7157             code = cm_SetAttr(scp, &attrs, userp, &req);
7158
7159             osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
7160         } else {
7161             osi_Log1(smb_logp, "**cm_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
7162         }
7163     }
7164     else
7165         code = 0;
7166
7167     cm_ReleaseSCache(scp);
7168     cm_ReleaseUser(userp);
7169     smb_ReleaseFID(fidp);
7170     return code;
7171 }
7172
7173 /* SMB_COM_WRITE_ANDX */
7174 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7175 {
7176     osi_hyper_t offset;
7177     long count, written = 0, total_written = 0;
7178     unsigned short fd;
7179     unsigned pid;
7180     smb_fid_t *fidp;
7181     smb_t *smbp = (smb_t*) inp;
7182     long code = 0;
7183     cm_scache_t *scp;
7184     cm_user_t *userp;
7185     char *op;
7186     int inDataBlockCount;
7187
7188     fd = smb_GetSMBParm(inp, 2);
7189     count = smb_GetSMBParm(inp, 10);
7190
7191     offset.HighPart = 0;
7192     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7193
7194     if (*inp->wctp == 14) {
7195         /* we have a request with 64-bit file offsets */
7196         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7197     }
7198
7199     op = inp->data + smb_GetSMBParm(inp, 11);
7200     inDataBlockCount = count;
7201
7202     osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
7203              fd, offset.HighPart, offset.LowPart, count);
7204
7205     fd = smb_ChainFID(fd, inp);
7206     fidp = smb_FindFID(vcp, fd, 0);
7207     if (!fidp) {
7208         osi_Log2(smb_logp, "smb_ReceiveV3WriteX Unknown SMB Fid vcp 0x%p fid %d",
7209                  vcp, fd);
7210         return CM_ERROR_BADFD;
7211     }
7212     lock_ObtainMutex(&fidp->mx);
7213     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7214         lock_ReleaseMutex(&fidp->mx);
7215         smb_CloseFID(vcp, fidp, NULL, 0);
7216         smb_ReleaseFID(fidp);
7217         return CM_ERROR_NOSUCHFILE;
7218     }
7219
7220     if (fidp->flags & SMB_FID_IOCTL) {
7221         lock_ReleaseMutex(&fidp->mx);
7222         code = smb_IoctlV3Write(fidp, vcp, inp, outp);
7223         smb_ReleaseFID(fidp);
7224         return code;
7225     }
7226
7227     if (fidp->flags & SMB_FID_RPC) {
7228         lock_ReleaseMutex(&fidp->mx);
7229         code = smb_RPCV3Write(fidp, vcp, inp, outp);
7230         smb_ReleaseFID(fidp);
7231         return code;
7232     }
7233
7234     if (!fidp->scp) {
7235         lock_ReleaseMutex(&fidp->mx);
7236         smb_ReleaseFID(fidp);
7237         return CM_ERROR_BADFDOP;
7238     }
7239
7240     scp = fidp->scp;
7241     cm_HoldSCache(scp);
7242     lock_ReleaseMutex(&fidp->mx);
7243
7244     userp = smb_GetUserFromVCP(vcp, inp);
7245
7246     /* special case: 0 bytes transferred means there is no data
7247        transferred.  A slight departure from SMB_COM_WRITE where this
7248        means that we are supposed to truncate the file at this
7249        position. */
7250
7251     {
7252         cm_key_t key;
7253         LARGE_INTEGER LOffset;
7254         LARGE_INTEGER LLength;
7255
7256         pid = smbp->pid;
7257         key = cm_GenerateKey(vcp->vcID, pid, fd);
7258
7259         LOffset.HighPart = offset.HighPart;
7260         LOffset.LowPart = offset.LowPart;
7261         LLength.HighPart = 0;
7262         LLength.LowPart = count;
7263
7264         lock_ObtainWrite(&scp->rw);
7265         code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7266         lock_ReleaseWrite(&scp->rw);
7267
7268         if (code)
7269             goto done;
7270     }
7271
7272     /*
7273      * Work around bug in NT client
7274      *
7275      * When copying a file, the NT client should first copy the data,
7276      * then copy the last write time.  But sometimes the NT client does
7277      * these in the wrong order, so the data copies would inadvertently
7278      * cause the last write time to be overwritten.  We try to detect this,
7279      * and don't set client mod time if we think that would go against the
7280      * intention.
7281      */
7282     lock_ObtainMutex(&fidp->mx);
7283     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7284         lock_ObtainWrite(&fidp->scp->rw);
7285         scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7286         scp->clientModTime = time(NULL);
7287         lock_ReleaseWrite(&fidp->scp->rw);
7288     }
7289     lock_ReleaseMutex(&fidp->mx);
7290
7291     code = 0;
7292     while ( code == 0 && count > 0 ) {
7293         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7294         if (code == 0 && written == 0)
7295             code = CM_ERROR_PARTIALWRITE;
7296
7297         offset = LargeIntegerAdd(offset,
7298                                  ConvertLongToLargeInteger(written));
7299         count -= written;
7300         total_written += written;
7301         written = 0;
7302     }
7303
7304     /* slots 0 and 1 are reserved for request chaining and will be
7305        filled in when we return. */
7306     smb_SetSMBParm(outp, 2, total_written);
7307     smb_SetSMBParm(outp, 3, 0); /* reserved */
7308     smb_SetSMBParm(outp, 4, 0); /* reserved */
7309     smb_SetSMBParm(outp, 5, 0); /* reserved */
7310     smb_SetSMBDataLength(outp, 0);
7311
7312  done:
7313
7314     cm_ReleaseSCache(scp);
7315     cm_ReleaseUser(userp);
7316     smb_ReleaseFID(fidp);
7317
7318     return code;
7319 }
7320
7321 /* SMB_COM_READ_ANDX */
7322 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7323 {
7324     osi_hyper_t offset;
7325     long count;
7326     long finalCount = 0;
7327     unsigned short fd;
7328     unsigned pid;
7329     smb_fid_t *fidp;
7330     smb_t *smbp = (smb_t*) inp;
7331     long code = 0;
7332     cm_scache_t *scp;
7333     cm_user_t *userp;
7334     cm_key_t key;
7335     char *op;
7336
7337     fd = smb_GetSMBParm(inp, 2); /* File ID */
7338     count = smb_GetSMBParm(inp, 5); /* MaxCount */
7339     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7340
7341     if (*inp->wctp == 12) {
7342         /* a request with 64-bit offsets */
7343         offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
7344
7345         if (LargeIntegerLessThanZero(offset)) {
7346             osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
7347                      offset.HighPart, offset.LowPart);
7348             return CM_ERROR_BADSMB;
7349         }
7350     } else {
7351         offset.HighPart = 0;
7352     }
7353
7354     osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
7355              fd, offset.HighPart, offset.LowPart, count);
7356
7357     fd = smb_ChainFID(fd, inp);
7358     fidp = smb_FindFID(vcp, fd, 0);
7359     if (!fidp) {
7360         osi_Log2(smb_logp, "smb_ReceiveV3Read Unknown SMB Fid vcp 0x%p fid %d",
7361                  vcp, fd);
7362         return CM_ERROR_BADFD;
7363     }
7364
7365     lock_ObtainMutex(&fidp->mx);
7366
7367     if (fidp->flags & SMB_FID_IOCTL) {
7368         lock_ReleaseMutex(&fidp->mx);
7369         inp->fid = fd;
7370         code = smb_IoctlV3Read(fidp, vcp, inp, outp);
7371         smb_ReleaseFID(fidp);
7372         return code;
7373     }
7374
7375     if (fidp->flags & SMB_FID_RPC) {
7376         lock_ReleaseMutex(&fidp->mx);
7377         inp->fid = fd;
7378         code = smb_RPCV3Read(fidp, vcp, inp, outp);
7379         smb_ReleaseFID(fidp);
7380         return code;
7381     }
7382
7383     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7384         lock_ReleaseMutex(&fidp->mx);
7385         smb_CloseFID(vcp, fidp, NULL, 0);
7386         smb_ReleaseFID(fidp);
7387         return CM_ERROR_NOSUCHFILE;
7388     }
7389
7390     if (!fidp->scp) {
7391         lock_ReleaseMutex(&fidp->mx);
7392         smb_ReleaseFID(fidp);
7393         return CM_ERROR_BADFDOP;
7394     }
7395
7396     scp = fidp->scp;
7397     cm_HoldSCache(scp);
7398
7399     lock_ReleaseMutex(&fidp->mx);
7400
7401     pid = smbp->pid;
7402     key = cm_GenerateKey(vcp->vcID, pid, fd);
7403     {
7404         LARGE_INTEGER LOffset, LLength;
7405
7406         LOffset.HighPart = offset.HighPart;
7407         LOffset.LowPart = offset.LowPart;
7408         LLength.HighPart = 0;
7409         LLength.LowPart = count;
7410
7411         lock_ObtainWrite(&scp->rw);
7412         code = cm_LockCheckRead(scp, LOffset, LLength, key);
7413         lock_ReleaseWrite(&scp->rw);
7414     }
7415     cm_ReleaseSCache(scp);
7416
7417     if (code) {
7418         smb_ReleaseFID(fidp);
7419         return code;
7420     }
7421
7422     /* set inp->fid so that later read calls in same msg can find fid */
7423     inp->fid = fd;
7424
7425     userp = smb_GetUserFromVCP(vcp, inp);
7426
7427     /* 0 and 1 are reserved for request chaining, were setup by our caller,
7428      * and will be further filled in after we return.
7429      */
7430     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
7431     smb_SetSMBParm(outp, 3, 0); /* resvd */
7432     smb_SetSMBParm(outp, 4, 0); /* resvd */
7433     smb_SetSMBParm(outp, 5, count);     /* # of bytes we're going to read */
7434     /* fill in #6 when we have all the parameters' space reserved */
7435     smb_SetSMBParm(outp, 7, 0); /* resv'd */
7436     smb_SetSMBParm(outp, 8, 0); /* resv'd */
7437     smb_SetSMBParm(outp, 9, 0); /* resv'd */
7438     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
7439     smb_SetSMBParm(outp, 11, 0);        /* reserved */
7440
7441     /* get op ptr after putting in the parms, since otherwise we don't
7442      * know where the data really is.
7443      */
7444     op = smb_GetSMBData(outp, NULL);
7445
7446     /* now fill in offset from start of SMB header to first data byte (to op) */
7447     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
7448
7449     /* set the packet data length the count of the # of bytes */
7450     smb_SetSMBDataLength(outp, count);
7451
7452     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7453
7454     /* fix some things up */
7455     smb_SetSMBParm(outp, 5, finalCount);
7456     smb_SetSMBDataLength(outp, finalCount);
7457
7458     cm_ReleaseUser(userp);
7459     smb_ReleaseFID(fidp);
7460     return code;
7461 }
7462
7463 /*
7464  * Values for createDisp, copied from NTDDK.H
7465  */
7466 #define  FILE_SUPERSEDE 0       // (???)
7467 #define  FILE_OPEN      1       // (open)
7468 #define  FILE_CREATE    2       // (exclusive)
7469 #define  FILE_OPEN_IF   3       // (non-exclusive)
7470 #define  FILE_OVERWRITE 4       // (open & truncate, but do not create)
7471 #define  FILE_OVERWRITE_IF 5    // (open & truncate, or create)
7472
7473 /* Flags field */
7474 #define REQUEST_OPLOCK 2
7475 #define REQUEST_BATCH_OPLOCK 4
7476 #define OPEN_DIRECTORY 8
7477 #define EXTENDED_RESPONSE_REQUIRED 0x10
7478
7479 /* CreateOptions field. */
7480 #define FILE_DIRECTORY_FILE       0x0001
7481 #define FILE_WRITE_THROUGH        0x0002
7482 #define FILE_SEQUENTIAL_ONLY      0x0004
7483 #define FILE_NON_DIRECTORY_FILE   0x0040
7484 #define FILE_NO_EA_KNOWLEDGE      0x0200
7485 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
7486 #define FILE_RANDOM_ACCESS        0x0800
7487 #define FILE_DELETE_ON_CLOSE      0x1000
7488 #define FILE_OPEN_BY_FILE_ID      0x2000
7489 #define FILE_OPEN_FOR_BACKUP_INTENT             0x00004000
7490 #define FILE_NO_COMPRESSION                     0x00008000
7491 #define FILE_RESERVE_OPFILTER                   0x00100000
7492 #define FILE_OPEN_REPARSE_POINT                 0x00200000
7493 #define FILE_OPEN_NO_RECALL                     0x00400000
7494 #define FILE_OPEN_FOR_FREE_SPACE_QUERY          0x00800000
7495
7496 /* SMB_COM_NT_CREATE_ANDX */
7497 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7498 {
7499     clientchar_t *pathp, *realPathp;
7500     long code = 0;
7501     cm_space_t *spacep;
7502     cm_user_t *userp;
7503     cm_scache_t *dscp;          /* parent dir */
7504     cm_scache_t *scp;           /* file to create or open */
7505     cm_scache_t *targetScp;     /* if scp is a symlink */
7506     cm_attr_t setAttr;
7507     clientchar_t *lastNamep;
7508     clientchar_t *treeStartp;
7509     unsigned short nameLength;
7510     unsigned int flags;
7511     unsigned int requestOpLock;
7512     unsigned int requestBatchOpLock;
7513     unsigned int mustBeDir;
7514     unsigned int extendedRespRequired;
7515     unsigned int treeCreate;
7516     int realDirFlag;
7517     unsigned int desiredAccess;
7518     unsigned int extAttributes;
7519     unsigned int createDisp;
7520     unsigned int createOptions;
7521     unsigned int shareAccess;
7522     unsigned short baseFid;
7523     smb_fid_t *baseFidp;
7524     smb_fid_t *fidp;
7525     cm_scache_t *baseDirp;
7526     unsigned short openAction;
7527     int parmSlot;
7528     long fidflags;
7529     FILETIME ft;
7530     LARGE_INTEGER sz;
7531     clientchar_t *tidPathp;
7532     BOOL foundscp;
7533     cm_req_t req;
7534     int created = 0;
7535     int prefetch = 0;
7536     int checkDoneRequired = 0;
7537     cm_lock_data_t *ldp = NULL;
7538     BOOL is_rpc = FALSE;
7539     BOOL is_ipc = FALSE;
7540
7541     smb_InitReq(&req);
7542
7543     /* This code is very long and has a lot of if-then-else clauses
7544      * scp and dscp get reused frequently and we need to ensure that
7545      * we don't lose a reference.  Start by ensuring that they are NULL.
7546      */
7547     scp = NULL;
7548     dscp = NULL;
7549     treeCreate = FALSE;
7550     foundscp = FALSE;
7551
7552     nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
7553     flags = smb_GetSMBOffsetParm(inp, 3, 1)
7554         | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
7555     requestOpLock = flags & REQUEST_OPLOCK;
7556     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7557     mustBeDir = flags & OPEN_DIRECTORY;
7558     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7559
7560     /*
7561      * Why all of a sudden 32-bit FID?
7562      * We will reject all bits higher than 16.
7563      */
7564     if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
7565         return CM_ERROR_INVAL;
7566     baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
7567     desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
7568         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7569     extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
7570         | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
7571     shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
7572         | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
7573     createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
7574         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
7575     createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
7576         | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
7577
7578     /* mustBeDir is never set; createOptions directory bit seems to be
7579      * more important
7580      */
7581     if (createOptions & FILE_DIRECTORY_FILE)
7582         realDirFlag = 1;
7583     else if (createOptions & FILE_NON_DIRECTORY_FILE)
7584         realDirFlag = 0;
7585     else
7586         realDirFlag = -1;
7587
7588     pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
7589                               NULL, SMB_STRF_ANSIPATH);
7590
7591     /* Sometimes path is not null-terminated, so we make a copy. */
7592     realPathp = malloc(nameLength+sizeof(clientchar_t));
7593     memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
7594     realPathp[nameLength/sizeof(clientchar_t)] = 0;
7595
7596     spacep = inp->spacep;
7597     /* smb_StripLastComponent will strip "::$DATA" if present */
7598     smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7599
7600     osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
7601     osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
7602     osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
7603
7604     if (baseFid == 0) {
7605         baseFidp = NULL;
7606         baseDirp = cm_RootSCachep(cm_rootUserp, &req);
7607         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7608         if (code == CM_ERROR_TIDIPC) {
7609             /* Attempt to use a TID allocated for IPC.  The client
7610              * is probably looking for DCE RPC end points which we
7611              * don't support OR it could be looking to make a DFS
7612              * referral request.
7613              */
7614             osi_Log0(smb_logp, "NTCreateX received IPC TID");
7615             is_ipc = TRUE;
7616         }
7617     }
7618
7619     osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
7620
7621     if (lastNamep &&
7622
7623         ((is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)) ||
7624
7625          /* special case magic file name for receiving IOCTL requests
7626           * (since IOCTL calls themselves aren't getting through).
7627           */
7628          cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0)) {
7629
7630         unsigned short file_type = 0;
7631         unsigned short device_state = 0;
7632
7633         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7634
7635         if (is_rpc) {
7636             code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
7637             osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
7638             if (code) {
7639                 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
7640                 smb_ReleaseFID(fidp);
7641                 free(realPathp);
7642                 return code;
7643             }
7644         } else {
7645             smb_SetupIoctlFid(fidp, spacep);
7646             osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
7647         }
7648
7649         /* set inp->fid so that later read calls in same msg can find fid */
7650         inp->fid = fidp->fid;
7651
7652         /* out parms */
7653         parmSlot = 2;
7654         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
7655         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7656         smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
7657         /* times */
7658         memset(&ft, 0, sizeof(ft));
7659         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7660         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7661         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7662         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7663         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
7664         sz.HighPart = 0x7fff; sz.LowPart = 0;
7665         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
7666         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
7667         smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;  /* filetype */
7668         smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;       /* dev state */
7669         smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
7670         smb_SetSMBDataLength(outp, 0);
7671
7672         /* clean up fid reference */
7673         smb_ReleaseFID(fidp);
7674         free(realPathp);
7675         return 0;
7676     }
7677
7678 #ifndef DFS_SUPPORT
7679     if (is_ipc) {
7680         osi_Log0(smb_logp, "NTCreateX rejecting IPC TID");
7681         free(realPathp);
7682         return CM_ERROR_BADFD;
7683     }
7684 #endif
7685
7686     if (!cm_IsValidClientString(realPathp)) {
7687 #ifdef DEBUG
7688         clientchar_t * hexp;
7689
7690         hexp = cm_GetRawCharsAlloc(realPathp, -1);
7691         osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
7692                  osi_LogSaveClientString(smb_logp, hexp));
7693         if (hexp)
7694             free(hexp);
7695 #else
7696         osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
7697 #endif
7698         free(realPathp);
7699         return CM_ERROR_BADNTFILENAME;
7700     }
7701
7702     userp = smb_GetUserFromVCP(vcp, inp);
7703     if (!userp) {
7704         osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
7705         free(realPathp);
7706         return CM_ERROR_INVAL;
7707     }
7708
7709     if (baseFidp != 0) {
7710         baseFidp = smb_FindFID(vcp, baseFid, 0);
7711         if (!baseFidp) {
7712             osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
7713             cm_ReleaseUser(userp);
7714             free(realPathp);
7715             return CM_ERROR_INVAL;
7716         }
7717
7718         if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7719             free(realPathp);
7720             smb_CloseFID(vcp, baseFidp, NULL, 0);
7721             smb_ReleaseFID(baseFidp);
7722             cm_ReleaseUser(userp);
7723             return CM_ERROR_NOSUCHPATH;
7724         }
7725
7726         baseDirp = baseFidp->scp;
7727         tidPathp = NULL;
7728     }
7729
7730     /* compute open mode */
7731     fidflags = 0;
7732     if (desiredAccess & DELETE)
7733         fidflags |= SMB_FID_OPENDELETE;
7734     if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7735         fidflags |= SMB_FID_OPENREAD_LISTDIR;
7736     if (desiredAccess & AFS_ACCESS_WRITE)
7737         fidflags |= SMB_FID_OPENWRITE;
7738     if (createOptions & FILE_DELETE_ON_CLOSE)
7739         fidflags |= SMB_FID_DELONCLOSE;
7740     if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7741         fidflags |= SMB_FID_SEQUENTIAL;
7742     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7743         fidflags |= SMB_FID_RANDOM;
7744     if (createOptions & FILE_OPEN_REPARSE_POINT)
7745         osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7746     if (smb_IsExecutableFileName(lastNamep))
7747         fidflags |= SMB_FID_EXECUTABLE;
7748
7749     /* and the share mode */
7750     if (shareAccess & FILE_SHARE_READ)
7751         fidflags |= SMB_FID_SHARE_READ;
7752     if (shareAccess & FILE_SHARE_WRITE)
7753         fidflags |= SMB_FID_SHARE_WRITE;
7754
7755     osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7756     code = 0;
7757
7758     /* For an exclusive create, we want to do a case sensitive match for the last component. */
7759     if ( createDisp == FILE_CREATE ||
7760          createDisp == FILE_OVERWRITE ||
7761          createDisp == FILE_OVERWRITE_IF) {
7762         code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7763                         userp, tidPathp, &req, &dscp);
7764         if (code == 0) {
7765 #ifdef DFS_SUPPORT
7766             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7767                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7768                                                           spacep->wdata);
7769                 cm_ReleaseSCache(dscp);
7770                 cm_ReleaseUser(userp);
7771                 free(realPathp);
7772                 if (baseFidp)
7773                     smb_ReleaseFID(baseFidp);
7774                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7775                     return CM_ERROR_PATH_NOT_COVERED;
7776                 else
7777                     return CM_ERROR_NOSUCHPATH;
7778             }
7779 #endif /* DFS_SUPPORT */
7780             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7781                              userp, &req, &scp);
7782             if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7783                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7784                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7785                 if (code == 0 && realDirFlag == 1) {
7786                     cm_ReleaseSCache(scp);
7787                     cm_ReleaseSCache(dscp);
7788                     cm_ReleaseUser(userp);
7789                     free(realPathp);
7790                     if (baseFidp)
7791                         smb_ReleaseFID(baseFidp);
7792                     return CM_ERROR_EXISTS;
7793                 }
7794             }
7795             /* we have both scp and dscp */
7796         }
7797     } else {
7798         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7799                         userp, tidPathp, &req, &scp);
7800 #ifdef DFS_SUPPORT
7801         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7802             int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7803             cm_ReleaseSCache(scp);
7804             cm_ReleaseUser(userp);
7805             free(realPathp);
7806             if (baseFidp)
7807                 smb_ReleaseFID(baseFidp);
7808             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7809                 return CM_ERROR_PATH_NOT_COVERED;
7810             else
7811                 return CM_ERROR_NOSUCHPATH;
7812         }
7813 #endif /* DFS_SUPPORT */
7814         /* we might have scp but not dscp */
7815     }
7816
7817     if (code &&
7818         code != CM_ERROR_NOSUCHFILE &&
7819         code != CM_ERROR_NOSUCHPATH &&
7820         code != CM_ERROR_BPLUS_NOMATCH) {
7821         cm_ReleaseUser(userp);
7822         free(realPathp);
7823         if (baseFidp)
7824             smb_ReleaseFID(baseFidp);
7825         return code;
7826     }
7827
7828     if (scp)
7829         foundscp = TRUE;
7830
7831     if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7832         /* look up parent directory */
7833         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7834          * the immediate parent.  We have to work our way up realPathp until we hit something that we
7835          * recognize.
7836          */
7837
7838         /* we might or might not have scp */
7839
7840         if (dscp == NULL) {
7841             do {
7842                 clientchar_t *tp;
7843
7844                 code = cm_NameI(baseDirp, spacep->wdata,
7845                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7846                                 userp, tidPathp, &req, &dscp);
7847
7848 #ifdef DFS_SUPPORT
7849                 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7850                     int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7851                                                               spacep->wdata);
7852                     if (scp)
7853                         cm_ReleaseSCache(scp);
7854                     cm_ReleaseSCache(dscp);
7855                     cm_ReleaseUser(userp);
7856                     free(realPathp);
7857                     if (baseFidp)
7858                         smb_ReleaseFID(baseFidp);
7859                     if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7860                         return CM_ERROR_PATH_NOT_COVERED;
7861                     else
7862                         return CM_ERROR_NOSUCHPATH;
7863                 }
7864 #endif /* DFS_SUPPORT */
7865
7866                 if (code &&
7867                     (code == CM_ERROR_NOSUCHFILE ||
7868                      code == CM_ERROR_NOSUCHPATH ||
7869                      code == CM_ERROR_BPLUS_NOMATCH) &&
7870                     (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7871                     (createDisp == FILE_CREATE) &&
7872                     (realDirFlag == 1)) {
7873                     *tp++ = 0;
7874                     treeCreate = TRUE;
7875                     treeStartp = realPathp + (tp - spacep->wdata);
7876
7877                     if (*tp && !smb_IsLegalFilename(tp)) {
7878                         cm_ReleaseUser(userp);
7879                         if (baseFidp)
7880                             smb_ReleaseFID(baseFidp);
7881                         free(realPathp);
7882                         if (scp)
7883                             cm_ReleaseSCache(scp);
7884                         return CM_ERROR_BADNTFILENAME;
7885                     }
7886                     code = 0;
7887                 }
7888             } while (dscp == NULL && code == 0);
7889         } else
7890             code = 0;
7891
7892         /* we might have scp and we might have dscp */
7893
7894         if (baseFidp)
7895             smb_ReleaseFID(baseFidp);
7896
7897         if (code) {
7898             osi_Log0(smb_logp,"NTCreateX parent not found");
7899             if (scp)
7900                 cm_ReleaseSCache(scp);
7901             if (dscp)
7902                 cm_ReleaseSCache(dscp);
7903             cm_ReleaseUser(userp);
7904             free(realPathp);
7905             return code;
7906         }
7907
7908         if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7909             /* A file exists where we want a directory. */
7910             if (scp)
7911                 cm_ReleaseSCache(scp);
7912             cm_ReleaseSCache(dscp);
7913             cm_ReleaseUser(userp);
7914             free(realPathp);
7915             return CM_ERROR_EXISTS;
7916         }
7917
7918         if (!lastNamep)
7919             lastNamep = realPathp;
7920         else
7921             lastNamep++;
7922
7923         if (!smb_IsLegalFilename(lastNamep)) {
7924             if (scp)
7925                 cm_ReleaseSCache(scp);
7926             if (dscp)
7927                 cm_ReleaseSCache(dscp);
7928             cm_ReleaseUser(userp);
7929             free(realPathp);
7930             return CM_ERROR_BADNTFILENAME;
7931         }
7932
7933         if (!foundscp && !treeCreate) {
7934             if ( createDisp == FILE_CREATE ||
7935                  createDisp == FILE_OVERWRITE ||
7936                  createDisp == FILE_OVERWRITE_IF)
7937             {
7938                 code = cm_Lookup(dscp, lastNamep,
7939                                   CM_FLAG_FOLLOW, userp, &req, &scp);
7940             } else {
7941                 code = cm_Lookup(dscp, lastNamep,
7942                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7943                                  userp, &req, &scp);
7944             }
7945             if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7946                 if (dscp)
7947                     cm_ReleaseSCache(dscp);
7948                 cm_ReleaseUser(userp);
7949                 free(realPathp);
7950                 return code;
7951             }
7952         }
7953         /* we have scp and dscp */
7954     } else {
7955         /* we have scp but not dscp */
7956         if (baseFidp)
7957             smb_ReleaseFID(baseFidp);
7958     }
7959
7960     /* if we get here, if code is 0, the file exists and is represented by
7961      * scp.  Otherwise, we have to create it.  The dir may be represented
7962      * by dscp, or we may have found the file directly.  If code is non-zero,
7963      * scp is NULL.
7964      */
7965
7966     /*
7967      * open the file itself
7968      * allocate the fidp early so the smb fid can be used by cm_CheckNTOpen()
7969      */
7970     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7971     osi_assertx(fidp, "null smb_fid_t");
7972
7973     /* save a reference to the user */
7974     cm_HoldUser(userp);
7975     fidp->userp = userp;
7976
7977     if (code == 0 && !treeCreate) {
7978         code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
7979         if (code) {
7980             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7981             if (dscp)
7982                 cm_ReleaseSCache(dscp);
7983             if (scp)
7984                 cm_ReleaseSCache(scp);
7985             cm_ReleaseUser(userp);
7986             smb_CloseFID(vcp, fidp, NULL, 0);
7987             smb_ReleaseFID(fidp);
7988             free(realPathp);
7989             return code;
7990         }
7991         checkDoneRequired = 1;
7992
7993         if (createDisp == FILE_CREATE) {
7994             /* oops, file shouldn't be there */
7995             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7996             if (dscp)
7997                 cm_ReleaseSCache(dscp);
7998             if (scp)
7999                 cm_ReleaseSCache(scp);
8000             cm_ReleaseUser(userp);
8001             smb_CloseFID(vcp, fidp, NULL, 0);
8002             smb_ReleaseFID(fidp);
8003             free(realPathp);
8004             return CM_ERROR_EXISTS;
8005         }
8006
8007         if ( createDisp == FILE_OVERWRITE ||
8008              createDisp == FILE_OVERWRITE_IF) {
8009
8010             setAttr.mask = CM_ATTRMASK_LENGTH;
8011             setAttr.length.LowPart = 0;
8012             setAttr.length.HighPart = 0;
8013             /* now watch for a symlink */
8014             code = 0;
8015             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8016                 targetScp = 0;
8017                 osi_assertx(dscp != NULL, "null cm_scache_t");
8018                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8019                 if (code == 0) {
8020                     /* we have a more accurate file to use (the
8021                      * target of the symbolic link).  Otherwise,
8022                      * we'll just use the symlink anyway.
8023                      */
8024                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
8025                               scp, targetScp);
8026                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8027                     cm_ReleaseSCache(scp);
8028                     scp = targetScp;
8029                     code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
8030                     if (code) {
8031                         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8032                         if (dscp)
8033                             cm_ReleaseSCache(dscp);
8034                         if (scp)
8035                             cm_ReleaseSCache(scp);
8036                         cm_ReleaseUser(userp);
8037                         smb_CloseFID(vcp, fidp, NULL, 0);
8038                         smb_ReleaseFID(fidp);
8039                         free(realPathp);
8040                         return code;
8041                     }
8042                 }
8043             }
8044             code = cm_SetAttr(scp, &setAttr, userp, &req);
8045             openAction = 3;     /* truncated existing file */
8046         }
8047         else
8048             openAction = 1;     /* found existing file */
8049
8050     } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8051         /* don't create if not found */
8052         if (dscp)
8053             cm_ReleaseSCache(dscp);
8054         if (scp)
8055             cm_ReleaseSCache(scp);
8056         cm_ReleaseUser(userp);
8057         smb_CloseFID(vcp, fidp, NULL, 0);
8058         smb_ReleaseFID(fidp);
8059         free(realPathp);
8060         return CM_ERROR_NOSUCHFILE;
8061     } else if (realDirFlag == 0 || realDirFlag == -1) {
8062         osi_assertx(dscp != NULL, "null cm_scache_t");
8063         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
8064                   osi_LogSaveClientString(smb_logp, lastNamep));
8065         openAction = 2;         /* created file */
8066         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8067         setAttr.clientModTime = time(NULL);
8068         smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
8069
8070         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
8071         if (code == 0) {
8072             created = 1;
8073             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8074                 smb_NotifyChange(FILE_ACTION_ADDED,
8075                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8076                                  dscp, lastNamep, NULL, TRUE);
8077         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8078             /* Not an exclusive create, and someone else tried
8079              * creating it already, then we open it anyway.  We
8080              * don't bother retrying after this, since if this next
8081              * fails, that means that the file was deleted after we
8082              * started this call.
8083              */
8084             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8085                               userp, &req, &scp);
8086             if (code == 0) {
8087                 if (createDisp == FILE_OVERWRITE_IF) {
8088                     setAttr.mask = CM_ATTRMASK_LENGTH;
8089                     setAttr.length.LowPart = 0;
8090                     setAttr.length.HighPart = 0;
8091
8092                     /* now watch for a symlink */
8093                     code = 0;
8094                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8095                         targetScp = 0;
8096                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8097                         if (code == 0) {
8098                             /* we have a more accurate file to use (the
8099                              * target of the symbolic link).  Otherwise,
8100                              * we'll just use the symlink anyway.
8101                              */
8102                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
8103                                       scp, targetScp);
8104                             cm_ReleaseSCache(scp);
8105                             scp = targetScp;
8106                         }
8107                     }
8108                     code = cm_SetAttr(scp, &setAttr, userp, &req);
8109                 }
8110             }   /* lookup succeeded */
8111         }
8112     } else {
8113         clientchar_t *tp, *pp;
8114         clientchar_t *cp; /* This component */
8115         int clen = 0; /* length of component */
8116         cm_scache_t *tscp1, *tscp2;
8117         int isLast = 0;
8118
8119         /* create directory */
8120         if ( !treeCreate )
8121             treeStartp = lastNamep;
8122         osi_assertx(dscp != NULL, "null cm_scache_t");
8123         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
8124                   osi_LogSaveClientString(smb_logp, treeStartp));
8125         openAction = 2;         /* created directory */
8126
8127         /* if the request is to create the root directory
8128          * it will appear as a directory name of the nul-string
8129          * and a code of CM_ERROR_NOSUCHFILE
8130          */
8131         if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
8132             code = CM_ERROR_EXISTS;
8133
8134         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8135         setAttr.clientModTime = time(NULL);
8136         smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
8137
8138         pp = treeStartp;
8139         cp = spacep->wdata;
8140         tscp1 = dscp;
8141         cm_HoldSCache(tscp1);
8142         tscp2 = NULL;
8143
8144         while (pp && *pp) {
8145             tp = cm_ClientStrChr(pp, '\\');
8146             if (!tp) {
8147                 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
8148                 clen = (int)cm_ClientStrLen(cp);
8149                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
8150             } else {
8151                 clen = (int)(tp - pp);
8152                 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
8153                                  pp, clen);
8154                 *(cp + clen) = 0;
8155                 tp++;
8156             }
8157             pp = tp;
8158
8159             if (clen == 0)
8160                 continue; /* the supplied path can't have consecutive slashes either , but */
8161
8162             /* cp is the next component to be created. */
8163             code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
8164             if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
8165                 smb_NotifyChange(FILE_ACTION_ADDED,
8166                                  FILE_NOTIFY_CHANGE_DIR_NAME,
8167                                  tscp1, cp, NULL, TRUE);
8168             if (code == 0 ||
8169                 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8170                 /* Not an exclusive create, and someone else tried
8171                  * creating it already, then we open it anyway.  We
8172                  * don't bother retrying after this, since if this next
8173                  * fails, that means that the file was deleted after we
8174                  * started this call.
8175                  */
8176                 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
8177                                  userp, &req, &tscp2);
8178             }
8179             if (code)
8180                 break;
8181
8182             if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
8183                 cm_ReleaseSCache(tscp1);
8184                 tscp1 = tscp2; /* Newly created directory will be next parent */
8185                 /* the hold is transfered to tscp1 from tscp2 */
8186             }
8187         }
8188
8189         if (dscp)
8190             cm_ReleaseSCache(dscp);
8191         dscp = tscp1;
8192         if (scp)
8193             cm_ReleaseSCache(scp);
8194         scp = tscp2;
8195         /*
8196          * if we get here and code == 0, then scp is the last directory created, and dscp is the
8197          * parent of scp.
8198          */
8199     }
8200
8201     if (code) {
8202         /* something went wrong creating or truncating the file */
8203         if (checkDoneRequired)
8204             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8205         if (scp)
8206             cm_ReleaseSCache(scp);
8207         if (dscp)
8208             cm_ReleaseSCache(dscp);
8209         cm_ReleaseUser(userp);
8210         smb_CloseFID(vcp, fidp, NULL, 0);
8211         smb_ReleaseFID(fidp);
8212         free(realPathp);
8213         return code;
8214     }
8215
8216     /* make sure we have file vs. dir right (only applies for single component case) */
8217     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8218         /* now watch for a symlink */
8219         code = 0;
8220         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8221             cm_scache_t * targetScp = 0;
8222             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8223             if (code == 0) {
8224                 /* we have a more accurate file to use (the
8225                 * target of the symbolic link).  Otherwise,
8226                 * we'll just use the symlink anyway.
8227                 */
8228                 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
8229                 if (checkDoneRequired) {
8230                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8231                     checkDoneRequired = 0;
8232                 }
8233                 cm_ReleaseSCache(scp);
8234                 scp = targetScp;
8235             }
8236         }
8237
8238         if (scp->fileType != CM_SCACHETYPE_FILE) {
8239             if (checkDoneRequired)
8240                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8241             if (dscp)
8242                 cm_ReleaseSCache(dscp);
8243             cm_ReleaseSCache(scp);
8244             cm_ReleaseUser(userp);
8245             smb_CloseFID(vcp, fidp, NULL, 0);
8246             smb_ReleaseFID(fidp);
8247             free(realPathp);
8248             return CM_ERROR_ISDIR;
8249         }
8250     }
8251
8252     /* (only applies to single component case) */
8253     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8254         if (checkDoneRequired)
8255             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8256         cm_ReleaseSCache(scp);
8257         if (dscp)
8258             cm_ReleaseSCache(dscp);
8259         cm_ReleaseUser(userp);
8260         smb_CloseFID(vcp, fidp, NULL, 0);
8261         smb_ReleaseFID(fidp);
8262         free(realPathp);
8263         return CM_ERROR_NOTDIR;
8264     }
8265
8266     /* If we are restricting sharing, we should do so with a suitable
8267        share lock. */
8268     if (scp->fileType == CM_SCACHETYPE_FILE &&
8269         !(fidflags & SMB_FID_SHARE_WRITE)) {
8270         cm_key_t key;
8271         LARGE_INTEGER LOffset, LLength;
8272         int sLockType;
8273
8274         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8275         LOffset.LowPart = SMB_FID_QLOCK_LOW;
8276         LLength.HighPart = 0;
8277         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8278
8279         /* If we are not opening the file for writing, then we don't
8280            try to get an exclusive lock.  No one else should be able to
8281            get an exclusive lock on the file anyway, although someone
8282            else can get a shared lock. */
8283         if ((fidflags & SMB_FID_SHARE_READ) ||
8284             !(fidflags & SMB_FID_OPENWRITE)) {
8285             sLockType = LOCKING_ANDX_SHARED_LOCK;
8286         } else {
8287             sLockType = 0;
8288         }
8289
8290         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8291
8292         lock_ObtainWrite(&scp->rw);
8293         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8294         lock_ReleaseWrite(&scp->rw);
8295
8296         if (code) {
8297             if (checkDoneRequired)
8298                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8299             cm_ReleaseSCache(scp);
8300             if (dscp)
8301                 cm_ReleaseSCache(dscp);
8302             cm_ReleaseUser(userp);
8303             smb_CloseFID(vcp, fidp, NULL, 0);
8304             smb_ReleaseFID(fidp);
8305             free(realPathp);
8306             return CM_ERROR_SHARING_VIOLATION;
8307         }
8308     }
8309
8310     /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
8311     if (checkDoneRequired) {
8312         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8313         checkDoneRequired = 0;
8314     }
8315
8316     lock_ObtainMutex(&fidp->mx);
8317     /* save a pointer to the vnode */
8318     fidp->scp = scp;    /* Hold transfered to fidp->scp and no longer needed */
8319     lock_ObtainWrite(&scp->rw);
8320     scp->flags |= CM_SCACHEFLAG_SMB_FID;
8321     lock_ReleaseWrite(&scp->rw);
8322     osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
8323
8324     fidp->flags = fidflags;
8325
8326     /* remember if the file was newly created */
8327     if (created)
8328         fidp->flags |= SMB_FID_CREATED;
8329
8330     /* save parent dir and pathname for delete or change notification */
8331     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8332         osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
8333         fidp->flags |= SMB_FID_NTOPEN;
8334         fidp->NTopen_dscp = dscp;
8335         dscp = NULL;
8336         fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8337     }
8338     fidp->NTopen_wholepathp = realPathp;
8339     lock_ReleaseMutex(&fidp->mx);
8340
8341     /* we don't need this any longer */
8342     if (dscp) {
8343         cm_ReleaseSCache(dscp);
8344         dscp = NULL;
8345     }
8346
8347     cm_Open(scp, 0, userp);
8348
8349     /* set inp->fid so that later read calls in same msg can find fid */
8350     inp->fid = fidp->fid;
8351
8352     lock_ObtainRead(&scp->rw);
8353
8354     /*
8355      * Always send the standard response.  Sending the extended
8356      * response results in the Explorer Shell being unable to
8357      * access directories at random times.
8358      */
8359     if (1 /*!extendedRespRequired */) {
8360         /* out parms */
8361         parmSlot = 2;
8362         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
8363         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8364         smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8365         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8366         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8367         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8368         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8369         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8370         smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8371         parmSlot += 2;
8372         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8373         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8374         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
8375         smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8376         parmSlot++;     /* dev state */
8377         smb_SetSMBParmByte(outp, parmSlot,
8378                             (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8379                               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8380                               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8381         smb_SetSMBDataLength(outp, 0);
8382     } else {
8383         /* out parms */
8384         parmSlot = 2;
8385         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
8386         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8387         smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8388         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8389         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8390         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8391         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8392         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8393         smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8394         parmSlot += 2;
8395         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8396         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8397         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
8398         smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8399         parmSlot++;     /* dev state */
8400         smb_SetSMBParmByte(outp, parmSlot,
8401                             (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8402                               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8403                               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8404         /* Setting the GUID results in a failure with cygwin */
8405         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8406         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8407         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8408         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8409         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8410         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8411         /* Maxmimal access rights */
8412         smb_SetSMBParmLong(outp, parmSlot, 0x001f01ff); parmSlot += 2;
8413         /* Guest access rights */
8414         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8415         smb_SetSMBDataLength(outp, 0);
8416     }
8417
8418     if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8419         LargeIntegerGreaterThanZero(scp->length) &&
8420         !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8421         prefetch = 1;
8422     }
8423     lock_ReleaseRead(&scp->rw);
8424
8425     if (prefetch) {
8426         rock_BkgFetch_t *rockp = malloc(sizeof(*rockp));
8427
8428         if (rockp) {
8429             rockp->base.LowPart = 0;
8430             rockp->base.HighPart = 0;
8431             rockp->length = scp->length;
8432
8433             cm_QueueBKGRequest(scp, cm_BkgPrefetch, rockp, userp, &req);
8434
8435             /* rock is freed by cm_BkgDaemon */
8436         }
8437     }
8438
8439     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
8440               osi_LogSaveClientString(smb_logp, realPathp));
8441
8442     cm_ReleaseUser(userp);
8443     smb_ReleaseFID(fidp);
8444
8445     /* Can't free realPathp if we get here since
8446        fidp->NTopen_wholepathp is pointing there */
8447
8448     /* leave scp held since we put it in fidp->scp */
8449     return 0;
8450 }
8451
8452 /*
8453  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
8454  * Instead, ultimately, would like to use a subroutine for common code.
8455  */
8456
8457 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
8458 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8459 {
8460     clientchar_t *pathp, *realPathp;
8461     long code = 0;
8462     cm_space_t *spacep;
8463     cm_user_t *userp;
8464     cm_scache_t *dscp;          /* parent dir */
8465     cm_scache_t *scp;           /* file to create or open */
8466     cm_scache_t *targetScp;     /* if scp is a symlink */
8467     cm_attr_t setAttr;
8468     clientchar_t *lastNamep;
8469     unsigned long nameLength;
8470     unsigned int flags;
8471     unsigned int requestOpLock;
8472     unsigned int requestBatchOpLock;
8473     unsigned int mustBeDir;
8474     unsigned int extendedRespRequired;
8475     int realDirFlag;
8476     unsigned int desiredAccess;
8477     unsigned int allocSize;
8478     unsigned int shareAccess;
8479     unsigned int extAttributes;
8480     unsigned int createDisp;
8481     unsigned int sdLen;
8482     unsigned int eaLen;
8483     unsigned int impLevel;
8484     unsigned int secFlags;
8485     unsigned int createOptions;
8486     unsigned short baseFid;
8487     smb_fid_t *baseFidp;
8488     smb_fid_t *fidp;
8489     cm_scache_t *baseDirp;
8490     unsigned short openAction;
8491     int parmSlot;
8492     long fidflags;
8493     FILETIME ft;
8494     clientchar_t *tidPathp;
8495     BOOL foundscp;
8496     int parmOffset, dataOffset;
8497     char *parmp;
8498     ULONG *lparmp;
8499     char *outData;
8500     cm_req_t req;
8501     int created = 0;
8502     int prefetch = 0;
8503     cm_lock_data_t *ldp = NULL;
8504     int checkDoneRequired = 0;
8505
8506     smb_InitReq(&req);
8507
8508     foundscp = FALSE;
8509     scp = NULL;
8510
8511     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8512         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8513     parmp = inp->data + parmOffset;
8514     lparmp = (ULONG *) parmp;
8515
8516     flags = lparmp[0];
8517     requestOpLock = flags & REQUEST_OPLOCK;
8518     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
8519     mustBeDir = flags & OPEN_DIRECTORY;
8520     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
8521
8522     /*
8523      * Why all of a sudden 32-bit FID?
8524      * We will reject all bits higher than 16.
8525      */
8526     if (lparmp[1] & 0xFFFF0000)
8527         return CM_ERROR_INVAL;
8528     baseFid = (unsigned short)lparmp[1];
8529     desiredAccess = lparmp[2];
8530     allocSize = lparmp[3];
8531     extAttributes = lparmp[5];
8532     shareAccess = lparmp[6];
8533     createDisp = lparmp[7];
8534     createOptions = lparmp[8];
8535     sdLen = lparmp[9];
8536     eaLen = lparmp[10];
8537     nameLength = lparmp[11];    /* spec says chars but appears to be bytes */
8538     impLevel = lparmp[12];
8539     secFlags = lparmp[13];
8540
8541     /* mustBeDir is never set; createOptions directory bit seems to be
8542      * more important
8543      */
8544     if (createOptions & FILE_DIRECTORY_FILE)
8545         realDirFlag = 1;
8546     else if (createOptions & FILE_NON_DIRECTORY_FILE)
8547         realDirFlag = 0;
8548     else
8549         realDirFlag = -1;
8550
8551     pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
8552                                nameLength, NULL, SMB_STRF_ANSIPATH);
8553     /* Sometimes path is not nul-terminated, so we make a copy. */
8554     realPathp = malloc(nameLength+sizeof(clientchar_t));
8555     memcpy(realPathp, pathp, nameLength);
8556     realPathp[nameLength/sizeof(clientchar_t)] = 0;
8557     spacep = cm_GetSpace();
8558     /* smb_StripLastComponent will strip "::$DATA" if present */
8559     smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
8560
8561     osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
8562     osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
8563     osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
8564     osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
8565
8566     if ( realDirFlag == 1 &&
8567          ( createDisp == FILE_SUPERSEDE ||
8568            createDisp == FILE_OVERWRITE ||
8569            createDisp == FILE_OVERWRITE_IF))
8570     {
8571         osi_Log0(smb_logp, "NTTranCreate rejecting invalid readDirFlag and createDisp combination");
8572         cm_FreeSpace(spacep);
8573         free(realPathp);
8574         return CM_ERROR_INVAL;
8575     }
8576
8577     /*
8578      * Nothing here to handle SMB_IOCTL_FILENAME.
8579      * Will add it if necessary.
8580      */
8581
8582     if (!cm_IsValidClientString(realPathp)) {
8583 #ifdef DEBUG
8584         clientchar_t * hexp;
8585
8586         hexp = cm_GetRawCharsAlloc(realPathp, -1);
8587         osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
8588                  osi_LogSaveClientString(smb_logp, hexp));
8589         if (hexp)
8590         free(hexp);
8591 #else
8592         osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
8593 #endif
8594         cm_FreeSpace(spacep);
8595         free(realPathp);
8596         return CM_ERROR_BADNTFILENAME;
8597     }
8598
8599     userp = smb_GetUserFromVCP(vcp, inp);
8600     if (!userp) {
8601         osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
8602         cm_FreeSpace(spacep);
8603         free(realPathp);
8604         return CM_ERROR_INVAL;
8605     }
8606
8607     if (baseFid == 0) {
8608         baseFidp = NULL;
8609         baseDirp = cm_RootSCachep(cm_rootUserp, &req);
8610         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8611         if (code == CM_ERROR_TIDIPC) {
8612             /* Attempt to use a TID allocated for IPC.  The client
8613              * is probably looking for DCE RPC end points which we
8614              * don't support OR it could be looking to make a DFS
8615              * referral request.
8616              */
8617             osi_Log0(smb_logp, "NTTranCreate received IPC TID");
8618 #ifndef DFS_SUPPORT
8619             cm_FreeSpace(spacep);
8620             free(realPathp);
8621             cm_ReleaseUser(userp);
8622             return CM_ERROR_NOSUCHPATH;
8623 #endif
8624         }
8625     } else {
8626         baseFidp = smb_FindFID(vcp, baseFid, 0);
8627         if (!baseFidp) {
8628             osi_Log2(smb_logp, "NTTranCreate Unknown SMB Fid vcp 0x%p fid %d",
8629                       vcp, baseFid);
8630             cm_FreeSpace(spacep);
8631             free(realPathp);
8632             cm_ReleaseUser(userp);
8633             return CM_ERROR_BADFD;
8634         }
8635
8636         if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8637             cm_FreeSpace(spacep);
8638             free(realPathp);
8639             cm_ReleaseUser(userp);
8640             smb_CloseFID(vcp, baseFidp, NULL, 0);
8641             smb_ReleaseFID(baseFidp);
8642             return CM_ERROR_NOSUCHPATH;
8643         }
8644
8645         baseDirp = baseFidp->scp;
8646         tidPathp = NULL;
8647     }
8648
8649     /* compute open mode */
8650     fidflags = 0;
8651     if (desiredAccess & DELETE)
8652         fidflags |= SMB_FID_OPENDELETE;
8653     if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
8654         fidflags |= SMB_FID_OPENREAD_LISTDIR;
8655     if (desiredAccess & AFS_ACCESS_WRITE)
8656         fidflags |= SMB_FID_OPENWRITE;
8657     if (createOptions & FILE_DELETE_ON_CLOSE)
8658         fidflags |= SMB_FID_DELONCLOSE;
8659     if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
8660         fidflags |= SMB_FID_SEQUENTIAL;
8661     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
8662         fidflags |= SMB_FID_RANDOM;
8663     if (createOptions & FILE_OPEN_REPARSE_POINT)
8664         osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
8665     if (smb_IsExecutableFileName(lastNamep))
8666         fidflags |= SMB_FID_EXECUTABLE;
8667
8668     /* And the share mode */
8669     if (shareAccess & FILE_SHARE_READ)
8670         fidflags |= SMB_FID_SHARE_READ;
8671     if (shareAccess & FILE_SHARE_WRITE)
8672         fidflags |= SMB_FID_SHARE_WRITE;
8673
8674     dscp = NULL;
8675     code = 0;
8676
8677     code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8678                     userp, tidPathp, &req, &dscp);
8679     if (code == 0) {
8680 #ifdef DFS_SUPPORT
8681         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8682             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8683             cm_ReleaseSCache(dscp);
8684             cm_ReleaseUser(userp);
8685             cm_FreeSpace(spacep);
8686             free(realPathp);
8687             if (baseFidp)
8688                 smb_ReleaseFID(baseFidp);
8689             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8690                 return CM_ERROR_PATH_NOT_COVERED;
8691             else
8692                 return CM_ERROR_NOSUCHPATH;
8693         }
8694 #endif /* DFS_SUPPORT */
8695         code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
8696                          userp, &req, &scp);
8697         if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
8698
8699             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
8700                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
8701             if (code == 0 && realDirFlag == 1 &&
8702                 (createDisp == FILE_OPEN ||
8703                  createDisp == FILE_OVERWRITE ||
8704                  createDisp == FILE_OVERWRITE_IF)) {
8705                 cm_ReleaseSCache(scp);
8706                 cm_ReleaseSCache(dscp);
8707                 cm_ReleaseUser(userp);
8708                 cm_FreeSpace(spacep);
8709                 free(realPathp);
8710                 if (baseFidp)
8711                     smb_ReleaseFID(baseFidp);
8712                 return CM_ERROR_EXISTS;
8713             }
8714         }
8715     } else {
8716         cm_ReleaseUser(userp);
8717         if (baseFidp)
8718             smb_ReleaseFID(baseFidp);
8719         cm_FreeSpace(spacep);
8720         free(realPathp);
8721         return CM_ERROR_NOSUCHPATH;
8722     }
8723
8724     if (code == 0)
8725         foundscp = TRUE;
8726
8727     if (code == CM_ERROR_NOSUCHFILE ||
8728         code == CM_ERROR_NOSUCHPATH ||
8729         code == CM_ERROR_BPLUS_NOMATCH ||
8730         (code == 0 && (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)))) {
8731         code = 0;
8732
8733         cm_FreeSpace(spacep);
8734
8735         if (baseFidp)
8736             smb_ReleaseFID(baseFidp);
8737
8738         if (code) {
8739             cm_ReleaseSCache(dscp);
8740             cm_ReleaseUser(userp);
8741             free(realPathp);
8742             return code;
8743         }
8744
8745         if (!lastNamep)
8746             lastNamep = realPathp;
8747         else
8748             lastNamep++;
8749
8750         if (!smb_IsLegalFilename(lastNamep)) {
8751             cm_ReleaseSCache(dscp);
8752             cm_ReleaseUser(userp);
8753             free(realPathp);
8754             return CM_ERROR_BADNTFILENAME;
8755         }
8756
8757         if (!foundscp) {
8758             if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF || createDisp == FILE_OPEN_IF) {
8759                 code = cm_Lookup(dscp, lastNamep,
8760                                   CM_FLAG_FOLLOW, userp, &req, &scp);
8761             } else {
8762                 code = cm_Lookup(dscp, lastNamep,
8763                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8764                                  userp, &req, &scp);
8765             }
8766             if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8767                 cm_ReleaseSCache(dscp);
8768                 cm_ReleaseUser(userp);
8769                 free(realPathp);
8770                 return code;
8771             }
8772         }
8773     } else {
8774         if (baseFidp)
8775             smb_ReleaseFID(baseFidp);
8776         cm_FreeSpace(spacep);
8777     }
8778
8779     /* open the file itself */
8780     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8781     osi_assertx(fidp, "null smb_fid_t");
8782
8783     /* save a reference to the user */
8784     cm_HoldUser(userp);
8785     fidp->userp = userp;
8786
8787     /* if we get here, if code is 0, the file exists and is represented by
8788      * scp.  Otherwise, we have to create it.  The dir may be represented
8789      * by dscp, or we may have found the file directly.  If code is non-zero,
8790      * scp is NULL.
8791      */
8792     if (code == 0) {
8793         code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
8794         if (code) {
8795             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8796             cm_ReleaseSCache(dscp);
8797             cm_ReleaseSCache(scp);
8798             cm_ReleaseUser(userp);
8799             smb_CloseFID(vcp, fidp, NULL, 0);
8800             smb_ReleaseFID(fidp);
8801             free(realPathp);
8802             return code;
8803         }
8804         checkDoneRequired = 1;
8805
8806         if (createDisp == FILE_CREATE) {
8807             /* oops, file shouldn't be there */
8808             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8809             cm_ReleaseSCache(dscp);
8810             cm_ReleaseSCache(scp);
8811             cm_ReleaseUser(userp);
8812             smb_CloseFID(vcp, fidp, NULL, 0);
8813             smb_ReleaseFID(fidp);
8814             free(realPathp);
8815             return CM_ERROR_EXISTS;
8816         }
8817
8818         if (createDisp == FILE_OVERWRITE ||
8819             createDisp == FILE_OVERWRITE_IF) {
8820             setAttr.mask = CM_ATTRMASK_LENGTH;
8821             setAttr.length.LowPart = 0;
8822             setAttr.length.HighPart = 0;
8823
8824             /* now watch for a symlink */
8825             code = 0;
8826             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8827                 targetScp = 0;
8828                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8829                 if (code == 0) {
8830                     /* we have a more accurate file to use (the
8831                     * target of the symbolic link).  Otherwise,
8832                     * we'll just use the symlink anyway.
8833                     */
8834                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
8835                               scp, targetScp);
8836                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8837                     cm_ReleaseSCache(scp);
8838                     scp = targetScp;
8839                     code = cm_CheckNTOpen(scp, desiredAccess, shareAccess, createDisp, 0, fidp->fid, userp, &req, &ldp);
8840                     if (code) {
8841                         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8842                         cm_ReleaseSCache(dscp);
8843                         if (scp)
8844                             cm_ReleaseSCache(scp);
8845                         cm_ReleaseUser(userp);
8846                         smb_CloseFID(vcp, fidp, NULL, 0);
8847                         smb_ReleaseFID(fidp);
8848                         free(realPathp);
8849                         return code;
8850                     }
8851                 }
8852             }
8853             code = cm_SetAttr(scp, &setAttr, userp, &req);
8854             openAction = 3;     /* truncated existing file */
8855         }
8856         else openAction = 1;    /* found existing file */
8857     }
8858     else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8859         /* don't create if not found */
8860         cm_ReleaseSCache(dscp);
8861         cm_ReleaseUser(userp);
8862         smb_CloseFID(vcp, fidp, NULL, 0);
8863         smb_ReleaseFID(fidp);
8864         free(realPathp);
8865         return CM_ERROR_NOSUCHFILE;
8866     }
8867     else if (realDirFlag == 0 || realDirFlag == -1) {
8868         /* createDisp: FILE_SUPERSEDE, FILE_CREATE, FILE_OPEN_IF, FILE_OVERWRITE_IF */
8869         osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8870                   osi_LogSaveClientString(smb_logp, lastNamep));
8871         openAction = 2;         /* created file */
8872         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8873         setAttr.clientModTime = time(NULL);
8874         smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
8875
8876         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8877                           &req);
8878         if (code == 0) {
8879             created = 1;
8880             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8881                 smb_NotifyChange(FILE_ACTION_ADDED,
8882                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8883                                  dscp, lastNamep, NULL, TRUE);
8884         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8885             /* Not an exclusive create, and someone else tried
8886              * creating it already, then we open it anyway.  We
8887              * don't bother retrying after this, since if this next
8888              * fails, that means that the file was deleted after we
8889              * started this call.
8890              */
8891             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8892                               userp, &req, &scp);
8893             if (code == 0) {
8894                 if (createDisp == FILE_OVERWRITE_IF) {
8895                     setAttr.mask = CM_ATTRMASK_LENGTH;
8896                     setAttr.length.LowPart = 0;
8897                     setAttr.length.HighPart = 0;
8898
8899                     /* now watch for a symlink */
8900                     code = 0;
8901                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8902                         targetScp = 0;
8903                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8904                         if (code == 0) {
8905                             /* we have a more accurate file to use (the
8906                             * target of the symbolic link).  Otherwise,
8907                             * we'll just use the symlink anyway.
8908                             */
8909                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
8910                                       scp, targetScp);
8911                             cm_ReleaseSCache(scp);
8912                             scp = targetScp;
8913                         }
8914                     }
8915                     code = cm_SetAttr(scp, &setAttr, userp, &req);
8916                 }
8917             }   /* lookup succeeded */
8918         }
8919     } else {
8920         /* create directory; createDisp: FILE_CREATE, FILE_OPEN_IF */
8921         osi_Log1(smb_logp,
8922                   "smb_ReceiveNTTranCreate creating directory %S",
8923                   osi_LogSaveClientString(smb_logp, lastNamep));
8924         openAction = 2;         /* created directory */
8925         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8926         setAttr.clientModTime = time(NULL);
8927         smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
8928
8929         code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8930         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8931             smb_NotifyChange(FILE_ACTION_ADDED,
8932                               FILE_NOTIFY_CHANGE_DIR_NAME,
8933                               dscp, lastNamep, NULL, TRUE);
8934         if (code == 0 ||
8935             (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8936             /* Not an exclusive create, and someone else tried
8937              * creating it already, then we open it anyway.  We
8938              * don't bother retrying after this, since if this next
8939              * fails, that means that the file was deleted after we
8940              * started this call.
8941              */
8942             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8943                               userp, &req, &scp);
8944         }
8945     }
8946
8947     if (code) {
8948         /* something went wrong creating or truncating the file */
8949         if (checkDoneRequired)
8950             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8951         if (scp)
8952             cm_ReleaseSCache(scp);
8953         cm_ReleaseUser(userp);
8954         smb_CloseFID(vcp, fidp, NULL, 0);
8955         smb_ReleaseFID(fidp);
8956         free(realPathp);
8957         return code;
8958     }
8959
8960     /* make sure we have file vs. dir right */
8961     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8962         /* now watch for a symlink */
8963         code = 0;
8964         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8965             targetScp = 0;
8966             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8967             if (code == 0) {
8968                 /* we have a more accurate file to use (the
8969                 * target of the symbolic link).  Otherwise,
8970                 * we'll just use the symlink anyway.
8971                 */
8972                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8973                           scp, targetScp);
8974                 if (checkDoneRequired) {
8975                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8976                     checkDoneRequired = 0;
8977                 }
8978                 cm_ReleaseSCache(scp);
8979                 scp = targetScp;
8980             }
8981         }
8982
8983         if (scp->fileType != CM_SCACHETYPE_FILE) {
8984             if (checkDoneRequired)
8985                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8986             cm_ReleaseSCache(scp);
8987             cm_ReleaseUser(userp);
8988             smb_CloseFID(vcp, fidp, NULL, 0);
8989             smb_ReleaseFID(fidp);
8990             free(realPathp);
8991             return CM_ERROR_ISDIR;
8992         }
8993     }
8994
8995     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8996         if (checkDoneRequired)
8997             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8998         cm_ReleaseSCache(scp);
8999         cm_ReleaseUser(userp);
9000         smb_CloseFID(vcp, fidp, NULL, 0);
9001         smb_ReleaseFID(fidp);
9002         free(realPathp);
9003         return CM_ERROR_NOTDIR;
9004     }
9005
9006     /* If we are restricting sharing, we should do so with a suitable
9007        share lock. */
9008     if (scp->fileType == CM_SCACHETYPE_FILE &&
9009         !(fidflags & SMB_FID_SHARE_WRITE)) {
9010         cm_key_t key;
9011         LARGE_INTEGER LOffset, LLength;
9012         int sLockType;
9013
9014         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
9015         LOffset.LowPart = SMB_FID_QLOCK_LOW;
9016         LLength.HighPart = 0;
9017         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
9018
9019         /* Similar to what we do in handling NTCreateX.  We get a
9020            shared lock if we are only opening the file for reading. */
9021         if ((fidflags & SMB_FID_SHARE_READ) ||
9022             !(fidflags & SMB_FID_OPENWRITE)) {
9023             sLockType = LOCKING_ANDX_SHARED_LOCK;
9024         } else {
9025             sLockType = 0;
9026         }
9027
9028         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
9029
9030         lock_ObtainWrite(&scp->rw);
9031         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
9032         lock_ReleaseWrite(&scp->rw);
9033
9034         if (code) {
9035             if (checkDoneRequired)
9036                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
9037             cm_ReleaseSCache(scp);
9038             cm_ReleaseUser(userp);
9039             /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
9040             smb_CloseFID(vcp, fidp, NULL, 0);
9041             smb_ReleaseFID(fidp);
9042             free(realPathp);
9043             return CM_ERROR_SHARING_VIOLATION;
9044         }
9045     }
9046
9047     /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
9048     if (checkDoneRequired) {
9049         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
9050         checkDoneRequired = 0;
9051     }
9052
9053     lock_ObtainMutex(&fidp->mx);
9054     /* save a pointer to the vnode */
9055     fidp->scp = scp;
9056     lock_ObtainWrite(&scp->rw);
9057     scp->flags |= CM_SCACHEFLAG_SMB_FID;
9058     lock_ReleaseWrite(&scp->rw);
9059     osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
9060
9061     fidp->flags = fidflags;
9062
9063     /* remember if the file was newly created */
9064     if (created)
9065         fidp->flags |= SMB_FID_CREATED;
9066
9067     /* save parent dir and pathname for deletion or change notification */
9068     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
9069         fidp->flags |= SMB_FID_NTOPEN;
9070         fidp->NTopen_dscp = dscp;
9071         osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
9072         dscp = NULL;
9073         fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
9074     }
9075     fidp->NTopen_wholepathp = realPathp;
9076     lock_ReleaseMutex(&fidp->mx);
9077
9078     /* we don't need this any longer */
9079     if (dscp)
9080         cm_ReleaseSCache(dscp);
9081
9082     cm_Open(scp, 0, userp);
9083
9084     /* set inp->fid so that later read calls in same msg can find fid */
9085     inp->fid = fidp->fid;
9086
9087     /* check whether we are required to send an extended response */
9088     if (!extendedRespRequired) {
9089         /* out parms */
9090         parmOffset = 8*4 + 39;
9091         parmOffset += 1;        /* pad to 4 */
9092         dataOffset = parmOffset + 70;
9093
9094         parmSlot = 1;
9095         outp->oddByte = 1;
9096         /* Total Parameter Count */
9097         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
9098         /* Total Data Count */
9099         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9100         /* Parameter Count */
9101         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
9102         /* Parameter Offset */
9103         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
9104         /* Parameter Displacement */
9105         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9106         /* Data Count */
9107         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9108         /* Data Offset */
9109         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
9110         /* Data Displacement */
9111         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9112         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
9113         smb_SetSMBDataLength(outp, 70);
9114
9115         lock_ObtainRead(&scp->rw);
9116         outData = smb_GetSMBData(outp, NULL);
9117         outData++;                      /* round to get to parmOffset */
9118         *outData = 0; outData++;        /* oplock */
9119         *outData = 0; outData++;        /* reserved */
9120         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
9121         *((ULONG *)outData) = openAction; outData += 4;
9122         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
9123         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
9124         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
9125         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
9126         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
9127         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
9128         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
9129         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
9130         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
9131         *((USHORT *)outData) = 0; outData += 2; /* filetype */
9132         *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
9133         outData += 2;   /* dev state */
9134         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
9135                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
9136                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
9137         outData += 2;   /* is a dir? */
9138     } else {
9139         /* out parms */
9140         parmOffset = 8*4 + 39;
9141         parmOffset += 1;        /* pad to 4 */
9142         dataOffset = parmOffset + 104;
9143
9144         parmSlot = 1;
9145         outp->oddByte = 1;
9146         /* Total Parameter Count */
9147         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
9148         /* Total Data Count */
9149         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9150         /* Parameter Count */
9151         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
9152         /* Parameter Offset */
9153         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
9154         /* Parameter Displacement */
9155         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9156         /* Data Count */
9157         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9158         /* Data Offset */
9159         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
9160         /* Data Displacement */
9161         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9162         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
9163         smb_SetSMBDataLength(outp, 105);
9164
9165         lock_ObtainRead(&scp->rw);
9166         outData = smb_GetSMBData(outp, NULL);
9167         outData++;                      /* round to get to parmOffset */
9168         *outData = 0; outData++;        /* oplock */
9169         *outData = 1; outData++;        /* response type */
9170         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
9171         *((ULONG *)outData) = openAction; outData += 4;
9172         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
9173         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
9174         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
9175         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
9176         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
9177         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
9178         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
9179         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
9180         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
9181         *((USHORT *)outData) = 0; outData += 2; /* filetype */
9182         *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
9183         outData += 2;   /* dev state */
9184         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
9185                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
9186                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
9187         outData += 1;   /* is a dir? */
9188         /* Setting the GUID results in failures with cygwin */
9189         memset(outData,0,24); outData += 24; /* GUID */
9190         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
9191         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
9192     }
9193
9194     if ((fidp->flags & SMB_FID_EXECUTABLE) &&
9195          LargeIntegerGreaterThanZero(scp->length) &&
9196          !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
9197         prefetch = 1;
9198     }
9199     lock_ReleaseRead(&scp->rw);
9200
9201     if (prefetch) {
9202         rock_BkgFetch_t *rockp = malloc(sizeof(*rockp));
9203
9204         if (rockp) {
9205             rockp->base.LowPart = 0;
9206             rockp->base.HighPart = 0;
9207             rockp->length = scp->length;
9208
9209             cm_QueueBKGRequest(scp, cm_BkgPrefetch, rockp, userp, &req);
9210
9211             /* rock is freed by cm_BkgDaemon */
9212         }
9213     }
9214
9215     osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
9216
9217     cm_ReleaseUser(userp);
9218     smb_ReleaseFID(fidp);
9219
9220     /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
9221     /* leave scp held since we put it in fidp->scp */
9222     return 0;
9223 }
9224
9225 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
9226 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
9227         smb_packet_t *outp)
9228 {
9229     smb_packet_t *savedPacketp;
9230     ULONG filter;
9231     USHORT fid, watchtree;
9232     smb_fid_t *fidp;
9233     cm_scache_t *scp;
9234
9235     filter = smb_GetSMBParm(inp, 19) |
9236              (smb_GetSMBParm(inp, 20) << 16);
9237     fid = smb_GetSMBParm(inp, 21);
9238     watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
9239
9240     fidp = smb_FindFID(vcp, fid, 0);
9241     if (!fidp) {
9242         osi_Log2(smb_logp, "NotifyChange Unknown SMB Fid vcp 0x%p fid %d",
9243                  vcp, fid);
9244         return CM_ERROR_BADFD;
9245     }
9246
9247     lock_ObtainMutex(&fidp->mx);
9248     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
9249         lock_ReleaseMutex(&fidp->mx);
9250         smb_CloseFID(vcp, fidp, NULL, 0);
9251         smb_ReleaseFID(fidp);
9252         return CM_ERROR_NOSUCHFILE;
9253     }
9254     scp = fidp->scp;
9255     cm_HoldSCache(scp);
9256     lock_ReleaseMutex(&fidp->mx);
9257
9258     /* Create a copy of the Directory Watch Packet to use when sending the
9259      * notification if in the future a matching change is detected.
9260      */
9261     savedPacketp = smb_CopyPacket(inp);
9262     if (vcp != savedPacketp->vcp) {
9263         smb_HoldVC(vcp);
9264         if (savedPacketp->vcp)
9265             smb_ReleaseVC(savedPacketp->vcp);
9266         savedPacketp->vcp = vcp;
9267     }
9268
9269     /* Add the watch to the list of events to send notifications for */
9270     lock_ObtainMutex(&smb_Dir_Watch_Lock);
9271     savedPacketp->nextp = smb_Directory_Watches;
9272     smb_Directory_Watches = savedPacketp;
9273     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9274
9275     osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
9276               fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
9277     osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
9278              filter, fid, watchtree);
9279     if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9280         osi_Log0(smb_logp, "      Notify Change File Name");
9281     if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9282         osi_Log0(smb_logp, "      Notify Change Directory Name");
9283     if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9284         osi_Log0(smb_logp, "      Notify Change Attributes");
9285     if (filter & FILE_NOTIFY_CHANGE_SIZE)
9286         osi_Log0(smb_logp, "      Notify Change Size");
9287     if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9288         osi_Log0(smb_logp, "      Notify Change Last Write");
9289     if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9290         osi_Log0(smb_logp, "      Notify Change Last Access");
9291     if (filter & FILE_NOTIFY_CHANGE_CREATION)
9292         osi_Log0(smb_logp, "      Notify Change Creation");
9293     if (filter & FILE_NOTIFY_CHANGE_EA)
9294         osi_Log0(smb_logp, "      Notify Change Extended Attributes");
9295     if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9296         osi_Log0(smb_logp, "      Notify Change Security");
9297     if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9298         osi_Log0(smb_logp, "      Notify Change Stream Name");
9299     if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9300         osi_Log0(smb_logp, "      Notify Change Stream Size");
9301     if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9302         osi_Log0(smb_logp, "      Notify Change Stream Write");
9303
9304     lock_ObtainWrite(&scp->rw);
9305     if (watchtree)
9306         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
9307     else
9308         scp->flags |= CM_SCACHEFLAG_WATCHED;
9309     lock_ReleaseWrite(&scp->rw);
9310     cm_ReleaseSCache(scp);
9311     smb_ReleaseFID(fidp);
9312
9313     outp->flags |= SMB_PACKETFLAG_NOSEND;
9314     return 0;
9315 }
9316
9317 unsigned char nullSecurityDesc[] = {
9318     0x01,                               /* security descriptor revision */
9319     0x00,                               /* reserved, should be zero */
9320     0x04, 0x80,                         /* security descriptor control;
9321                                          * 0x0004 : null-DACL present - everyone has full access
9322                                          * 0x8000 : relative format */
9323     0x14, 0x00, 0x00, 0x00,             /* offset of owner SID */
9324     0x20, 0x00, 0x00, 0x00,             /* offset of group SID */
9325     0x00, 0x00, 0x00, 0x00,             /* offset of DACL would go here */
9326     0x00, 0x00, 0x00, 0x00,             /* offset of SACL would go here */
9327     0x01, 0x01, 0x00, 0x00,             /* "everyone SID" owner SID */
9328     0x00, 0x00, 0x00, 0x01,
9329     0x00, 0x00, 0x00, 0x00,
9330     0x01, 0x01, 0x00, 0x00,             /* "everyone SID" owner SID */
9331     0x00, 0x00, 0x00, 0x01,
9332     0x00, 0x00, 0x00, 0x00
9333 };
9334
9335 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
9336 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9337 {
9338     int parmOffset, parmCount, dataOffset, dataCount;
9339     int totalParmCount, totalDataCount;
9340     int parmSlot;
9341     int maxData, maxParm;
9342     int inTotalParm, inTotalData;
9343     int inParm, inData;
9344     int inParmOffset, inDataOffset;
9345     char *outData;
9346     char *parmp;
9347     USHORT *sparmp;
9348     ULONG *lparmp;
9349     USHORT fid;
9350     ULONG securityInformation;
9351     smb_fid_t *fidp;
9352     long code = 0;
9353     DWORD dwLength;
9354
9355     /*
9356      * For details on the meanings of the various
9357      * SMB_COM_TRANSACTION fields, see sections 2.2.4.33
9358      * of http://msdn.microsoft.com/en-us/library/ee442092%28PROT.13%29.aspx
9359      */
9360
9361     inTotalParm = smb_GetSMBOffsetParm(inp, 1, 1)
9362         | (smb_GetSMBOffsetParm(inp, 2, 1) << 16);
9363
9364     inTotalData = smb_GetSMBOffsetParm(inp, 3, 1)
9365         | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
9366
9367     maxParm = smb_GetSMBOffsetParm(inp, 5, 1)
9368         | (smb_GetSMBOffsetParm(inp, 6, 1) << 16);
9369
9370     maxData = smb_GetSMBOffsetParm(inp, 7, 1)
9371         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
9372
9373     inParm = smb_GetSMBOffsetParm(inp, 9, 1)
9374         | (smb_GetSMBOffsetParm(inp, 10, 1) << 16);
9375
9376     inParmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
9377         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
9378
9379     inData = smb_GetSMBOffsetParm(inp, 13, 1)
9380         | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
9381
9382     inDataOffset = smb_GetSMBOffsetParm(inp, 15, 1)
9383         | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
9384
9385     parmp = inp->data + inParmOffset;
9386     sparmp = (USHORT *) parmp;
9387     lparmp = (ULONG *) parmp;
9388
9389     fid = sparmp[0];
9390     securityInformation = lparmp[1];
9391
9392     fidp = smb_FindFID(vcp, fid, 0);
9393     if (!fidp) {
9394         osi_Log2(smb_logp, "smb_ReceiveNTTranQuerySecurityDesc Unknown SMB Fid vcp 0x%p fid %d",
9395                  vcp, fid);
9396         return CM_ERROR_BADFD;
9397     }
9398
9399     lock_ObtainMutex(&fidp->mx);
9400     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
9401         lock_ReleaseMutex(&fidp->mx);
9402         smb_CloseFID(vcp, fidp, NULL, 0);
9403         smb_ReleaseFID(fidp);
9404         return CM_ERROR_NOSUCHFILE;
9405     }
9406     lock_ReleaseMutex(&fidp->mx);
9407
9408     osi_Log4(smb_logp,"smb_ReceiveNTTranQuerySecurityDesc fidp 0x%p scp 0x%p file \"%S\" Info=0x%x",
9409               fidp, fidp->scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp),
9410               securityInformation);
9411
9412     smb_ReleaseFID(fidp);
9413
9414     if ( securityInformation & ~(OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION) )
9415     {
9416         code = CM_ERROR_BAD_LEVEL;
9417         goto done;
9418     }
9419
9420     dwLength = sizeof( nullSecurityDesc);
9421
9422     totalDataCount = dwLength;
9423     totalParmCount = 4;
9424
9425     if (maxData >= totalDataCount) {
9426         dataCount = totalDataCount;
9427         parmCount = min(totalParmCount, maxParm);
9428     } else if (maxParm >= totalParmCount) {
9429         totalDataCount = dataCount = 0;
9430         parmCount = totalParmCount;
9431     } else {
9432         totalDataCount = dataCount = 0;
9433         totalParmCount = parmCount = 0;
9434     }
9435
9436     /* out parms */
9437     parmOffset = 8*4 + 39;
9438     parmOffset += 1;    /* pad to 4 */
9439
9440     dataOffset = parmOffset + parmCount;
9441
9442     parmSlot = 1;
9443     outp->oddByte = 1;
9444     /* Total Parameter Count */
9445     smb_SetSMBParmLong(outp, parmSlot, totalParmCount); parmSlot += 2;
9446     /* Total Data Count */
9447     smb_SetSMBParmLong(outp, parmSlot, totalDataCount); parmSlot += 2;
9448     /* Parameter Count */
9449     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
9450     /* Parameter Offset */
9451     smb_SetSMBParmLong(outp, parmSlot, parmCount ? parmOffset : 0); parmSlot += 2;
9452     /* Parameter Displacement */
9453     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9454     /* Data Count */
9455     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
9456     /* Data Offset */
9457     smb_SetSMBParmLong(outp, parmSlot, dataCount ? dataOffset : 0); parmSlot += 2;
9458     /* Data Displacement */
9459     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9460     /* Setup Count */
9461     smb_SetSMBParmByte(outp, parmSlot, 0);
9462
9463     if (parmCount == totalParmCount && dwLength == dataCount) {
9464         smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
9465
9466         /* Data */
9467         outData = smb_GetSMBData(outp, NULL);
9468         outData++;                      /* round to get to dataOffset */
9469
9470         *((ULONG *)outData) = dataCount; outData += 4;  /* SD Length (4 bytes) */
9471         memcpy(outData, nullSecurityDesc, dataCount);
9472         outData += dataCount;
9473
9474         code = 0;
9475     } else if (parmCount >= 4) {
9476         smb_SetSMBDataLength(outp, 1 + parmCount);
9477
9478         /* Data */
9479         outData = smb_GetSMBData(outp, NULL);
9480         outData++;                      /* round to get to dataOffset */
9481
9482         *((ULONG *)outData) = dwLength; outData += 4;   /* SD Length (4 bytes) */
9483         code = CM_ERROR_BUFFERTOOSMALL;
9484     } else {
9485         smb_SetSMBDataLength(outp, 0);
9486         code = CM_ERROR_BUFFER_OVERFLOW;
9487     }
9488
9489   done:
9490     return code;
9491 }
9492
9493 /* SMB_COM_NT_TRANSACT
9494
9495    SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
9496  */
9497 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9498 {
9499     unsigned short function;
9500
9501     function = smb_GetSMBParm(inp, 18);
9502
9503     osi_Log1(smb_logp, "SMB NT Transact function %d", function);
9504
9505     /* We can handle long names */
9506     if (vcp->flags & SMB_VCFLAG_USENT)
9507         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
9508
9509     switch (function) {
9510     case 1:                     /* NT_TRANSACT_CREATE */
9511         return smb_ReceiveNTTranCreate(vcp, inp, outp);
9512     case 2:                     /* NT_TRANSACT_IOCTL */
9513         osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
9514         break;
9515     case 3:                     /* NT_TRANSACT_SET_SECURITY_DESC */
9516         osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
9517         break;
9518     case 4:                     /* NT_TRANSACT_NOTIFY_CHANGE */
9519         return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
9520     case 5:                     /* NT_TRANSACT_RENAME */
9521         osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
9522         break;
9523     case 6:                     /* NT_TRANSACT_QUERY_SECURITY_DESC */
9524         return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
9525     case 7:
9526         osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
9527         break;
9528     case 8:
9529         osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
9530         break;
9531     }
9532     return CM_ERROR_BADOP;
9533 }
9534
9535 /*
9536  * smb_NotifyChange -- find relevant change notification messages and
9537  *                     reply to them
9538  *
9539  * If we don't know the file name (i.e. a callback break), filename is
9540  * NULL, and we return a zero-length list.
9541  *
9542  * At present there is not a single call to smb_NotifyChange that
9543  * has the isDirectParent parameter set to FALSE.
9544  */
9545 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
9546         cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
9547         BOOL isDirectParent)
9548 {
9549     smb_packet_t *watch, *lastWatch, *nextWatch;
9550     ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
9551     char *outData, *oldOutData;
9552     ULONG filter;
9553     USHORT fid, wtree;
9554     ULONG maxLen;
9555     BOOL twoEntries = FALSE;
9556     ULONG otherNameLen, oldParmCount = 0;
9557     DWORD otherAction;
9558     smb_fid_t *fidp;
9559
9560     /* Get ready for rename within directory */
9561     if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
9562         twoEntries = TRUE;
9563         otherAction = FILE_ACTION_RENAMED_NEW_NAME;
9564     }
9565
9566     osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
9567              osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
9568     if (action == 0)
9569         osi_Log0(smb_logp,"      FILE_ACTION_NONE");
9570     if (action == FILE_ACTION_ADDED)
9571         osi_Log0(smb_logp,"      FILE_ACTION_ADDED");
9572     if (action == FILE_ACTION_REMOVED)
9573         osi_Log0(smb_logp,"      FILE_ACTION_REMOVED");
9574     if (action == FILE_ACTION_MODIFIED)
9575         osi_Log0(smb_logp,"      FILE_ACTION_MODIFIED");
9576     if (action == FILE_ACTION_RENAMED_OLD_NAME)
9577         osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_OLD_NAME");
9578     if (action == FILE_ACTION_RENAMED_NEW_NAME)
9579         osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_NEW_NAME");
9580
9581     lock_ObtainMutex(&smb_Dir_Watch_Lock);
9582     watch = smb_Directory_Watches;
9583     while (watch) {
9584         filter = smb_GetSMBParm(watch, 19)
9585             | (smb_GetSMBParm(watch, 20) << 16);
9586         fid = smb_GetSMBParm(watch, 21);
9587         wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
9588
9589         maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
9590             | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
9591
9592         /*
9593          * Strange hack - bug in NT Client and NT Server that we must emulate?
9594          */
9595         if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
9596             filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
9597
9598         fidp = smb_FindFID(watch->vcp, fid, 0);
9599         if (!fidp) {
9600             osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
9601             lastWatch = watch;
9602             watch = watch->nextp;
9603             continue;
9604         }
9605
9606         if (fidp->scp != dscp ||
9607             fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
9608             (filter & notifyFilter) == 0 ||
9609             (!isDirectParent && !wtree))
9610         {
9611             osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
9612             lastWatch = watch;
9613             watch = watch->nextp;
9614             smb_ReleaseFID(fidp);
9615             continue;
9616         }
9617
9618         osi_Log4(smb_logp,
9619                   "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
9620                   fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
9621         if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9622             osi_Log0(smb_logp, "      Notify Change File Name");
9623         if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9624             osi_Log0(smb_logp, "      Notify Change Directory Name");
9625         if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9626             osi_Log0(smb_logp, "      Notify Change Attributes");
9627         if (filter & FILE_NOTIFY_CHANGE_SIZE)
9628             osi_Log0(smb_logp, "      Notify Change Size");
9629         if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9630             osi_Log0(smb_logp, "      Notify Change Last Write");
9631         if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9632             osi_Log0(smb_logp, "      Notify Change Last Access");
9633         if (filter & FILE_NOTIFY_CHANGE_CREATION)
9634             osi_Log0(smb_logp, "      Notify Change Creation");
9635         if (filter & FILE_NOTIFY_CHANGE_EA)
9636             osi_Log0(smb_logp, "      Notify Change Extended Attributes");
9637         if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9638             osi_Log0(smb_logp, "      Notify Change Security");
9639         if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9640             osi_Log0(smb_logp, "      Notify Change Stream Name");
9641         if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9642             osi_Log0(smb_logp, "      Notify Change Stream Size");
9643         if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9644             osi_Log0(smb_logp, "      Notify Change Stream Write");
9645
9646         /* A watch can only be notified once.  Remove it from the list */
9647         nextWatch = watch->nextp;
9648         if (watch == smb_Directory_Watches)
9649             smb_Directory_Watches = nextWatch;
9650         else
9651             lastWatch->nextp = nextWatch;
9652
9653         /* Turn off WATCHED flag in dscp */
9654         lock_ObtainWrite(&dscp->rw);
9655         if (wtree)
9656             dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9657         else
9658             dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
9659         lock_ReleaseWrite(&dscp->rw);
9660
9661         /* Convert to response packet */
9662         ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
9663 #ifdef SEND_CANONICAL_PATHNAMES
9664         ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
9665 #endif
9666         ((smb_t *) watch)->wct = 0;
9667
9668         /* out parms */
9669         if (filename == NULL) {
9670             parmCount = 0;
9671         } else {
9672             nameLen = (ULONG)cm_ClientStrLen(filename);
9673             parmCount = 3*4 + nameLen*2;
9674             parmCount = (parmCount + 3) & ~3;   /* pad to 4 */
9675             if (twoEntries) {
9676                 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
9677                 oldParmCount = parmCount;
9678                 parmCount += 3*4 + otherNameLen*2;
9679                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9680             }
9681             if (maxLen < parmCount)
9682                 parmCount = 0;  /* not enough room */
9683         }
9684         parmOffset = 8*4 + 39;
9685         parmOffset += 1;                        /* pad to 4 */
9686         dataOffset = parmOffset + parmCount;
9687
9688         parmSlot = 1;
9689         watch->oddByte = 1;
9690         /* Total Parameter Count */
9691         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9692         /* Total Data Count */
9693         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9694         /* Parameter Count */
9695         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9696         /* Parameter Offset */
9697         smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
9698         /* Parameter Displacement */
9699         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9700         /* Data Count */
9701         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9702         /* Data Offset */
9703         smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
9704         /* Data Displacement */
9705         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9706         smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
9707         smb_SetSMBDataLength(watch, parmCount + 1);
9708
9709         if (parmCount != 0) {
9710             outData = smb_GetSMBData(watch, NULL);
9711             outData++;  /* round to get to parmOffset */
9712             oldOutData = outData;
9713             *((DWORD *)outData) = oldParmCount; outData += 4;
9714             /* Next Entry Offset */
9715             *((DWORD *)outData) = action; outData += 4;
9716             /* Action */
9717             *((DWORD *)outData) = nameLen*2; outData += 4;
9718             /* File Name Length */
9719
9720             smb_UnparseString(watch, outData, filename, NULL, 0);
9721             /* File Name */
9722
9723             if (twoEntries) {
9724                 outData = oldOutData + oldParmCount;
9725                 *((DWORD *)outData) = 0; outData += 4;
9726                 /* Next Entry Offset */
9727                 *((DWORD *)outData) = otherAction; outData += 4;
9728                 /* Action */
9729                 *((DWORD *)outData) = otherNameLen*2;
9730                 outData += 4;   /* File Name Length */
9731                 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
9732             }
9733         }
9734
9735         /*
9736          * If filename is null, we don't know the cause of the
9737          * change notification.  We return zero data (see above),
9738          * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
9739          * (= 0x010C).  We set the error code here by hand, without
9740          * modifying wct and bcc.
9741          */
9742         if (filename == NULL) {
9743             ((smb_t *) watch)->rcls = 0x0C;
9744             ((smb_t *) watch)->reh = 0x01;
9745             ((smb_t *) watch)->errLow = 0;
9746             ((smb_t *) watch)->errHigh = 0;
9747             /* Set NT Status codes flag */
9748             ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9749         }
9750
9751         smb_SendPacket(watch->vcp, watch);
9752         smb_FreePacket(watch);
9753
9754         smb_ReleaseFID(fidp);
9755         watch = nextWatch;
9756     }
9757     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9758 }
9759
9760 /* SMB_COM_NT_CANCEL */
9761 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9762 {
9763     unsigned char *replyWctp;
9764     smb_packet_t *watch, *lastWatch;
9765     USHORT fid, watchtree;
9766     smb_fid_t *fidp;
9767     cm_scache_t *scp;
9768
9769     osi_Log0(smb_logp, "SMB3 receive NT cancel");
9770
9771     lock_ObtainMutex(&smb_Dir_Watch_Lock);
9772     watch = smb_Directory_Watches;
9773     while (watch) {
9774         if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
9775              && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
9776              && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
9777              && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
9778             if (watch == smb_Directory_Watches)
9779                 smb_Directory_Watches = watch->nextp;
9780             else
9781                 lastWatch->nextp = watch->nextp;
9782             lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9783
9784             /* Turn off WATCHED flag in scp */
9785             fid = smb_GetSMBParm(watch, 21);
9786             watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
9787
9788             if (vcp != watch->vcp)
9789                 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
9790                           vcp, watch->vcp);
9791
9792             fidp = smb_FindFID(vcp, fid, 0);
9793             if (fidp) {
9794                 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
9795                          fid, watchtree,
9796                          (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
9797
9798                 scp = fidp->scp;
9799                 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
9800                 if (scp) {
9801                     lock_ObtainWrite(&scp->rw);
9802                     if (watchtree)
9803                         scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9804                     else
9805                         scp->flags &= ~CM_SCACHEFLAG_WATCHED;
9806                     lock_ReleaseWrite(&scp->rw);
9807                 }
9808                 smb_ReleaseFID(fidp);
9809             } else {
9810                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
9811             }
9812
9813             /* assume STATUS32; return 0xC0000120 (CANCELED) */
9814             replyWctp = watch->wctp;
9815             *replyWctp++ = 0;
9816             *replyWctp++ = 0;
9817             *replyWctp++ = 0;
9818             ((smb_t *)watch)->rcls = 0x20;
9819             ((smb_t *)watch)->reh = 0x1;
9820             ((smb_t *)watch)->errLow = 0;
9821             ((smb_t *)watch)->errHigh = 0xC0;
9822             ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9823             smb_SendPacket(vcp, watch);
9824             smb_FreePacket(watch);
9825             return 0;
9826         }
9827         lastWatch = watch;
9828         watch = watch->nextp;
9829     }
9830     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9831
9832     return 0;
9833 }
9834
9835 /*
9836  * NT rename also does hard links.
9837  */
9838
9839 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
9840 #define RENAME_FLAG_HARD_LINK                0x103
9841 #define RENAME_FLAG_RENAME                   0x104
9842 #define RENAME_FLAG_COPY                     0x105
9843
9844 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9845 {
9846     clientchar_t *oldPathp, *newPathp;
9847     long code = 0;
9848     char * tp;
9849     int attrs;
9850     int rename_type;
9851
9852     attrs = smb_GetSMBParm(inp, 0);
9853     rename_type = smb_GetSMBParm(inp, 1);
9854
9855     if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
9856         osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
9857         return CM_ERROR_NOACCESS;
9858     }
9859
9860     tp = smb_GetSMBData(inp, NULL);
9861     oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9862     if (!oldPathp)
9863         return CM_ERROR_BADSMB;
9864     newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9865     if (!newPathp)
9866         return CM_ERROR_BADSMB;
9867
9868     osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
9869              osi_LogSaveClientString(smb_logp, oldPathp),
9870              osi_LogSaveClientString(smb_logp, newPathp),
9871              ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
9872
9873     if (rename_type == RENAME_FLAG_RENAME) {
9874         code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
9875     } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
9876         code = smb_Link(vcp,inp,oldPathp,newPathp);
9877     } else
9878         code = CM_ERROR_BADOP;
9879     return code;
9880 }
9881
9882 void smb3_Init()
9883 {
9884     lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
9885 }
9886
9887 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9888 {
9889     smb_username_t *unp;
9890     cm_user_t *     userp;
9891
9892     unp = smb_FindUserByName(usern, machine, flags);
9893     if (!unp->userp) {
9894         lock_ObtainMutex(&unp->mx);
9895         unp->userp = cm_NewUser();
9896         lock_ReleaseMutex(&unp->mx);
9897         osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9898     }  else     {
9899         osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9900     }
9901     userp = unp->userp;
9902     cm_HoldUser(userp);
9903     smb_ReleaseUsername(unp);
9904     return userp;
9905 }
9906
9907 cm_user_t *smb_FindCMUserBySID(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9908 {
9909     smb_username_t *unp;
9910     cm_user_t *     userp;
9911
9912     unp = smb_FindUserByName(usern, machine, flags);
9913     if (!unp->userp) {
9914         lock_ObtainMutex(&unp->mx);
9915         unp->flags |= SMB_USERNAMEFLAG_SID;
9916         unp->userp = cm_NewUser();
9917         lock_ReleaseMutex(&unp->mx);
9918         osi_Log2(smb_logp,"smb_FindCMUserBySID New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9919     }  else     {
9920         osi_Log2(smb_logp,"smb_FindCMUserBySID Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9921     }
9922     userp = unp->userp;
9923     cm_HoldUser(userp);
9924     smb_ReleaseUsername(unp);
9925     return userp;
9926 }