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