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