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