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