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