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