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