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