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