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