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