DEVEL15-windows-delete-test-file-not-dir-20070131
[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;
3296     cm_scache_t *scp;
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, 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, 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         
3658     for(patchp = *dirPatchespp; patchp; patchp =
3659          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3660                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3661         if (code) continue;
3662         lock_ObtainMutex(&scp->mx);
3663         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3664                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3665         if (code) { 
3666             lock_ReleaseMutex(&scp->mx);
3667             cm_ReleaseSCache(scp);
3668
3669             dptr = patchp->dptr;
3670
3671             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3672                errors in the client. */
3673             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3674                 /* 1969-12-31 23:59:59 +00 */
3675                 ft.dwHighDateTime = 0x19DB200;
3676                 ft.dwLowDateTime = 0x5BB78980;
3677
3678                 /* copy to Creation Time */
3679                 *((FILETIME *)dptr) = ft;
3680                 dptr += 8;
3681
3682                 /* copy to Last Access Time */
3683                 *((FILETIME *)dptr) = ft;
3684                 dptr += 8;
3685
3686                 /* copy to Last Write Time */
3687                 *((FILETIME *)dptr) = ft;
3688                 dptr += 8;
3689
3690                 /* copy to Change Time */
3691                 *((FILETIME *)dptr) = ft;
3692                 dptr += 24;
3693
3694                 /* merge in hidden attribute */
3695                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3696                     *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3697                 }
3698                 dptr += 4;
3699             } else {
3700                 /* 1969-12-31 23:59:58 +00*/
3701                 dosTime = 0xEBBFBF7D;
3702
3703                 /* and copy out date */
3704                 shortTemp = (dosTime>>16) & 0xffff;
3705                 *((u_short *)dptr) = shortTemp;
3706                 dptr += 2;
3707
3708                 /* copy out creation time */
3709                 shortTemp = dosTime & 0xffff;
3710                 *((u_short *)dptr) = shortTemp;
3711                 dptr += 2;
3712
3713                 /* and copy out date */
3714                 shortTemp = (dosTime>>16) & 0xffff;
3715                 *((u_short *)dptr) = shortTemp;
3716                 dptr += 2;
3717                         
3718                 /* copy out access time */
3719                 shortTemp = dosTime & 0xffff;
3720                 *((u_short *)dptr) = shortTemp;
3721                 dptr += 2;
3722
3723                 /* and copy out date */
3724                 shortTemp = (dosTime>>16) & 0xffff;
3725                 *((u_short *)dptr) = shortTemp;
3726                 dptr += 2;
3727                         
3728                 /* copy out mod time */
3729                 shortTemp = dosTime & 0xffff;
3730                 *((u_short *)dptr) = shortTemp;
3731                 dptr += 10;
3732
3733                 /* merge in hidden (dot file) attribute */
3734                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3735                     attr = SMB_ATTR_HIDDEN;
3736                     *dptr++ = attr & 0xff;
3737                     *dptr++ = (attr >> 8) & 0xff;
3738                 }       
3739             }
3740             continue;
3741         }
3742         
3743         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3744
3745         /* now watch for a symlink */
3746         code = 0;
3747         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3748             lock_ReleaseMutex(&scp->mx);
3749             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3750             if (code == 0) {
3751                 /* we have a more accurate file to use (the
3752                  * target of the symbolic link).  Otherwise,
3753                  * we'll just use the symlink anyway.
3754                  */
3755                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3756                           scp, targetScp);
3757                 cm_ReleaseSCache(scp);
3758                 scp = targetScp;
3759             }
3760             lock_ObtainMutex(&scp->mx);
3761         }
3762
3763         dptr = patchp->dptr;
3764
3765         if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3766             /* get filetime */
3767             smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3768
3769             /* copy to Creation Time */
3770             *((FILETIME *)dptr) = ft;
3771             dptr += 8;
3772
3773             /* copy to Last Access Time */
3774             *((FILETIME *)dptr) = ft;
3775             dptr += 8;
3776
3777             /* copy to Last Write Time */
3778             *((FILETIME *)dptr) = ft;
3779             dptr += 8;
3780
3781             /* copy to Change Time */
3782             *((FILETIME *)dptr) = ft;
3783             dptr += 8;
3784
3785             /* Use length for both file length and alloc length */
3786             *((LARGE_INTEGER *)dptr) = scp->length;
3787             dptr += 8;
3788             *((LARGE_INTEGER *)dptr) = scp->length;
3789             dptr += 8;
3790
3791             /* Copy attributes */
3792             lattr = smb_ExtAttributes(scp);
3793             if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3794                 if (lattr == SMB_ATTR_NORMAL)
3795                     lattr = SMB_ATTR_DIRECTORY;
3796                 else
3797                     lattr |= SMB_ATTR_DIRECTORY;
3798             }
3799             /* merge in hidden (dot file) attribute */
3800             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3801                 if (lattr == SMB_ATTR_NORMAL)
3802                     lattr = SMB_ATTR_HIDDEN;
3803                 else
3804                     lattr |= SMB_ATTR_HIDDEN;
3805             }
3806             *((u_long *)dptr) = lattr;
3807             dptr += 4;
3808         } else {
3809             /* get dos time */
3810             smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3811
3812             /* and copy out date */
3813             shortTemp = (dosTime>>16) & 0xffff;
3814             *((u_short *)dptr) = shortTemp;
3815             dptr += 2;
3816
3817             /* copy out creation time */
3818             shortTemp = dosTime & 0xffff;
3819             *((u_short *)dptr) = shortTemp;
3820             dptr += 2;
3821
3822             /* and copy out date */
3823             shortTemp = (dosTime>>16) & 0xffff;
3824             *((u_short *)dptr) = shortTemp;
3825             dptr += 2;
3826
3827             /* copy out access time */
3828             shortTemp = dosTime & 0xffff;
3829             *((u_short *)dptr) = shortTemp;
3830             dptr += 2;
3831
3832             /* and copy out date */
3833             shortTemp = (dosTime>>16) & 0xffff;
3834             *((u_short *)dptr) = shortTemp;
3835             dptr += 2;
3836
3837             /* copy out mod time */
3838             shortTemp = dosTime & 0xffff;
3839             *((u_short *)dptr) = shortTemp;
3840             dptr += 2;
3841
3842             /* copy out file length and alloc length,
3843              * using the same for both
3844              */
3845             *((u_long *)dptr) = scp->length.LowPart;
3846             dptr += 4;
3847             *((u_long *)dptr) = scp->length.LowPart;
3848             dptr += 4;
3849
3850             /* finally copy out attributes as short */
3851             attr = smb_Attributes(scp);
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             *dptr++ = attr & 0xff;
3860             *dptr++ = (attr >> 8) & 0xff;
3861         }
3862
3863         lock_ReleaseMutex(&scp->mx);
3864         cm_ReleaseSCache(scp);
3865     }
3866         
3867     /* now free the patches */
3868     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3869         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3870         free(patchp);
3871     }
3872         
3873     /* and mark the list as empty */
3874     *dirPatchespp = NULL;
3875
3876     return code;
3877 }
3878
3879 #ifndef USE_OLD_MATCHING
3880 // char table for case insensitive comparison
3881 char mapCaseTable[256];
3882
3883 VOID initUpperCaseTable(VOID) 
3884 {
3885     int i;
3886     for (i = 0; i < 256; ++i) 
3887        mapCaseTable[i] = toupper(i);
3888     // make '"' match '.' 
3889     mapCaseTable[(int)'"'] = toupper('.');
3890     // make '<' match '*' 
3891     mapCaseTable[(int)'<'] = toupper('*');
3892     // make '>' match '?' 
3893     mapCaseTable[(int)'>'] = toupper('?');    
3894 }
3895
3896 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3897 // name 'name'.
3898 // Note : this procedure works recursively calling itself.
3899 // Parameters
3900 // PSZ pattern    : string containing metacharacters.
3901 // PSZ name       : file name to be compared with 'pattern'.
3902 // Return value
3903 // BOOL : TRUE/FALSE (match/mistmatch)
3904
3905 BOOL 
3906 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold) 
3907 {
3908     PSZ pename;         // points to the last 'name' character
3909     PSZ p;
3910     pename = name + strlen(name) - 1;
3911     while (*name) {
3912         switch (*pattern) {
3913         case '?':
3914             ++pattern;
3915             if (*name == '.')
3916                 continue;
3917             ++name;
3918             break;
3919          case '*':
3920             ++pattern;
3921             if (*pattern == '\0')
3922                 return TRUE;
3923             for (p = pename; p >= name; --p) {
3924                 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3925                      !casefold && (*p == *pattern)) &&
3926                      szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3927                     return TRUE;
3928             } /* endfor */
3929             return FALSE;
3930         default:
3931             if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3932                 (!casefold && *name != *pattern))
3933                 return FALSE;
3934             ++pattern, ++name;
3935             break;
3936         } /* endswitch */
3937     } /* endwhile */ 
3938
3939     /* if all we have left are wildcards, then we match */
3940     for (;*pattern; pattern++) {
3941         if (*pattern != '*' && *pattern != '?')
3942             return FALSE;
3943     }
3944     return TRUE;
3945 }
3946
3947 /* do a case-folding search of the star name mask with the name in namep.
3948  * Return 1 if we match, otherwise 0.
3949  */
3950 int smb_V3MatchMask(char *namep, char *maskp, int flags) 
3951 {
3952     char * newmask;
3953     int    i, j, star, qmark, casefold, retval;
3954
3955     /* make sure we only match 8.3 names, if requested */
3956     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
3957         return 0;
3958     
3959     casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3960
3961     /* optimize the pattern:
3962      * if there is a mixture of '?' and '*',
3963      * for example  the sequence "*?*?*?*"
3964      * must be turned into the form "*"
3965      */
3966     newmask = (char *)malloc(strlen(maskp)+1);
3967     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3968         switch ( maskp[i] ) {
3969         case '?':
3970         case '>':
3971             qmark++;
3972             break;
3973         case '<':
3974         case '*':
3975             star++;
3976             break;
3977         default:
3978             if ( star ) {
3979                 newmask[j++] = '*';
3980             } else if ( qmark ) {
3981                 while ( qmark-- )
3982                     newmask[j++] = '?';
3983             }
3984             newmask[j++] = maskp[i];
3985             star = 0;
3986             qmark = 0;
3987         }
3988     }
3989     if ( star ) {
3990         newmask[j++] = '*';
3991     } else if ( qmark ) {
3992         while ( qmark-- )
3993             newmask[j++] = '?';
3994     }
3995     newmask[j++] = '\0';
3996
3997     retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3998
3999     free(newmask);
4000     return retval;
4001 }
4002
4003 #else /* USE_OLD_MATCHING */
4004 /* do a case-folding search of the star name mask with the name in namep.
4005  * Return 1 if we match, otherwise 0.
4006  */
4007 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4008 {
4009     unsigned char tcp1, tcp2;   /* Pattern characters */
4010     unsigned char tcn1;         /* Name characters */
4011     int sawDot = 0, sawStar = 0, req8dot3 = 0;
4012     char *starNamep, *starMaskp;
4013     static char nullCharp[] = {0};
4014     int casefold = flags & CM_FLAG_CASEFOLD;
4015
4016     /* make sure we only match 8.3 names, if requested */
4017     req8dot3 = (flags & CM_FLAG_8DOT3);
4018     if (req8dot3 && !cm_Is8Dot3(namep)) 
4019         return 0;
4020
4021     /* loop */
4022     while (1) {
4023         /* Next pattern character */
4024         tcp1 = *maskp++;
4025
4026         /* Next name character */
4027         tcn1 = *namep;
4028
4029         if (tcp1 == 0) {
4030             /* 0 - end of pattern */
4031             if (tcn1 == 0)
4032                 return 1;
4033             else
4034                 return 0;
4035         }
4036         else if (tcp1 == '.' || tcp1 == '"') {
4037             if (sawDot) {
4038                 if (tcn1 == '.') {
4039                     namep++;
4040                     continue;
4041                 } else
4042                     return 0;
4043             }
4044             else {
4045                 /*
4046                  * first dot in pattern;
4047                  * must match dot or end of name
4048                  */
4049                 sawDot = 1;
4050                 if (tcn1 == 0)
4051                     continue;
4052                 else if (tcn1 == '.') {
4053                     sawStar = 0;
4054                     namep++;
4055                     continue;
4056                 }
4057                 else
4058                     return 0;
4059             }
4060         }
4061         else if (tcp1 == '?') {
4062             if (tcn1 == 0 || tcn1 == '.')
4063                 return 0;
4064             namep++;
4065             continue;
4066         }
4067         else if (tcp1 == '>') {
4068             if (tcn1 != 0 && tcn1 != '.')
4069                 namep++;
4070             continue;
4071         }
4072         else if (tcp1 == '*' || tcp1 == '<') {
4073             tcp2 = *maskp++;
4074             if (tcp2 == 0)
4075                 return 1;
4076             else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4077                 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4078                     tcn1 = *++namep;
4079                 if (tcn1 == 0) {
4080                     if (sawDot)
4081                         return 0;
4082                     else
4083                         continue;
4084                 }
4085                 else {
4086                     namep++;
4087                     continue;
4088                 }
4089             }
4090             else {
4091                 /*
4092                  * pattern character after '*' is not null or
4093                  * period.  If it is '?' or '>', we are not
4094                  * going to understand it.  If it is '*' or
4095                  * '<', we are going to skip over it.  None of
4096                  * these are likely, I hope.
4097                  */
4098                 /* skip over '*' and '<' */
4099                 while (tcp2 == '*' || tcp2 == '<')
4100                     tcp2 = *maskp++;
4101
4102                 /* skip over characters that don't match tcp2 */
4103                 while (req8dot3 && tcn1 != '.' && tcn1 != 0 && 
4104                         ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
4105                           (!casefold && tcn1 != tcp2)))
4106                     tcn1 = *++namep;
4107
4108                 /* No match */
4109                 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4110                     return 0;
4111
4112                 /* Remember where we are */
4113                 sawStar = 1;
4114                 starMaskp = maskp;
4115                 starNamep = namep;
4116
4117                 namep++;
4118                 continue;
4119             }
4120         }
4121         else {
4122             /* tcp1 is not a wildcard */
4123             if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
4124                  (!casefold && tcn1 == tcp1)) {
4125                 /* they match */
4126                 namep++;
4127                 continue;
4128             }
4129             /* if trying to match a star pattern, go back */
4130             if (sawStar) {
4131                 maskp = starMaskp - 2;
4132                 namep = starNamep + 1;
4133                 sawStar = 0;
4134                 continue;
4135             }
4136             /* that's all */
4137             return 0;
4138         }
4139     }
4140 }
4141 #endif /* USE_OLD_MATCHING */
4142
4143 /* smb_ReceiveTran2SearchDir implements both 
4144  * Tran2_Find_First and Tran2_Find_Next
4145  */
4146 #define TRAN2_FIND_FLAG_CLOSE_SEARCH            0x01
4147 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END     0x02
4148 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS      0x04
4149 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH         0x08
4150 #define TRAN2_FIND_FLAG_BACKUP_INTENT           0x10
4151
4152 /* this is an optimized handler for T2SearchDir that handles the case
4153    where there are no wildcards in the search path.  I.e. an
4154    application is using FindFirst(Ex) to get information about a
4155    single file or directory.  It will attempt to do a single lookup.
4156    If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4157    the usual mechanism. 
4158    
4159    This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4160    */
4161 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4162 {
4163     int attribute;
4164     long nextCookie;
4165     long code = 0, code2 = 0;
4166     char *pathp;
4167     int maxCount;
4168     smb_dirListPatch_t *dirListPatchesp;
4169     smb_dirListPatch_t *curPatchp;
4170     long orbytes;                       /* # of bytes in this output record */
4171     long ohbytes;                       /* # of bytes, except file name */
4172     long onbytes;                       /* # of bytes in name, incl. term. null */
4173     cm_scache_t *scp = NULL;
4174     cm_scache_t *targetscp = NULL;
4175     cm_user_t *userp = NULL;
4176     char *op;                           /* output data ptr */
4177     char *origOp;                       /* original value of op */
4178     cm_space_t *spacep;                 /* for pathname buffer */
4179     long maxReturnData;                 /* max # of return data */
4180     long maxReturnParms;                /* max # of return parms */
4181     long bytesInBuffer;                 /* # data bytes in the output buffer */
4182     char *maskp;                        /* mask part of path */
4183     int infoLevel;
4184     int searchFlags;
4185     int eos;
4186     smb_tran2Packet_t *outp;            /* response packet */
4187     char *tidPathp;
4188     int align;
4189     char shortName[13];                 /* 8.3 name if needed */
4190     int NeedShortName;
4191     char *shortNameEnd;
4192     cm_req_t req;
4193     char * s;
4194
4195     cm_InitReq(&req);
4196
4197     eos = 0;
4198     osi_assert(p->opcode == 1);
4199
4200     /* find first; obtain basic parameters from request */
4201
4202     /* note that since we are going to failover to regular
4203      * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4204      * modify any of the input parameters here. */
4205     attribute = p->parmsp[0];
4206     maxCount = p->parmsp[1];
4207     infoLevel = p->parmsp[3];
4208     searchFlags = p->parmsp[2];
4209     pathp = ((char *) p->parmsp) + 12;  /* points to path */
4210     nextCookie = 0;
4211     maskp = strrchr(pathp, '\\');
4212     if (maskp == NULL) 
4213         maskp = pathp;
4214     else 
4215         maskp++;        /* skip over backslash */
4216     /* track if this is likely to match a lot of entries */
4217
4218     osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%s], mask[%s]",
4219             osi_LogSaveString(smb_logp, pathp),
4220             osi_LogSaveString(smb_logp, maskp));
4221
4222     switch ( infoLevel ) {
4223     case SMB_INFO_STANDARD:
4224         s = "InfoStandard";
4225         break;
4226     case SMB_INFO_QUERY_EA_SIZE:
4227         s = "InfoQueryEaSize";
4228         break;
4229     case SMB_INFO_QUERY_EAS_FROM_LIST:
4230         s = "InfoQueryEasFromList";
4231         break;
4232     case SMB_FIND_FILE_DIRECTORY_INFO:
4233         s = "FindFileDirectoryInfo";
4234         break;
4235     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4236         s = "FindFileFullDirectoryInfo";
4237         break;
4238     case SMB_FIND_FILE_NAMES_INFO:
4239         s = "FindFileNamesInfo";
4240         break;
4241     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4242         s = "FindFileBothDirectoryInfo";
4243         break;
4244     default:
4245         s = "unknownInfoLevel";
4246     }
4247
4248     osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4249
4250     osi_Log4(smb_logp,
4251              "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4252              attribute, infoLevel, maxCount, searchFlags);
4253     
4254     if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4255         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4256         return CM_ERROR_INVAL;
4257     }
4258
4259     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4260         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;     /* no resume keys */
4261
4262     dirListPatchesp = NULL;
4263
4264     maxReturnData = p->maxReturnData;
4265     maxReturnParms = 10;        /* return params for findfirst, which
4266                                    is the only one we handle.*/
4267
4268 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4269     if (maxReturnData > 6000) 
4270         maxReturnData = 6000;
4271 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4272
4273     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4274                                       maxReturnData);
4275
4276     osi_Log2(smb_logp, "T2SDSingle search dir count %d [%s]",
4277              maxCount, osi_LogSaveString(smb_logp, pathp));
4278         
4279     /* bail out if request looks bad */
4280     if (!pathp) {
4281         smb_FreeTran2Packet(outp);
4282         return CM_ERROR_BADSMB;
4283     }
4284         
4285     userp = smb_GetTran2User(vcp, p);
4286     if (!userp) {
4287         osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4288         smb_FreeTran2Packet(outp);
4289         return CM_ERROR_BADSMB;
4290     }
4291
4292     /* try to get the vnode for the path name next */
4293     spacep = cm_GetSpace();
4294     smb_StripLastComponent(spacep->data, NULL, pathp);
4295     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4296     if (code) {
4297         cm_ReleaseUser(userp);
4298         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4299         smb_FreeTran2Packet(outp);
4300         return 0;
4301     }
4302
4303     code = cm_NameI(cm_data.rootSCachep, spacep->data,
4304                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4305                     userp, tidPathp, &req, &scp);
4306     cm_FreeSpace(spacep);
4307
4308     if (code) {
4309         cm_ReleaseUser(userp);
4310         smb_SendTran2Error(vcp, p, opx, code);
4311         smb_FreeTran2Packet(outp);
4312         return 0;
4313     }
4314
4315 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4316     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4317         cm_ReleaseSCache(scp);
4318         cm_ReleaseUser(userp);
4319         if ( WANTS_DFS_PATHNAMES(p) )
4320             code = CM_ERROR_PATH_NOT_COVERED;
4321         else
4322             code = CM_ERROR_BADSHARENAME;
4323         smb_SendTran2Error(vcp, p, opx, code);
4324         smb_FreeTran2Packet(outp);
4325         return 0;
4326     }
4327 #endif /* DFS_SUPPORT */
4328     osi_Log1(smb_logp,"smb_ReceiveTran2SearchDir scp 0x%p", scp);
4329     lock_ObtainMutex(&scp->mx);
4330     if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4331          LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4332         scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4333     }
4334     lock_ReleaseMutex(&scp->mx);
4335
4336     /* now do a single case sensitive lookup for the file in question */
4337     code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4338
4339     /* if a case sensitive match failed, we try a case insensitive one
4340        next. */
4341     if (code == CM_ERROR_NOSUCHFILE) {
4342         code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4343     }
4344
4345     if (code == 0 && targetscp->fid.vnode == 0) {
4346         cm_ReleaseSCache(targetscp);
4347         code = CM_ERROR_NOSUCHFILE;
4348     }
4349
4350     if (code) {
4351         /* if we can't find the directory entry, this block will
4352            return CM_ERROR_NOSUCHFILE, which we will pass on to
4353            smb_ReceiveTran2SearchDir(). */
4354         cm_ReleaseSCache(scp);
4355         cm_ReleaseUser(userp);
4356         if (code != CM_ERROR_NOSUCHFILE) {
4357             smb_SendTran2Error(vcp, p, opx, code);
4358             code = 0;
4359         }
4360         smb_FreeTran2Packet(outp);
4361         return code;
4362     }
4363
4364     /* now that we have the target in sight, we proceed with filling
4365        up the return data. */
4366
4367     op = origOp = outp->datap;
4368     bytesInBuffer = 0;
4369
4370     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4371         /* skip over resume key */
4372         op += 4;
4373     }
4374
4375     if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4376         && targetscp->fid.vnode != 0
4377         && !cm_Is8Dot3(maskp)) {
4378
4379         cm_dirFid_t dfid;
4380         dfid.vnode = htonl(targetscp->fid.vnode);
4381         dfid.unique = htonl(targetscp->fid.unique);
4382
4383         cm_Gen8Dot3NameInt(maskp, &dfid, shortName, &shortNameEnd);
4384         NeedShortName = 1;
4385     } else {
4386         NeedShortName = 0;
4387     }
4388
4389     osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %s (%s)",
4390               htonl(targetscp->fid.vnode),
4391               htonl(targetscp->fid.unique),
4392               osi_LogSaveString(smb_logp, pathp),
4393               NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4394
4395     /* Eliminate entries that don't match requested attributes */
4396     if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4397         smb_IsDotFile(maskp)) {
4398
4399         code = CM_ERROR_NOSUCHFILE;
4400         osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4401         goto skip_file;
4402
4403     }
4404
4405     if (!(attribute & SMB_ATTR_DIRECTORY) &&
4406         (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4407          targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4408          targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4409
4410         code = CM_ERROR_NOSUCHFILE;
4411         osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4412         goto skip_file;
4413
4414     }
4415
4416     /* Check if the name will fit */
4417     if (infoLevel < 0x101)
4418         ohbytes = 23;           /* pre-NT */
4419     else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4420         ohbytes = 12;           /* NT names only */
4421     else
4422         ohbytes = 64;           /* NT */
4423
4424     if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4425         ohbytes += 26;          /* Short name & length */
4426
4427     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4428         ohbytes += 4;           /* if resume key required */
4429     }
4430
4431     if (infoLevel != SMB_INFO_STANDARD
4432         && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4433         && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4434         ohbytes += 4;           /* EASIZE */
4435
4436     /* add header to name & term. null */
4437     onbytes = strlen(maskp);
4438     orbytes = ohbytes + onbytes + 1;
4439
4440     /* now, we round up the record to a 4 byte alignment, and we make
4441      * sure that we have enough room here for even the aligned version
4442      * (so we don't have to worry about an * overflow when we pad
4443      * things out below).  That's the reason for the alignment
4444      * arithmetic below.
4445      */
4446     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4447         align = (4 - (orbytes & 3)) & 3;
4448     else
4449         align = 0;
4450
4451     if (orbytes + align > maxReturnData) {
4452
4453         /* even though this request is unlikely to succeed with a
4454            failover, we do it anyway. */
4455         code = CM_ERROR_NOSUCHFILE;
4456         osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4457                  maxReturnData);
4458         goto skip_file;
4459     }
4460
4461     /* this is one of the entries to use: it is not deleted and it
4462      * matches the star pattern we're looking for.  Put out the name,
4463      * preceded by its length.
4464      */
4465     /* First zero everything else */
4466     memset(origOp, 0, ohbytes);
4467
4468     if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4469         *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4470     else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4471         *((u_long *)(op + 8)) = onbytes;
4472     else
4473         *((u_long *)(op + 60)) = onbytes;
4474     strcpy(origOp+ohbytes, maskp);
4475     if (smb_StoreAnsiFilenames)
4476         CharToOem(origOp+ohbytes, origOp+ohbytes);
4477
4478     /* Short name if requested and needed */
4479     if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4480         if (NeedShortName) {
4481             strcpy(op + 70, shortName);
4482             if (smb_StoreAnsiFilenames)
4483                 CharToOem(op + 70, op + 70);
4484             *(op + 68) = (char)(shortNameEnd - shortName);
4485         }
4486     }
4487
4488     /* NextEntryOffset and FileIndex */
4489     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4490         int entryOffset = orbytes + align;
4491         *((u_long *)op) = 0;
4492         *((u_long *)(op+4)) = 0;
4493     }
4494
4495     if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4496         curPatchp = malloc(sizeof(*curPatchp));
4497         osi_QAdd((osi_queue_t **) &dirListPatchesp,
4498                  &curPatchp->q);
4499         curPatchp->dptr = op;
4500         if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4501             curPatchp->dptr += 8;
4502
4503         if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4504             curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4505         } else {
4506             curPatchp->flags = 0;
4507         }
4508
4509         curPatchp->fid.cell = targetscp->fid.cell;
4510         curPatchp->fid.volume = targetscp->fid.volume;
4511         curPatchp->fid.vnode = targetscp->fid.vnode;
4512         curPatchp->fid.unique = targetscp->fid.unique;
4513
4514         /* temp */
4515         curPatchp->dep = NULL;
4516     }   
4517
4518     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4519         /* put out resume key */
4520         *((u_long *)origOp) = 0;
4521     }
4522
4523     /* Adjust byte ptr and count */
4524     origOp += orbytes;  /* skip entire record */
4525     bytesInBuffer += orbytes;
4526
4527     /* and pad the record out */
4528     while (--align >= 0) {
4529         *origOp++ = 0;
4530         bytesInBuffer++;
4531     }
4532
4533     /* apply the patches */
4534     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp, &req);
4535
4536     outp->parmsp[0] = 0;
4537     outp->parmsp[1] = 1;        /* number of names returned */
4538     outp->parmsp[2] = 1;        /* end of search */
4539     outp->parmsp[3] = 0;        /* nothing wrong with EAS */
4540     outp->parmsp[4] = 0;
4541
4542     outp->totalParms = 10;      /* in bytes */
4543
4544     outp->totalData = bytesInBuffer;
4545
4546     osi_Log0(smb_logp, "T2SDSingle done.");
4547
4548     if (code != CM_ERROR_NOSUCHFILE) {
4549         if (code)
4550             smb_SendTran2Error(vcp, p, opx, code);
4551         else
4552             smb_SendTran2Packet(vcp, outp, opx);
4553         code = 0;
4554     }
4555
4556  skip_file:
4557     smb_FreeTran2Packet(outp);
4558     cm_ReleaseSCache(scp);
4559     cm_ReleaseSCache(targetscp);
4560     cm_ReleaseUser(userp);
4561
4562     return code;
4563 }
4564
4565
4566 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4567 {
4568     int attribute;
4569     long nextCookie;
4570     char *tp;
4571     long code = 0, code2 = 0;
4572     char *pathp;
4573     cm_dirEntry_t *dep;
4574     int maxCount;
4575     smb_dirListPatch_t *dirListPatchesp;
4576     smb_dirListPatch_t *curPatchp;
4577     cm_buf_t *bufferp;
4578     long temp;
4579     long orbytes;                       /* # of bytes in this output record */
4580     long ohbytes;                       /* # of bytes, except file name */
4581     long onbytes;                       /* # of bytes in name, incl. term. null */
4582     osi_hyper_t dirLength;
4583     osi_hyper_t bufferOffset;
4584     osi_hyper_t curOffset;
4585     osi_hyper_t thyper;
4586     smb_dirSearch_t *dsp;
4587     cm_scache_t *scp;
4588     long entryInDir;
4589     long entryInBuffer;
4590     cm_pageHeader_t *pageHeaderp;
4591     cm_user_t *userp = NULL;
4592     int slotInPage;
4593     int returnedNames;
4594     long nextEntryCookie;
4595     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
4596     char *op;                   /* output data ptr */
4597     char *origOp;                       /* original value of op */
4598     cm_space_t *spacep;         /* for pathname buffer */
4599     long maxReturnData;         /* max # of return data */
4600     long maxReturnParms;                /* max # of return parms */
4601     long bytesInBuffer;         /* # data bytes in the output buffer */
4602     int starPattern;
4603     char *maskp;                        /* mask part of path */
4604     int infoLevel;
4605     int searchFlags;
4606     int eos;
4607     smb_tran2Packet_t *outp;    /* response packet */
4608     char *tidPathp;
4609     int align;
4610     char shortName[13];         /* 8.3 name if needed */
4611     int NeedShortName;
4612     int foundInexact;
4613     char *shortNameEnd;
4614     int fileType;
4615     cm_fid_t fid;
4616     cm_req_t req;
4617     char * s;
4618
4619     cm_InitReq(&req);
4620
4621     eos = 0;
4622     if (p->opcode == 1) {
4623         /* find first; obtain basic parameters from request */
4624         attribute = p->parmsp[0];
4625         maxCount = p->parmsp[1];
4626         infoLevel = p->parmsp[3];
4627         searchFlags = p->parmsp[2];
4628         pathp = ((char *) p->parmsp) + 12;      /* points to path */
4629         if (smb_StoreAnsiFilenames)
4630             OemToChar(pathp,pathp);
4631         nextCookie = 0;
4632         maskp = strrchr(pathp, '\\');
4633         if (maskp == NULL) 
4634             maskp = pathp;
4635         else 
4636             maskp++;    /* skip over backslash */
4637
4638         /* track if this is likely to match a lot of entries */
4639         starPattern = smb_V3IsStarMask(maskp);
4640
4641 #ifndef NOFINDFIRSTOPTIMIZE
4642         if (!starPattern) {
4643             /* if this is for a single directory or file, we let the
4644                optimized routine handle it.  The only error it 
4645                returns is CM_ERROR_NOSUCHFILE.  The  */
4646             code = smb_T2SearchDirSingle(vcp, p, opx);
4647
4648             /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4649             if (code != CM_ERROR_NOSUCHFILE) {
4650                 return code;
4651             }
4652         }
4653 #endif
4654
4655         dsp = smb_NewDirSearch(1);
4656         dsp->attribute = attribute;
4657         strcpy(dsp->mask, maskp);       /* and save mask */
4658     }
4659     else {
4660         osi_assert(p->opcode == 2);
4661         /* find next; obtain basic parameters from request or open dir file */
4662         dsp = smb_FindDirSearch(p->parmsp[0]);
4663         maxCount = p->parmsp[1];
4664         infoLevel = p->parmsp[2];
4665         nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4666         searchFlags = p->parmsp[5];
4667         if (!dsp) {
4668             osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4669                      p->parmsp[0], nextCookie);
4670             return CM_ERROR_BADFD;
4671         }
4672         attribute = dsp->attribute;
4673         pathp = NULL;
4674         maskp = dsp->mask;
4675         starPattern = 1;        /* assume, since required a Find Next */
4676     }
4677
4678     switch ( infoLevel ) {
4679     case SMB_INFO_STANDARD:
4680         s = "InfoStandard";
4681         break;
4682     case SMB_INFO_QUERY_EA_SIZE:
4683         s = "InfoQueryEaSize";
4684         break;
4685     case SMB_INFO_QUERY_EAS_FROM_LIST:
4686         s = "InfoQueryEasFromList";
4687         break;
4688     case SMB_FIND_FILE_DIRECTORY_INFO:
4689         s = "FindFileDirectoryInfo";
4690         break;
4691     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4692         s = "FindFileFullDirectoryInfo";
4693         break;
4694     case SMB_FIND_FILE_NAMES_INFO:
4695         s = "FindFileNamesInfo";
4696         break;
4697     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4698         s = "FindFileBothDirectoryInfo";
4699         break;
4700     default:
4701         s = "unknownInfoLevel";
4702     }
4703
4704     osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4705
4706     osi_Log4(smb_logp,
4707               "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4708               attribute, infoLevel, maxCount, searchFlags);
4709
4710     osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4711               p->opcode, dsp->cookie, nextCookie);
4712
4713     if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4714         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4715         smb_ReleaseDirSearch(dsp);
4716         return CM_ERROR_INVAL;
4717     }
4718
4719     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4720         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;     /* no resume keys */
4721
4722     dirListPatchesp = NULL;
4723
4724     maxReturnData = p->maxReturnData;
4725     if (p->opcode == 1) /* find first */
4726         maxReturnParms = 10;    /* bytes */
4727     else    
4728         maxReturnParms = 8;     /* bytes */
4729
4730 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4731     if (maxReturnData > 6000) 
4732         maxReturnData = 6000;
4733 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4734
4735     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4736                                       maxReturnData);
4737
4738     osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4739              maxCount, osi_LogSaveString(smb_logp, pathp));
4740         
4741     /* bail out if request looks bad */
4742     if (p->opcode == 1 && !pathp) {
4743         smb_ReleaseDirSearch(dsp);
4744         smb_FreeTran2Packet(outp);
4745         return CM_ERROR_BADSMB;
4746     }
4747         
4748     osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4749              dsp->cookie, nextCookie, attribute);
4750
4751     userp = smb_GetTran2User(vcp, p);
4752     if (!userp) {
4753         osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4754         smb_ReleaseDirSearch(dsp);
4755         smb_FreeTran2Packet(outp);
4756         return CM_ERROR_BADSMB;
4757     }
4758
4759     /* try to get the vnode for the path name next */
4760     lock_ObtainMutex(&dsp->mx);
4761     if (dsp->scp) {
4762         scp = dsp->scp;
4763         osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4764         cm_HoldSCache(scp);
4765         code = 0;
4766     } else {
4767         spacep = cm_GetSpace();
4768         smb_StripLastComponent(spacep->data, NULL, pathp);
4769         code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4770         if (code) {
4771             cm_ReleaseUser(userp);
4772             smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4773             smb_FreeTran2Packet(outp);
4774             lock_ReleaseMutex(&dsp->mx);
4775             smb_DeleteDirSearch(dsp);
4776             smb_ReleaseDirSearch(dsp);
4777             return 0;
4778         }
4779         code = cm_NameI(cm_data.rootSCachep, spacep->data,
4780                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4781                         userp, tidPathp, &req, &scp);
4782         cm_FreeSpace(spacep);
4783
4784         if (code == 0) {
4785 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4786             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4787                 cm_ReleaseSCache(scp);
4788                 cm_ReleaseUser(userp);
4789                 if ( WANTS_DFS_PATHNAMES(p) )
4790                     code = CM_ERROR_PATH_NOT_COVERED;
4791                 else
4792                     code = CM_ERROR_BADSHARENAME;
4793                 smb_SendTran2Error(vcp, p, opx, code);
4794                 smb_FreeTran2Packet(outp);
4795                 lock_ReleaseMutex(&dsp->mx);
4796                 smb_DeleteDirSearch(dsp);
4797                 smb_ReleaseDirSearch(dsp);
4798                 return 0;
4799             }
4800 #endif /* DFS_SUPPORT */
4801             dsp->scp = scp;
4802             osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4803             /* we need one hold for the entry we just stored into,
4804              * and one for our own processing.  When we're done
4805              * with this function, we'll drop the one for our own
4806              * processing.  We held it once from the namei call,
4807              * and so we do another hold now.
4808              */
4809             cm_HoldSCache(scp);
4810             lock_ObtainMutex(&scp->mx);
4811             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4812                  LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4813                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4814                 dsp->flags |= SMB_DIRSEARCH_BULKST;
4815             }
4816             lock_ReleaseMutex(&scp->mx);
4817         } 
4818     }
4819     lock_ReleaseMutex(&dsp->mx);
4820     if (code) {
4821         cm_ReleaseUser(userp);
4822         smb_FreeTran2Packet(outp);
4823         smb_DeleteDirSearch(dsp);
4824         smb_ReleaseDirSearch(dsp);
4825         return code;
4826     }
4827
4828     /* get the directory size */
4829     lock_ObtainMutex(&scp->mx);
4830     code = cm_SyncOp(scp, NULL, userp, &req, 0,
4831                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4832     if (code) {
4833         lock_ReleaseMutex(&scp->mx);
4834         cm_ReleaseSCache(scp);
4835         cm_ReleaseUser(userp);
4836         smb_FreeTran2Packet(outp);
4837         smb_DeleteDirSearch(dsp);
4838         smb_ReleaseDirSearch(dsp);
4839         return code;
4840     }
4841
4842     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4843
4844   startsearch:
4845     dirLength = scp->length;
4846     bufferp = NULL;
4847     bufferOffset.LowPart = bufferOffset.HighPart = 0;
4848     curOffset.HighPart = 0;
4849     curOffset.LowPart = nextCookie;
4850     origOp = outp->datap;
4851
4852     foundInexact = 0;
4853     code = 0;
4854     returnedNames = 0;
4855     bytesInBuffer = 0;
4856     while (1) {
4857         op = origOp;
4858         if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4859             /* skip over resume key */
4860             op += 4;
4861
4862         /* make sure that curOffset.LowPart doesn't point to the first
4863          * 32 bytes in the 2nd through last dir page, and that it doesn't
4864          * point at the first 13 32-byte chunks in the first dir page,
4865          * since those are dir and page headers, and don't contain useful
4866          * information.
4867          */
4868         temp = curOffset.LowPart & (2048-1);
4869         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4870             /* we're in the first page */
4871             if (temp < 13*32) temp = 13*32;
4872         }
4873         else {
4874             /* we're in a later dir page */
4875             if (temp < 32) temp = 32;
4876         }
4877                 
4878         /* make sure the low order 5 bits are zero */
4879         temp &= ~(32-1);
4880                 
4881         /* now put temp bits back ito curOffset.LowPart */
4882         curOffset.LowPart &= ~(2048-1);
4883         curOffset.LowPart |= temp;
4884
4885         /* check if we've passed the dir's EOF */
4886         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4887             osi_Log0(smb_logp, "T2 search dir passed eof");
4888             eos = 1;
4889             break;
4890         }
4891
4892         /* check if we've returned all the names that will fit in the
4893          * response packet; we check return count as well as the number
4894          * of bytes requested.  We check the # of bytes after we find
4895          * the dir entry, since we'll need to check its size.
4896          */
4897         if (returnedNames >= maxCount) {
4898             osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4899                       returnedNames, maxCount);
4900             break;
4901         }
4902
4903         /* see if we can use the bufferp we have now; compute in which
4904          * page the current offset would be, and check whether that's
4905          * the offset of the buffer we have.  If not, get the buffer.
4906          */
4907         thyper.HighPart = curOffset.HighPart;
4908         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4909         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4910             /* wrong buffer */
4911             if (bufferp) {
4912                 buf_Release(bufferp);
4913                 bufferp = NULL;
4914             }       
4915             lock_ReleaseMutex(&scp->mx);
4916             lock_ObtainRead(&scp->bufCreateLock);
4917             code = buf_Get(scp, &thyper, &bufferp);
4918             lock_ReleaseRead(&scp->bufCreateLock);
4919             lock_ObtainMutex(&dsp->mx);
4920
4921             /* now, if we're doing a star match, do bulk fetching
4922              * of all of the status info for files in the dir.
4923              */
4924             if (starPattern) {
4925                 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4926                                            infoLevel, userp,
4927                                            &req);
4928                 lock_ObtainMutex(&scp->mx);
4929                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4930                     LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4931                     /* Don't bulk stat if risking timeout */
4932                     DWORD now = GetTickCount();
4933                     if (now - req.startTime > RDRtimeout) {
4934                         scp->bulkStatProgress = thyper;
4935                         scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4936                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4937                     } else
4938                         code = cm_TryBulkStat(scp, &thyper, userp, &req);
4939                 }
4940             } else {
4941                 lock_ObtainMutex(&scp->mx);
4942             }
4943             lock_ReleaseMutex(&dsp->mx);
4944             if (code) {
4945                 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4946                 break;
4947             }
4948
4949             bufferOffset = thyper;
4950
4951             /* now get the data in the cache */
4952             while (1) {
4953                 code = cm_SyncOp(scp, bufferp, userp, &req,
4954                                  PRSFS_LOOKUP,
4955                                  CM_SCACHESYNC_NEEDCALLBACK
4956                                  | CM_SCACHESYNC_READ);
4957                 if (code) {
4958                     osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4959                     break;
4960                 }
4961                        
4962                 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4963
4964                 if (cm_HaveBuffer(scp, bufferp, 0)) {
4965                     osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4966                     break;
4967                 }
4968
4969                 /* otherwise, load the buffer and try again */
4970                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4971                                     &req);
4972                 if (code) {
4973                     osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d", 
4974                               scp, bufferp, code);
4975                     break;
4976                 }
4977             }
4978             if (code) {
4979                 buf_Release(bufferp);
4980                 bufferp = NULL;
4981                 break;
4982             }
4983         }       /* if (wrong buffer) ... */
4984                 
4985         /* now we have the buffer containing the entry we're interested
4986          * in; copy it out if it represents a non-deleted entry.
4987          */
4988         entryInDir = curOffset.LowPart & (2048-1);
4989         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4990
4991         /* page header will help tell us which entries are free.  Page
4992          * header can change more often than once per buffer, since
4993          * AFS 3 dir page size may be less than (but not more than)
4994          * a buffer package buffer.
4995          */
4996         /* only look intra-buffer */
4997         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4998         temp &= ~(2048 - 1);    /* turn off intra-page bits */
4999         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5000
5001         /* now determine which entry we're looking at in the page.
5002          * If it is free (there's a free bitmap at the start of the
5003          * dir), we should skip these 32 bytes.
5004          */
5005         slotInPage = (entryInDir & 0x7e0) >> 5;
5006         if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5007             (1 << (slotInPage & 0x7)))) {
5008             /* this entry is free */
5009             numDirChunks = 1;   /* only skip this guy */
5010             goto nextEntry;
5011         }
5012
5013         tp = bufferp->datap + entryInBuffer;
5014         dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
5015
5016         /* while we're here, compute the next entry's location, too,
5017          * since we'll need it when writing out the cookie into the dir
5018          * listing stream.
5019          *
5020          * XXXX Probably should do more sanity checking.
5021          */
5022         numDirChunks = cm_NameEntries(dep->name, &onbytes);
5023                 
5024         /* compute offset of cookie representing next entry */
5025         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5026
5027         /* Need 8.3 name? */
5028         NeedShortName = 0;
5029         if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
5030              && dep->fid.vnode != 0
5031              && !cm_Is8Dot3(dep->name)) {
5032             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5033             NeedShortName = 1;
5034         }
5035
5036         osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
5037                   dep->fid.vnode, dep->fid.unique, 
5038                   osi_LogSaveString(smb_logp, dep->name),
5039                   NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
5040
5041         /* When matching, we are using doing a case fold if we have a wildcard mask.
5042          * If we get a non-wildcard match, it's a lookup for a specific file. 
5043          */
5044         if (dep->fid.vnode != 0 && 
5045             (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5046              (NeedShortName &&
5047               smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
5048
5049             /* Eliminate entries that don't match requested attributes */
5050             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
5051                  smb_IsDotFile(dep->name)) {
5052                 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5053                 goto nextEntry; /* no hidden files */
5054             }
5055             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
5056             {
5057                 /* We have already done the cm_TryBulkStat above */
5058                 fid.cell = scp->fid.cell;
5059                 fid.volume = scp->fid.volume;
5060                 fid.vnode = ntohl(dep->fid.vnode);
5061                 fid.unique = ntohl(dep->fid.unique);
5062                 fileType = cm_FindFileType(&fid);
5063                 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5064                  "has filetype %d", dep->name,
5065                  fileType);*/
5066                 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5067                     fileType == CM_SCACHETYPE_DFSLINK ||
5068                     fileType == CM_SCACHETYPE_INVALID)
5069                     osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5070                     goto nextEntry;
5071             }
5072
5073             /* finally check if this name will fit */
5074
5075             /* standard dir entry stuff */
5076             if (infoLevel < 0x101)
5077                 ohbytes = 23;   /* pre-NT */
5078             else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5079                 ohbytes = 12;   /* NT names only */
5080             else
5081                 ohbytes = 64;   /* NT */
5082
5083             if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
5084                 ohbytes += 26;  /* Short name & length */
5085
5086             if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5087                 ohbytes += 4;   /* if resume key required */
5088             }   
5089
5090             if (infoLevel != SMB_INFO_STANDARD
5091                  && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
5092                  && infoLevel != SMB_FIND_FILE_NAMES_INFO)
5093                 ohbytes += 4;   /* EASIZE */
5094
5095             /* add header to name & term. null */
5096             orbytes = onbytes + ohbytes + 1;
5097
5098             /* now, we round up the record to a 4 byte alignment,
5099              * and we make sure that we have enough room here for
5100              * even the aligned version (so we don't have to worry
5101              * about an * overflow when we pad things out below).
5102              * That's the reason for the alignment arithmetic below.
5103              */
5104             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5105                 align = (4 - (orbytes & 3)) & 3;
5106             else
5107                 align = 0;
5108             if (orbytes + bytesInBuffer + align > maxReturnData) {
5109                 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5110                           maxReturnData);
5111                 break;
5112             }
5113
5114             /* this is one of the entries to use: it is not deleted
5115              * and it matches the star pattern we're looking for.
5116              * Put out the name, preceded by its length.
5117              */
5118             /* First zero everything else */
5119             memset(origOp, 0, ohbytes);
5120
5121             if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
5122                 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
5123             else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5124                 *((u_long *)(op + 8)) = onbytes;
5125             else
5126                 *((u_long *)(op + 60)) = onbytes;
5127             strcpy(origOp+ohbytes, dep->name);
5128             if (smb_StoreAnsiFilenames)
5129                 CharToOem(origOp+ohbytes, origOp+ohbytes);
5130
5131             /* Short name if requested and needed */
5132             if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
5133                 if (NeedShortName) {
5134                     strcpy(op + 70, shortName);
5135                     if (smb_StoreAnsiFilenames)
5136                         CharToOem(op + 70, op + 70);
5137                     *(op + 68) = (char)(shortNameEnd - shortName);
5138                 }
5139             }
5140
5141             /* now, adjust the # of entries copied */
5142             returnedNames++;
5143
5144             /* NextEntryOffset and FileIndex */
5145             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
5146                 int entryOffset = orbytes + align;
5147                 *((u_long *)op) = entryOffset;
5148                 *((u_long *)(op+4)) = nextEntryCookie;
5149             }
5150
5151             /* now we emit the attribute.  This is tricky, since
5152              * we need to really stat the file to find out what
5153              * type of entry we've got.  Right now, we're copying
5154              * out data from a buffer, while holding the scp
5155              * locked, so it isn't really convenient to stat
5156              * something now.  We'll put in a place holder
5157              * now, and make a second pass before returning this
5158              * to get the real attributes.  So, we just skip the
5159              * data for now, and adjust it later.  We allocate a
5160              * patch record to make it easy to find this point
5161              * later.  The replay will happen at a time when it is
5162              * safe to unlock the directory.
5163              */
5164             if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5165                 curPatchp = malloc(sizeof(*curPatchp));
5166                 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5167                           &curPatchp->q);
5168                 curPatchp->dptr = op;
5169                 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5170                     curPatchp->dptr += 8;
5171
5172                 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
5173                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5174                 }       
5175                 else    
5176                     curPatchp->flags = 0;
5177
5178                 curPatchp->fid.cell = scp->fid.cell;
5179                 curPatchp->fid.volume = scp->fid.volume;
5180                 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
5181                 curPatchp->fid.unique = ntohl(dep->fid.unique);
5182
5183                 /* temp */
5184                 curPatchp->dep = dep;
5185             }   
5186
5187             if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5188                 /* put out resume key */
5189                 *((u_long *)origOp) = nextEntryCookie;
5190
5191             /* Adjust byte ptr and count */
5192             origOp += orbytes;  /* skip entire record */
5193             bytesInBuffer += orbytes;
5194
5195             /* and pad the record out */
5196             while (--align >= 0) {
5197                 *origOp++ = 0;
5198                 bytesInBuffer++;
5199             }
5200         }       /* if we're including this name */
5201         else if (!starPattern &&
5202                  !foundInexact &&
5203                  dep->fid.vnode != 0 &&
5204                  smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
5205             /* We were looking for exact matches, but here's an inexact one*/
5206             foundInexact = 1;
5207         }
5208                 
5209       nextEntry:
5210         /* and adjust curOffset to be where the new cookie is */
5211         thyper.HighPart = 0;
5212         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5213         curOffset = LargeIntegerAdd(thyper, curOffset);
5214     } /* while copying data for dir listing */
5215
5216     /* If we didn't get a star pattern, we did an exact match during the first pass. 
5217      * If there were no exact matches found, we fail over to inexact matches by
5218      * marking the query as a star pattern (matches all case permutations), and
5219      * re-running the query. 
5220      */
5221     if (returnedNames == 0 && !starPattern && foundInexact) {
5222         osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5223         starPattern = 1;
5224         goto startsearch;
5225     }
5226
5227     /* release the mutex */
5228     lock_ReleaseMutex(&scp->mx);
5229     if (bufferp) {
5230         buf_Release(bufferp);
5231         bufferp = NULL;
5232     }
5233
5234     /* apply and free last set of patches; if not doing a star match, this
5235      * will be empty, but better safe (and freeing everything) than sorry.
5236      */
5237     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
5238                               &req);
5239         
5240     /* now put out the final parameters */
5241     if (returnedNames == 0) 
5242         eos = 1;
5243     if (p->opcode == 1) {
5244         /* find first */
5245         outp->parmsp[0] = (unsigned short) dsp->cookie;
5246         outp->parmsp[1] = returnedNames;
5247         outp->parmsp[2] = eos;
5248         outp->parmsp[3] = 0;            /* nothing wrong with EAS */
5249         outp->parmsp[4] = 0;    
5250         /* don't need last name to continue
5251          * search, cookie is enough.  Normally,
5252          * this is the offset of the file name
5253          * of the last entry returned.
5254          */
5255         outp->totalParms = 10;  /* in bytes */
5256     }
5257     else {
5258         /* find next */
5259         outp->parmsp[0] = returnedNames;
5260         outp->parmsp[1] = eos;
5261         outp->parmsp[2] = 0;    /* EAS error */
5262         outp->parmsp[3] = 0;    /* last name, as above */
5263         outp->totalParms = 8;   /* in bytes */
5264     }   
5265
5266     /* return # of bytes in the buffer */
5267     outp->totalData = bytesInBuffer;
5268
5269     /* Return error code if unsuccessful on first request */
5270     if (code == 0 && p->opcode == 1 && returnedNames == 0)
5271         code = CM_ERROR_NOSUCHFILE;
5272
5273     osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5274              p->opcode, dsp->cookie, returnedNames, code);
5275
5276     /* if we're supposed to close the search after this request, or if
5277      * we're supposed to close the search if we're done, and we're done,
5278      * or if something went wrong, close the search.
5279      */
5280     if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) || 
5281         (returnedNames == 0) ||
5282         ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) || 
5283         code != 0)
5284         smb_DeleteDirSearch(dsp);
5285
5286     if (code)
5287         smb_SendTran2Error(vcp, p, opx, code);
5288     else
5289         smb_SendTran2Packet(vcp, outp, opx);
5290
5291     smb_FreeTran2Packet(outp);
5292     smb_ReleaseDirSearch(dsp);
5293     cm_ReleaseSCache(scp);
5294     cm_ReleaseUser(userp);
5295     return 0;
5296 }
5297
5298 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5299 {
5300     int dirHandle;
5301     smb_dirSearch_t *dsp;
5302
5303     dirHandle = smb_GetSMBParm(inp, 0);
5304         
5305     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5306
5307     dsp = smb_FindDirSearch(dirHandle);
5308         
5309     if (!dsp)
5310         return CM_ERROR_BADFD;
5311         
5312     /* otherwise, we have an FD to destroy */
5313     smb_DeleteDirSearch(dsp);
5314     smb_ReleaseDirSearch(dsp);
5315         
5316     /* and return results */
5317     smb_SetSMBDataLength(outp, 0);
5318
5319     return 0;
5320 }
5321
5322 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5323 {
5324     smb_SetSMBDataLength(outp, 0);
5325     return 0;
5326 }
5327
5328 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5329 {
5330     char *pathp;
5331     long code = 0;
5332     cm_space_t *spacep;
5333     int excl;
5334     cm_user_t *userp;
5335     cm_scache_t *dscp;          /* dir we're dealing with */
5336     cm_scache_t *scp;           /* file we're creating */
5337     cm_attr_t setAttr;
5338     int initialModeBits;
5339     smb_fid_t *fidp;
5340     int attributes;
5341     char *lastNamep;
5342     afs_uint32 dosTime;
5343     int openFun;
5344     int trunc;
5345     int openMode;
5346     int extraInfo;
5347     int openAction;
5348     int parmSlot;                       /* which parm we're dealing with */
5349     char *tidPathp;
5350     cm_req_t req;
5351     int created = 0;
5352
5353     cm_InitReq(&req);
5354
5355     scp = NULL;
5356         
5357     extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5358     openFun = smb_GetSMBParm(inp, 8); /* open function */
5359     excl = ((openFun & 3) == 0);
5360     trunc = ((openFun & 3) == 2); /* truncate it */
5361     openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5362     openAction = 0;             /* tracks what we did */
5363
5364     attributes = smb_GetSMBParm(inp, 5);
5365     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5366
5367                                 /* compute initial mode bits based on read-only flag in attributes */
5368     initialModeBits = 0666;
5369     if (attributes & SMB_ATTR_READONLY) 
5370         initialModeBits &= ~0222;
5371         
5372     pathp = smb_GetSMBData(inp, NULL);
5373     if (smb_StoreAnsiFilenames)
5374         OemToChar(pathp,pathp);
5375
5376     spacep = inp->spacep;
5377     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5378
5379     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5380         /* special case magic file name for receiving IOCTL requests
5381          * (since IOCTL calls themselves aren't getting through).
5382          */
5383 #ifdef NOTSERVICE
5384         osi_Log0(smb_logp, "IOCTL Open");
5385 #endif
5386
5387         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5388         smb_SetupIoctlFid(fidp, spacep);
5389
5390         /* set inp->fid so that later read calls in same msg can find fid */
5391         inp->fid = fidp->fid;
5392         
5393         /* copy out remainder of the parms */
5394         parmSlot = 2;
5395         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5396         if (extraInfo) {
5397             smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5398             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* mod time */
5399             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5400             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* len */
5401             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5402             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5403             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5404             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5405         }   
5406         /* and the final "always present" stuff */
5407         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5408         /* next write out the "unique" ID */
5409         smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5410         smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5411         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5412         smb_SetSMBDataLength(outp, 0);
5413
5414         /* and clean up fid reference */
5415         smb_ReleaseFID(fidp);
5416         return 0;
5417     }
5418
5419 #ifdef DEBUG_VERBOSE
5420     {
5421         char *hexp, *asciip;
5422         asciip = (lastNamep ? lastNamep : pathp );
5423         hexp = osi_HexifyString(asciip);
5424         DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5425         free(hexp);
5426     }
5427 #endif
5428     userp = smb_GetUserFromVCP(vcp, inp);
5429
5430     dscp = NULL;
5431     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5432     if (code) {
5433         cm_ReleaseUser(userp);
5434         return CM_ERROR_NOSUCHPATH;
5435     }
5436     code = cm_NameI(cm_data.rootSCachep, pathp,
5437                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5438                     userp, tidPathp, &req, &scp);
5439
5440 #ifdef DFS_SUPPORT
5441     if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5442         cm_ReleaseSCache(scp);
5443         cm_ReleaseUser(userp);
5444         if ( WANTS_DFS_PATHNAMES(inp) )
5445             return CM_ERROR_PATH_NOT_COVERED;
5446         else
5447             return CM_ERROR_BADSHARENAME;
5448     }
5449 #endif /* DFS_SUPPORT */
5450
5451     if (code != 0) {
5452         code = cm_NameI(cm_data.rootSCachep, spacep->data,
5453                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5454                         userp, tidPathp, &req, &dscp);
5455         if (code) {
5456             cm_ReleaseUser(userp);
5457             return code;
5458         }
5459
5460 #ifdef DFS_SUPPORT
5461         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5462             cm_ReleaseSCache(dscp);
5463             cm_ReleaseUser(userp);
5464             if ( WANTS_DFS_PATHNAMES(inp) )
5465                 return CM_ERROR_PATH_NOT_COVERED;
5466             else
5467                 return CM_ERROR_BADSHARENAME;
5468         }
5469 #endif /* DFS_SUPPORT */
5470         /* otherwise, scp points to the parent directory.  Do a lookup,
5471          * and truncate the file if we find it, otherwise we create the
5472          * file.
5473          */
5474         if (!lastNamep) 
5475             lastNamep = pathp;
5476         else 
5477             lastNamep++;
5478         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5479                           &req, &scp);
5480         if (code && code != CM_ERROR_NOSUCHFILE) {
5481             cm_ReleaseSCache(dscp);
5482             cm_ReleaseUser(userp);
5483             return code;
5484         }
5485     }
5486         
5487     /* if we get here, if code is 0, the file exists and is represented by
5488      * scp.  Otherwise, we have to create it.  The dir may be represented
5489      * by dscp, or we may have found the file directly.  If code is non-zero,
5490      * scp is NULL.
5491      */
5492     if (code == 0) {
5493         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5494         if (code) {
5495             if (dscp) cm_ReleaseSCache(dscp);
5496             cm_ReleaseSCache(scp);
5497             cm_ReleaseUser(userp);
5498             return code;
5499         }
5500
5501         if (excl) {
5502             /* oops, file shouldn't be there */
5503             if (dscp) 
5504                 cm_ReleaseSCache(dscp);
5505             cm_ReleaseSCache(scp);
5506             cm_ReleaseUser(userp);
5507             return CM_ERROR_EXISTS;
5508         }
5509
5510         if (trunc) {
5511             setAttr.mask = CM_ATTRMASK_LENGTH;
5512             setAttr.length.LowPart = 0;
5513             setAttr.length.HighPart = 0;
5514             code = cm_SetAttr(scp, &setAttr, userp, &req);
5515             openAction = 3;     /* truncated existing file */
5516         }
5517         else openAction = 1;    /* found existing file */
5518     }
5519     else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5520         /* don't create if not found */
5521         if (dscp) cm_ReleaseSCache(dscp);
5522         cm_ReleaseUser(userp);
5523         return CM_ERROR_NOSUCHFILE;
5524     }
5525     else {
5526         osi_assert(dscp != NULL);
5527         osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5528                  osi_LogSaveString(smb_logp, lastNamep));
5529         openAction = 2; /* created file */
5530         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5531         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5532         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5533                          &req);
5534         if (code == 0) {
5535             created = 1;
5536             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5537                 smb_NotifyChange(FILE_ACTION_ADDED,
5538                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5539                                  dscp, lastNamep, NULL, TRUE);
5540         } else if (!excl && code == CM_ERROR_EXISTS) {
5541             /* not an exclusive create, and someone else tried
5542              * creating it already, then we open it anyway.  We
5543              * don't bother retrying after this, since if this next
5544              * fails, that means that the file was deleted after we
5545              * started this call.
5546              */
5547             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5548                              userp, &req, &scp);
5549             if (code == 0) {
5550                 if (trunc) {
5551                     setAttr.mask = CM_ATTRMASK_LENGTH;
5552                     setAttr.length.LowPart = 0;
5553                     setAttr.length.HighPart = 0;
5554                     code = cm_SetAttr(scp, &setAttr, userp, &req);
5555                 }   
5556             }   /* lookup succeeded */
5557         }
5558     }
5559         
5560     /* we don't need this any longer */
5561     if (dscp) 
5562         cm_ReleaseSCache(dscp);
5563
5564     if (code) {
5565         /* something went wrong creating or truncating the file */
5566         if (scp) 
5567             cm_ReleaseSCache(scp);
5568         cm_ReleaseUser(userp);
5569         return code;
5570     }
5571         
5572     /* make sure we're about to open a file */
5573     if (scp->fileType != CM_SCACHETYPE_FILE) {
5574         cm_ReleaseSCache(scp);
5575         cm_ReleaseUser(userp);
5576         return CM_ERROR_ISDIR;
5577     }
5578
5579     /* now all we have to do is open the file itself */
5580     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5581     osi_assert(fidp);
5582         
5583     cm_HoldUser(userp);
5584     lock_ObtainMutex(&fidp->mx);
5585     /* save a pointer to the vnode */
5586     fidp->scp = scp;
5587     lock_ObtainMutex(&scp->mx);
5588     scp->flags |= CM_SCACHEFLAG_SMB_FID;
5589     lock_ReleaseMutex(&scp->mx);
5590     osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5591     /* also the user */
5592     fidp->userp = userp;
5593         
5594     /* compute open mode */
5595     if (openMode != 1) 
5596         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5597     if (openMode == 1 || openMode == 2)
5598         fidp->flags |= SMB_FID_OPENWRITE;
5599
5600     /* remember if the file was newly created */
5601     if (created)
5602         fidp->flags |= SMB_FID_CREATED;
5603
5604     lock_ReleaseMutex(&fidp->mx);
5605     smb_ReleaseFID(fidp);
5606         
5607     cm_Open(scp, 0, userp);
5608
5609     /* set inp->fid so that later read calls in same msg can find fid */
5610     inp->fid = fidp->fid;
5611         
5612     /* copy out remainder of the parms */
5613     parmSlot = 2;
5614     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5615     lock_ObtainMutex(&scp->mx);
5616     if (extraInfo) {
5617         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5618         smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5619         smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5620         smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5621         smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5622         smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5623         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5624         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5625         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5626     }
5627     /* and the final "always present" stuff */
5628     smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5629     /* next write out the "unique" ID */
5630     smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5631     smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5632     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5633     lock_ReleaseMutex(&scp->mx);
5634     smb_SetSMBDataLength(outp, 0);
5635
5636     osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5637
5638     cm_ReleaseUser(userp);
5639     /* leave scp held since we put it in fidp->scp */
5640     return 0;
5641 }       
5642
5643 static void smb_GetLockParams(unsigned char LockType, 
5644                               char ** buf, 
5645                               unsigned int * ppid, 
5646                               LARGE_INTEGER * pOffset, 
5647                               LARGE_INTEGER * pLength)
5648 {
5649     if (LockType & LOCKING_ANDX_LARGE_FILES) {
5650         /* Large Files */
5651         *ppid = *((USHORT *) *buf);
5652         pOffset->HighPart = *((LONG *)(*buf + 4));
5653         pOffset->LowPart = *((DWORD *)(*buf + 8));
5654         pLength->HighPart = *((LONG *)(*buf + 12));
5655         pLength->LowPart = *((DWORD *)(*buf + 16));
5656         *buf += 20;
5657     }
5658     else {
5659         /* Not Large Files */
5660         *ppid = *((USHORT *) *buf);
5661         pOffset->HighPart = 0;
5662         pOffset->LowPart = *((DWORD *)(*buf + 2));
5663         pLength->HighPart = 0;
5664         pLength->LowPart = *((DWORD *)(*buf + 6));
5665         *buf += 10;
5666     }
5667 }
5668
5669 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5670 {
5671     cm_req_t req;
5672     cm_user_t *userp;
5673     unsigned short fid;
5674     smb_fid_t *fidp;
5675     cm_scache_t *scp;
5676     unsigned char LockType;
5677     unsigned short NumberOfUnlocks, NumberOfLocks;
5678     long Timeout;
5679     char *op;
5680     char *op_locks;
5681     LARGE_INTEGER LOffset, LLength;
5682     smb_waitingLockRequest_t *wlRequest = NULL;
5683     cm_file_lock_t *lockp;
5684     long code = 0;
5685     int i;
5686     cm_key_t key;
5687     unsigned int pid;
5688
5689     cm_InitReq(&req);
5690
5691     fid = smb_GetSMBParm(inp, 2);
5692     fid = smb_ChainFID(fid, inp);
5693
5694     fidp = smb_FindFID(vcp, fid, 0);
5695     if (!fidp)
5696         return CM_ERROR_BADFD;
5697     
5698     lock_ObtainMutex(&fidp->mx);
5699     if (fidp->flags & SMB_FID_IOCTL) {
5700         osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5701         lock_ReleaseMutex(&fidp->mx);
5702         smb_ReleaseFID(fidp);
5703         return CM_ERROR_BADFD;
5704     }
5705     scp = fidp->scp;
5706     osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5707     cm_HoldSCache(scp);
5708     lock_ReleaseMutex(&fidp->mx);
5709
5710     /* set inp->fid so that later read calls in same msg can find fid */
5711     inp->fid = fid;
5712
5713     userp = smb_GetUserFromVCP(vcp, inp);
5714
5715
5716     lock_ObtainMutex(&scp->mx);
5717     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5718                       CM_SCACHESYNC_NEEDCALLBACK
5719                          | CM_SCACHESYNC_GETSTATUS
5720                          | CM_SCACHESYNC_LOCK);
5721     if (code) {
5722         osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5723         goto doneSync;
5724     }
5725
5726     LockType = smb_GetSMBParm(inp, 3) & 0xff;
5727     Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5728     NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5729     NumberOfLocks = smb_GetSMBParm(inp, 7);
5730
5731     if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5732         (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5733
5734         /* We don't support these requests.  Apparently, we can safely
5735            not deal with them too. */
5736         osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5737                  ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5738                   "LOCKING_ANDX_CANCEL_LOCK":
5739                   "LOCKING_ANDX_CHANGE_LOCKTYPE")); 
5740         /* No need to call osi_LogSaveString since these are string
5741            constants.*/
5742
5743         code = CM_ERROR_BADOP;
5744         goto done;
5745
5746     }
5747
5748     op = smb_GetSMBData(inp, NULL);
5749
5750     for (i=0; i<NumberOfUnlocks; i++) {
5751         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5752
5753         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5754
5755         code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5756
5757         if (code) 
5758             goto done;
5759     }
5760
5761     op_locks = op;
5762
5763     for (i=0; i<NumberOfLocks; i++) {
5764         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5765
5766         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5767
5768         code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5769                         userp, &req, &lockp);
5770
5771         if (code == CM_ERROR_NOACCESS && LockType == LockWrite && 
5772             (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
5773         {
5774             code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
5775                             userp, &req, &lockp);
5776         }
5777
5778         if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5779             smb_waitingLock_t * wLock;
5780
5781             /* Put on waiting list */
5782             if(wlRequest == NULL) {
5783                 int j;
5784                 char * opt;
5785                 cm_key_t tkey;
5786                 LARGE_INTEGER tOffset, tLength;
5787
5788                 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5789
5790                 osi_assert(wlRequest != NULL);
5791
5792                 wlRequest->vcp = vcp;
5793                 smb_HoldVC(vcp);
5794                 wlRequest->scp = scp;
5795                 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
5796                 cm_HoldSCache(scp);
5797                 wlRequest->inp = smb_CopyPacket(inp);
5798                 wlRequest->outp = smb_CopyPacket(outp);
5799                 wlRequest->lockType = LockType;
5800                 wlRequest->timeRemaining = Timeout;
5801                 wlRequest->locks = NULL;
5802
5803                 /* The waiting lock request needs to have enough
5804                    information to undo all the locks in the request.
5805                    We do the following to store info about locks that
5806                    have already been granted.  Sure, we can get most
5807                    of the info from the packet, but the packet doesn't
5808                    hold the result of cm_Lock call.  In practice we
5809                    only receive packets with one or two locks, so we
5810                    are only wasting a few bytes here and there and
5811                    only for a limited period of time until the waiting
5812                    lock times out or is freed. */
5813
5814                 for(opt = op_locks, j=i; j > 0; j--) {
5815                     smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5816
5817                     tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5818
5819                     wLock = malloc(sizeof(smb_waitingLock_t));
5820
5821                     osi_assert(wLock != NULL);
5822
5823                     wLock->key = tkey;
5824                     wLock->LOffset = tOffset;
5825                     wLock->LLength = tLength;
5826                     wLock->lockp = NULL;
5827                     wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5828                     osi_QAdd((osi_queue_t **) &wlRequest->locks,
5829                              &wLock->q);
5830                 }
5831             }
5832
5833             wLock = malloc(sizeof(smb_waitingLock_t));
5834
5835             osi_assert(wLock != NULL);
5836
5837             wLock->key = key;
5838             wLock->LOffset = LOffset;
5839             wLock->LLength = LLength;
5840             wLock->lockp = lockp;
5841             wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5842             osi_QAdd((osi_queue_t **) &wlRequest->locks,
5843                      &wLock->q);
5844
5845             osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5846                      wLock);
5847
5848             code = 0;
5849             continue;
5850         }
5851
5852         if (code) {
5853             osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5854             break;
5855         }
5856     }
5857
5858     if (code) {
5859
5860         /* Since something went wrong with the lock number i, we now
5861            have to go ahead and release any locks acquired before the
5862            failure.  All locks before lock number i (of which there
5863            are i of them) have either been successful or are waiting.
5864            Either case requires calling cm_Unlock(). */
5865
5866         /* And purge the waiting lock */
5867         if(wlRequest != NULL) {
5868             smb_waitingLock_t * wl;
5869             smb_waitingLock_t * wlNext;
5870             long ul_code;
5871
5872             for(wl = wlRequest->locks; wl; wl = wlNext) {
5873
5874                 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5875
5876                 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5877                 
5878                 if(ul_code != 0) {
5879                     osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5880                 } else {
5881                     osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5882                 }
5883
5884                 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5885                 free(wl);
5886
5887             }
5888
5889             smb_ReleaseVC(wlRequest->vcp);
5890             cm_ReleaseSCache(wlRequest->scp);
5891             smb_FreePacket(wlRequest->inp);
5892             smb_FreePacket(wlRequest->outp);
5893
5894             free(wlRequest);
5895
5896             wlRequest = NULL;
5897         }
5898
5899     } else {
5900
5901         if (wlRequest != NULL) {
5902
5903             lock_ObtainWrite(&smb_globalLock);
5904             osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5905                      &wlRequest->q);
5906             osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5907             lock_ReleaseWrite(&smb_globalLock);
5908
5909             /* don't send reply immediately */
5910             outp->flags |= SMB_PACKETFLAG_NOSEND;
5911         }
5912
5913         smb_SetSMBDataLength(outp, 0);
5914     }
5915
5916   done:   
5917     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5918
5919   doneSync:
5920     lock_ReleaseMutex(&scp->mx);
5921     cm_ReleaseSCache(scp);
5922     cm_ReleaseUser(userp);
5923     smb_ReleaseFID(fidp);
5924
5925     return code;
5926 }
5927
5928 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5929 {
5930     unsigned short fid;
5931     smb_fid_t *fidp;
5932     cm_scache_t *scp;
5933     long code = 0;
5934     afs_uint32 searchTime;
5935     cm_user_t *userp;
5936     cm_req_t req;
5937
5938     cm_InitReq(&req);
5939
5940     fid = smb_GetSMBParm(inp, 0);
5941     fid = smb_ChainFID(fid, inp);
5942         
5943     fidp = smb_FindFID(vcp, fid, 0);
5944     if (!fidp)
5945         return CM_ERROR_BADFD;
5946     
5947     lock_ObtainMutex(&fidp->mx);
5948     if (fidp->flags & SMB_FID_IOCTL) {
5949         lock_ReleaseMutex(&fidp->mx);
5950         smb_ReleaseFID(fidp);
5951         return CM_ERROR_BADFD;
5952     }
5953     scp = fidp->scp;
5954     osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
5955     cm_HoldSCache(scp);
5956     lock_ReleaseMutex(&fidp->mx);
5957         
5958     userp = smb_GetUserFromVCP(vcp, inp);
5959         
5960         
5961     /* otherwise, stat the file */
5962     lock_ObtainMutex(&scp->mx);
5963     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5964                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5965     if (code) 
5966         goto done;
5967
5968     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5969
5970     /* decode times.  We need a search time, but the response to this
5971      * call provides the date first, not the time, as returned in the
5972      * searchTime variable.  So we take the high-order bits first.
5973      */
5974     smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5975     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);       /* ctime */
5976     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5977     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);       /* atime */
5978     smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5979     smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);       /* mtime */
5980     smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5981
5982     /* now handle file size and allocation size */
5983     smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);              /* file size */
5984     smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5985     smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);              /* alloc size */
5986     smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5987
5988     /* file attribute */
5989     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5990         
5991     /* and finalize stuff */
5992     smb_SetSMBDataLength(outp, 0);
5993     code = 0;
5994
5995   done:
5996     lock_ReleaseMutex(&scp->mx);
5997     cm_ReleaseSCache(scp);
5998     cm_ReleaseUser(userp);
5999     smb_ReleaseFID(fidp);
6000     return code;
6001 }       
6002
6003 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6004 {
6005     unsigned short fid;
6006     smb_fid_t *fidp;
6007     cm_scache_t *scp;
6008     long code = 0;
6009     afs_uint32 searchTime;
6010     time_t unixTime;
6011     cm_user_t *userp;
6012     cm_attr_t attrs;
6013     cm_req_t req;
6014
6015     cm_InitReq(&req);
6016
6017     fid = smb_GetSMBParm(inp, 0);
6018     fid = smb_ChainFID(fid, inp);
6019         
6020     fidp = smb_FindFID(vcp, fid, 0);
6021     if (!fidp)
6022         return CM_ERROR_BADFD;
6023     
6024     lock_ObtainMutex(&fidp->mx);
6025     if (fidp->flags & SMB_FID_IOCTL) {
6026         lock_ReleaseMutex(&fidp->mx);
6027         smb_ReleaseFID(fidp);
6028         return CM_ERROR_BADFD;
6029     }
6030     scp = fidp->scp;
6031     osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6032     cm_HoldSCache(scp);
6033     lock_ReleaseMutex(&fidp->mx);
6034         
6035     userp = smb_GetUserFromVCP(vcp, inp);
6036         
6037         
6038     /* now prepare to call cm_setattr.  This message only sets various times,
6039      * and AFS only implements mtime, and we'll set the mtime if that's
6040      * requested.  The others we'll ignore.
6041      */
6042     searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6043         
6044     if (searchTime != 0) {
6045         smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6046
6047         if ( unixTime != -1 ) {
6048             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6049             attrs.clientModTime = unixTime;
6050             code = cm_SetAttr(scp, &attrs, userp, &req);
6051
6052             osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6053         } else {
6054             osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6055         }
6056     }
6057     else 
6058         code = 0;
6059
6060     cm_ReleaseSCache(scp);
6061     cm_ReleaseUser(userp);
6062     smb_ReleaseFID(fidp);
6063     return code;
6064 }
6065
6066 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6067 {
6068     osi_hyper_t offset;
6069     long count, written = 0, total_written = 0;
6070     unsigned short fd;
6071     unsigned pid;
6072     smb_fid_t *fidp;
6073     long code = 0;
6074     cm_user_t *userp;
6075     char *op;
6076     int inDataBlockCount;
6077
6078     fd = smb_GetSMBParm(inp, 2);
6079     count = smb_GetSMBParm(inp, 10);
6080
6081     offset.HighPart = 0;
6082     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6083
6084     if (*inp->wctp == 14) {
6085         /* we have a request with 64-bit file offsets */
6086 #ifdef AFS_LARGEFILES
6087         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6088 #else
6089         if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6090             /* uh oh */
6091             osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6092             /* we shouldn't have received this op if we didn't specify
6093                largefile support */
6094             return CM_ERROR_BADOP;
6095         }
6096 #endif
6097     }
6098
6099     op = inp->data + smb_GetSMBParm(inp, 11);
6100     inDataBlockCount = count;
6101
6102     osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6103              fd, offset.HighPart, offset.LowPart, count);
6104         
6105     fd = smb_ChainFID(fd, inp);
6106     fidp = smb_FindFID(vcp, fd, 0);
6107     if (!fidp)
6108         return CM_ERROR_BADFD;
6109         
6110     lock_ObtainMutex(&fidp->mx);
6111     if (fidp->flags & SMB_FID_IOCTL) {
6112         lock_ReleaseMutex(&fidp->mx);
6113         code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6114         smb_ReleaseFID(fidp);
6115         return code;
6116     }
6117     lock_ReleaseMutex(&fidp->mx);
6118     userp = smb_GetUserFromVCP(vcp, inp);
6119
6120     /* special case: 0 bytes transferred means there is no data
6121        transferred.  A slight departure from SMB_COM_WRITE where this
6122        means that we are supposed to truncate the file at this
6123        position. */
6124
6125     {
6126         cm_key_t key;
6127         LARGE_INTEGER LOffset;
6128         LARGE_INTEGER LLength;
6129
6130         pid = ((smb_t *) inp)->pid;
6131         key = cm_GenerateKey(vcp->vcID, pid, fd);
6132
6133         LOffset.HighPart = offset.HighPart;
6134         LOffset.LowPart = offset.LowPart;
6135         LLength.HighPart = 0;
6136         LLength.LowPart = count;
6137
6138         lock_ObtainMutex(&fidp->scp->mx);
6139         code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6140         lock_ReleaseMutex(&fidp->scp->mx);
6141
6142         if (code)
6143             goto done;
6144     }
6145
6146     /*
6147      * Work around bug in NT client
6148      *
6149      * When copying a file, the NT client should first copy the data,
6150      * then copy the last write time.  But sometimes the NT client does
6151      * these in the wrong order, so the data copies would inadvertently
6152      * cause the last write time to be overwritten.  We try to detect this,
6153      * and don't set client mod time if we think that would go against the
6154      * intention.
6155      */
6156     lock_ObtainMutex(&fidp->mx);
6157     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6158         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6159         fidp->scp->clientModTime = time(NULL);
6160     }
6161     lock_ReleaseMutex(&fidp->mx);
6162
6163     code = 0;
6164     while ( code == 0 && count > 0 ) {
6165 #ifndef DJGPP
6166         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6167 #else /* DJGPP */
6168         code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
6169 #endif /* !DJGPP */
6170         if (code == 0 && written == 0)
6171             code = CM_ERROR_PARTIALWRITE;
6172
6173         offset = LargeIntegerAdd(offset,
6174                                  ConvertLongToLargeInteger(written));
6175         count -= written;
6176         total_written += written;
6177         written = 0;
6178     }
6179
6180  done_writing:
6181     
6182     /* slots 0 and 1 are reserved for request chaining and will be
6183        filled in when we return. */
6184     smb_SetSMBParm(outp, 2, total_written);
6185     smb_SetSMBParm(outp, 3, 0); /* reserved */
6186     smb_SetSMBParm(outp, 4, 0); /* reserved */
6187     smb_SetSMBParm(outp, 5, 0); /* reserved */
6188     smb_SetSMBDataLength(outp, 0);
6189
6190  done:
6191     cm_ReleaseUser(userp);
6192     smb_ReleaseFID(fidp);
6193
6194     return code;
6195 }
6196
6197 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6198 {
6199     osi_hyper_t offset;
6200     long count;
6201     long finalCount = 0;
6202     unsigned short fd;
6203     unsigned pid;
6204     smb_fid_t *fidp;
6205     long code = 0;
6206     cm_user_t *userp;
6207     cm_key_t key;
6208     char *op;
6209         
6210     fd = smb_GetSMBParm(inp, 2);
6211     count = smb_GetSMBParm(inp, 5);
6212     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6213
6214     if (*inp->wctp == 12) {
6215         /* a request with 64-bit offsets */
6216 #ifdef AFS_LARGEFILES
6217         offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6218
6219         if (LargeIntegerLessThanZero(offset)) {
6220             osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6221                      offset.HighPart, offset.LowPart);
6222             return CM_ERROR_BADSMB;
6223         }
6224 #else
6225         if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6226             osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit.  Dropping");
6227             return CM_ERROR_BADSMB;
6228         } else {
6229             offset.HighPart = 0;
6230         }
6231 #endif
6232     } else {
6233         offset.HighPart = 0;
6234     }
6235
6236     osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6237              fd, offset.HighPart, offset.LowPart, count);
6238
6239     fd = smb_ChainFID(fd, inp);
6240     fidp = smb_FindFID(vcp, fd, 0);
6241     if (!fidp) {
6242         return CM_ERROR_BADFD;
6243     }
6244
6245     pid = ((smb_t *) inp)->pid;
6246     key = cm_GenerateKey(vcp->vcID, pid, fd);
6247     {
6248         LARGE_INTEGER LOffset, LLength;
6249
6250         LOffset.HighPart = offset.HighPart;
6251         LOffset.LowPart = offset.LowPart;
6252         LLength.HighPart = 0;
6253         LLength.LowPart = count;
6254
6255         lock_ObtainMutex(&fidp->scp->mx);
6256         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6257         lock_ReleaseMutex(&fidp->scp->mx);
6258     }
6259
6260     if (code) {
6261         smb_ReleaseFID(fidp);
6262         return code;
6263     }
6264
6265     /* set inp->fid so that later read calls in same msg can find fid */
6266     inp->fid = fd;
6267
6268     lock_ObtainMutex(&fidp->mx);
6269     if (fidp->flags & SMB_FID_IOCTL) {
6270         lock_ReleaseMutex(&fidp->mx);
6271         code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6272         smb_ReleaseFID(fidp);
6273         return code;
6274     }
6275     lock_ReleaseMutex(&fidp->mx);
6276
6277     userp = smb_GetUserFromVCP(vcp, inp);
6278
6279     /* 0 and 1 are reserved for request chaining, were setup by our caller,
6280      * and will be further filled in after we return.
6281      */
6282     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6283     smb_SetSMBParm(outp, 3, 0); /* resvd */
6284     smb_SetSMBParm(outp, 4, 0); /* resvd */
6285     smb_SetSMBParm(outp, 5, count);     /* # of bytes we're going to read */
6286     /* fill in #6 when we have all the parameters' space reserved */
6287     smb_SetSMBParm(outp, 7, 0); /* resv'd */
6288     smb_SetSMBParm(outp, 8, 0); /* resv'd */
6289     smb_SetSMBParm(outp, 9, 0); /* resv'd */
6290     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
6291     smb_SetSMBParm(outp, 11, 0);        /* reserved */
6292
6293     /* get op ptr after putting in the parms, since otherwise we don't
6294      * know where the data really is.
6295      */
6296     op = smb_GetSMBData(outp, NULL);
6297         
6298     /* now fill in offset from start of SMB header to first data byte (to op) */
6299     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6300
6301     /* set the packet data length the count of the # of bytes */
6302     smb_SetSMBDataLength(outp, count);
6303
6304 #ifndef DJGPP
6305     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6306 #else /* DJGPP */
6307     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
6308 #endif /* !DJGPP */
6309
6310     /* fix some things up */
6311     smb_SetSMBParm(outp, 5, finalCount);
6312     smb_SetSMBDataLength(outp, finalCount);
6313
6314     cm_ReleaseUser(userp);
6315     smb_ReleaseFID(fidp);
6316     return code;
6317 }   
6318         
6319 /*
6320  * Values for createDisp, copied from NTDDK.H
6321  */
6322 #define  FILE_SUPERSEDE 0       // (???)
6323 #define  FILE_OPEN      1       // (open)
6324 #define  FILE_CREATE    2       // (exclusive)
6325 #define  FILE_OPEN_IF   3       // (non-exclusive)
6326 #define  FILE_OVERWRITE 4       // (open & truncate, but do not create)
6327 #define  FILE_OVERWRITE_IF 5    // (open & truncate, or create)
6328
6329 /* Flags field */
6330 #define REQUEST_OPLOCK 2
6331 #define REQUEST_BATCH_OPLOCK 4
6332 #define OPEN_DIRECTORY 8
6333 #define EXTENDED_RESPONSE_REQUIRED 0x10
6334
6335 /* CreateOptions field. */
6336 #define FILE_DIRECTORY_FILE       0x0001
6337 #define FILE_WRITE_THROUGH        0x0002
6338 #define FILE_SEQUENTIAL_ONLY      0x0004
6339 #define FILE_NON_DIRECTORY_FILE   0x0040
6340 #define FILE_NO_EA_KNOWLEDGE      0x0200
6341 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6342 #define FILE_RANDOM_ACCESS        0x0800
6343 #define FILE_DELETE_ON_CLOSE      0x1000
6344 #define FILE_OPEN_BY_FILE_ID      0x2000
6345
6346 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6347 {
6348     char *pathp, *realPathp;
6349     long code = 0;
6350     cm_space_t *spacep;
6351     cm_user_t *userp;
6352     cm_scache_t *dscp;          /* parent dir */
6353     cm_scache_t *scp;           /* file to create or open */
6354     cm_scache_t *targetScp;     /* if scp is a symlink */
6355     cm_attr_t setAttr;
6356     char *lastNamep;
6357     char *treeStartp;
6358     unsigned short nameLength;
6359     unsigned int flags;
6360     unsigned int requestOpLock;
6361     unsigned int requestBatchOpLock;
6362     unsigned int mustBeDir;
6363     unsigned int extendedRespRequired;
6364     unsigned int treeCreate;
6365     int realDirFlag;
6366     unsigned int desiredAccess;
6367     unsigned int extAttributes;
6368     unsigned int createDisp;
6369     unsigned int createOptions;
6370     unsigned int shareAccess;
6371     int initialModeBits;
6372     unsigned short baseFid;
6373     smb_fid_t *baseFidp;
6374     smb_fid_t *fidp;
6375     cm_scache_t *baseDirp;
6376     unsigned short openAction;
6377     int parmSlot;
6378     long fidflags;
6379     FILETIME ft;
6380     LARGE_INTEGER sz;
6381     char *tidPathp;
6382     BOOL foundscp;
6383     cm_req_t req;
6384     int created = 0;
6385     cm_lock_data_t *ldp = NULL;                                                                        
6386
6387     cm_InitReq(&req);
6388
6389     /* This code is very long and has a lot of if-then-else clauses
6390      * scp and dscp get reused frequently and we need to ensure that 
6391      * we don't lose a reference.  Start by ensuring that they are NULL.
6392      */
6393     scp = NULL;
6394     dscp = NULL;
6395     treeCreate = FALSE;
6396     foundscp = FALSE;
6397
6398     nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6399     flags = smb_GetSMBOffsetParm(inp, 3, 1)
6400         | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6401     requestOpLock = flags & REQUEST_OPLOCK;
6402     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6403     mustBeDir = flags & OPEN_DIRECTORY;
6404     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6405
6406     /*
6407      * Why all of a sudden 32-bit FID?
6408      * We will reject all bits higher than 16.
6409      */
6410     if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6411         return CM_ERROR_INVAL;
6412     baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6413     desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6414         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6415     extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6416         | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6417     shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6418         | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6419     createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6420         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6421     createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6422         | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6423
6424     /* mustBeDir is never set; createOptions directory bit seems to be
6425      * more important
6426      */
6427     if (createOptions & FILE_DIRECTORY_FILE)
6428         realDirFlag = 1;
6429     else if (createOptions & FILE_NON_DIRECTORY_FILE)
6430         realDirFlag = 0;
6431     else
6432         realDirFlag = -1;
6433
6434     /*
6435      * compute initial mode bits based on read-only flag in
6436      * extended attributes
6437      */
6438     initialModeBits = 0666;
6439     if (extAttributes & SMB_ATTR_READONLY) 
6440         initialModeBits &= ~0222;
6441
6442     pathp = smb_GetSMBData(inp, NULL);
6443     /* Sometimes path is not null-terminated, so we make a copy. */
6444     realPathp = malloc(nameLength+1);
6445     memcpy(realPathp, pathp, nameLength);
6446     realPathp[nameLength] = 0;
6447     if (smb_StoreAnsiFilenames)
6448         OemToChar(realPathp,realPathp);
6449
6450     spacep = inp->spacep;
6451     smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6452
6453     osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
6454     osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6455     osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
6456
6457     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
6458         /* special case magic file name for receiving IOCTL requests
6459          * (since IOCTL calls themselves aren't getting through).
6460          */
6461         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6462         smb_SetupIoctlFid(fidp, spacep);
6463         osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6464
6465         /* set inp->fid so that later read calls in same msg can find fid */
6466         inp->fid = fidp->fid;
6467
6468         /* out parms */
6469         parmSlot = 2;
6470         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
6471         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6472         smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6473         /* times */
6474         memset(&ft, 0, sizeof(ft));
6475         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6476         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6477         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6478         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6479         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6480         sz.HighPart = 0x7fff; sz.LowPart = 0;
6481         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6482         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6483         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
6484         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
6485         smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
6486         smb_SetSMBDataLength(outp, 0);
6487
6488         /* clean up fid reference */
6489         smb_ReleaseFID(fidp);
6490         free(realPathp);
6491         return 0;
6492     }
6493
6494 #ifdef DEBUG_VERBOSE
6495     {
6496         char *hexp, *asciip;
6497         asciip = (lastNamep? lastNamep : realPathp);
6498         hexp = osi_HexifyString( asciip );
6499         DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6500         free(hexp);
6501     }
6502 #endif
6503
6504     userp = smb_GetUserFromVCP(vcp, inp);
6505     if (!userp) {
6506         osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6507         free(realPathp);
6508         return CM_ERROR_INVAL;
6509     }
6510
6511     if (baseFid == 0) {
6512         baseFidp = NULL;
6513         baseDirp = cm_data.rootSCachep;
6514         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6515         if (code == CM_ERROR_TIDIPC) {
6516             /* Attempt to use a TID allocated for IPC.  The client
6517              * is probably looking for DCE RPC end points which we
6518              * don't support OR it could be looking to make a DFS
6519              * referral request. 
6520              */
6521             osi_Log0(smb_logp, "NTCreateX received IPC TID");
6522 #ifndef DFS_SUPPORT
6523             free(realPathp);
6524             cm_ReleaseUser(userp);
6525             return CM_ERROR_NOSUCHFILE;
6526 #endif /* DFS_SUPPORT */
6527         }
6528     } else {
6529         baseFidp = smb_FindFID(vcp, baseFid, 0);
6530         if (!baseFidp) {
6531             osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6532             free(realPathp);
6533             cm_ReleaseUser(userp);
6534             return CM_ERROR_INVAL;
6535         }       
6536         baseDirp = baseFidp->scp;
6537         tidPathp = NULL;
6538     }
6539
6540     osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6541
6542     /* compute open mode */
6543     fidflags = 0;
6544     if (desiredAccess & DELETE)
6545         fidflags |= SMB_FID_OPENDELETE;
6546     if (desiredAccess & AFS_ACCESS_READ)
6547         fidflags |= SMB_FID_OPENREAD_LISTDIR;
6548     if (desiredAccess & AFS_ACCESS_WRITE)
6549         fidflags |= SMB_FID_OPENWRITE;
6550     if (createOptions & FILE_DELETE_ON_CLOSE)
6551         fidflags |= SMB_FID_DELONCLOSE;
6552     if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6553         fidflags |= SMB_FID_SEQUENTIAL;
6554     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6555         fidflags |= SMB_FID_RANDOM;
6556
6557     /* and the share mode */
6558     if (shareAccess & FILE_SHARE_READ)
6559         fidflags |= SMB_FID_SHARE_READ;
6560     if (shareAccess & FILE_SHARE_WRITE)
6561         fidflags |= SMB_FID_SHARE_WRITE;
6562
6563     osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6564     code = 0;
6565
6566     /* For an exclusive create, we want to do a case sensitive match for the last component. */
6567     if ( createDisp == FILE_CREATE || 
6568          createDisp == FILE_OVERWRITE ||
6569          createDisp == FILE_OVERWRITE_IF) {
6570         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6571                         userp, tidPathp, &req, &dscp);
6572         if (code == 0) {
6573 #ifdef DFS_SUPPORT
6574             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6575                 cm_ReleaseSCache(dscp);
6576                 cm_ReleaseUser(userp);
6577                 free(realPathp);
6578                 if (baseFidp) 
6579                     smb_ReleaseFID(baseFidp);
6580                 if ( WANTS_DFS_PATHNAMES(inp) )
6581                     return CM_ERROR_PATH_NOT_COVERED;
6582                 else
6583                     return CM_ERROR_BADSHARENAME;
6584             }
6585 #endif /* DFS_SUPPORT */
6586             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6587                              userp, &req, &scp);
6588             if (code == CM_ERROR_NOSUCHFILE) {
6589                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
6590                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6591                 if (code == 0 && realDirFlag == 1) {
6592                     cm_ReleaseSCache(scp);
6593                     cm_ReleaseSCache(dscp);
6594                     cm_ReleaseUser(userp);
6595                     free(realPathp);
6596                     if (baseFidp) 
6597                         smb_ReleaseFID(baseFidp);
6598                     return CM_ERROR_EXISTS;
6599                 }
6600             }
6601         }
6602         /* we have both scp and dscp */
6603     } else {
6604         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6605                         userp, tidPathp, &req, &scp);
6606 #ifdef DFS_SUPPORT
6607         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6608             cm_ReleaseSCache(scp);
6609             cm_ReleaseUser(userp);
6610             free(realPathp);
6611             if (baseFidp) 
6612                 smb_ReleaseFID(baseFidp);
6613             if ( WANTS_DFS_PATHNAMES(inp) )
6614                 return CM_ERROR_PATH_NOT_COVERED;
6615             else
6616                 return CM_ERROR_BADSHARENAME;
6617         }
6618 #endif /* DFS_SUPPORT */
6619         /* we might have scp but not dscp */
6620     }
6621
6622     if (scp)
6623         foundscp = TRUE;
6624     
6625     if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6626         /* look up parent directory */
6627         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6628          * the immediate parent.  We have to work our way up realPathp until we hit something that we
6629          * recognize.
6630          */
6631
6632         /* we might or might not have scp */
6633
6634         if (dscp == NULL) {
6635             do {
6636                 char *tp;
6637
6638                 code = cm_NameI(baseDirp, spacep->data,
6639                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6640                              userp, tidPathp, &req, &dscp);
6641
6642 #ifdef DFS_SUPPORT
6643                 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6644                     if (scp)
6645                         cm_ReleaseSCache(scp);
6646                     cm_ReleaseSCache(dscp);
6647                     cm_ReleaseUser(userp);
6648                     free(realPathp);
6649                     if (baseFidp) 
6650                         smb_ReleaseFID(baseFidp);
6651                     if ( WANTS_DFS_PATHNAMES(inp) )
6652                         return CM_ERROR_PATH_NOT_COVERED;
6653                     else
6654                         return CM_ERROR_BADSHARENAME;
6655                 }
6656 #endif /* DFS_SUPPORT */
6657
6658                 if (code && 
6659                      (tp = strrchr(spacep->data,'\\')) &&
6660                      (createDisp == FILE_CREATE) &&
6661                      (realDirFlag == 1)) {
6662                     *tp++ = 0;
6663                     treeCreate = TRUE;
6664                     treeStartp = realPathp + (tp - spacep->data);
6665
6666                     if (*tp && !smb_IsLegalFilename(tp)) {
6667                         cm_ReleaseUser(userp);
6668                         if (baseFidp) 
6669                             smb_ReleaseFID(baseFidp);
6670                         free(realPathp);
6671                         if (scp)
6672                             cm_ReleaseSCache(scp);
6673                         return CM_ERROR_BADNTFILENAME;
6674                     }
6675                     code = 0;
6676                 }
6677             } while (dscp == NULL && code == 0);
6678         } else
6679             code = 0;
6680
6681         /* we might have scp and we might have dscp */
6682
6683         if (baseFidp)
6684             smb_ReleaseFID(baseFidp);
6685
6686         if (code) {
6687             osi_Log0(smb_logp,"NTCreateX parent not found");
6688             if (scp)
6689                 cm_ReleaseSCache(scp);
6690             if (dscp)
6691                 cm_ReleaseSCache(dscp);
6692             cm_ReleaseUser(userp);
6693             free(realPathp);
6694             return code;
6695         }
6696
6697         if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6698             /* A file exists where we want a directory. */
6699             if (scp)
6700                 cm_ReleaseSCache(scp);
6701             cm_ReleaseSCache(dscp);
6702             cm_ReleaseUser(userp);
6703             free(realPathp);
6704             return CM_ERROR_EXISTS;
6705         }
6706
6707         if (!lastNamep) 
6708             lastNamep = realPathp;
6709         else 
6710             lastNamep++;
6711
6712         if (!smb_IsLegalFilename(lastNamep)) {
6713             if (scp)
6714                 cm_ReleaseSCache(scp);
6715             if (dscp)
6716                 cm_ReleaseSCache(dscp);
6717             cm_ReleaseUser(userp);
6718             free(realPathp);
6719             return CM_ERROR_BADNTFILENAME;
6720         }
6721
6722         if (!foundscp && !treeCreate) {
6723             if ( createDisp == FILE_CREATE || 
6724                  createDisp == FILE_OVERWRITE ||
6725                  createDisp == FILE_OVERWRITE_IF) 
6726             {
6727                 code = cm_Lookup(dscp, lastNamep,
6728                                   CM_FLAG_FOLLOW, userp, &req, &scp);
6729             } else {
6730                 code = cm_Lookup(dscp, lastNamep,
6731                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6732                                  userp, &req, &scp);
6733             }
6734             if (code && code != CM_ERROR_NOSUCHFILE) {
6735                 if (dscp)
6736                     cm_ReleaseSCache(dscp);
6737                 cm_ReleaseUser(userp);
6738                 free(realPathp);
6739                 return code;
6740             }
6741         }
6742         /* we have scp and dscp */
6743     } else {
6744         /* we have scp but not dscp */
6745         if (baseFidp)
6746             smb_ReleaseFID(baseFidp);
6747     }
6748
6749     /* if we get here, if code is 0, the file exists and is represented by
6750      * scp.  Otherwise, we have to create it.  The dir may be represented
6751      * by dscp, or we may have found the file directly.  If code is non-zero,
6752      * scp is NULL.
6753      */
6754     if (code == 0 && !treeCreate) {
6755         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6756         if (code) {
6757             if (dscp)
6758                 cm_ReleaseSCache(dscp);
6759             if (scp)
6760                 cm_ReleaseSCache(scp);
6761             cm_ReleaseUser(userp);
6762             free(realPathp);
6763             return code;
6764         }
6765
6766         if (createDisp == FILE_CREATE) {
6767             /* oops, file shouldn't be there */
6768             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6769             if (dscp)
6770                 cm_ReleaseSCache(dscp);
6771             if (scp)
6772                 cm_ReleaseSCache(scp);
6773             cm_ReleaseUser(userp);
6774             free(realPathp);
6775             return CM_ERROR_EXISTS;
6776         }
6777
6778         if ( createDisp == FILE_OVERWRITE || 
6779              createDisp == FILE_OVERWRITE_IF) {
6780
6781             setAttr.mask = CM_ATTRMASK_LENGTH;
6782             setAttr.length.LowPart = 0;
6783             setAttr.length.HighPart = 0;
6784             /* now watch for a symlink */
6785             code = 0;
6786             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6787                 targetScp = 0;
6788                 osi_assert(dscp != NULL);
6789                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6790                 if (code == 0) {
6791                     /* we have a more accurate file to use (the
6792                      * target of the symbolic link).  Otherwise,
6793                      * we'll just use the symlink anyway.
6794                      */
6795                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
6796                               scp, targetScp);
6797                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6798                     cm_ReleaseSCache(scp);
6799                     scp = targetScp;
6800                     code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6801                     if (code) {
6802                         if (dscp)
6803                             cm_ReleaseSCache(dscp);
6804                         if (scp)
6805                             cm_ReleaseSCache(scp);
6806                         cm_ReleaseUser(userp);
6807                         free(realPathp);
6808                         return code;
6809                     }
6810                 }
6811             }
6812             code = cm_SetAttr(scp, &setAttr, userp, &req);
6813             openAction = 3;     /* truncated existing file */
6814         }
6815         else 
6816             openAction = 1;     /* found existing file */
6817
6818     } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6819         /* don't create if not found */
6820         if (dscp)
6821             cm_ReleaseSCache(dscp);
6822         if (scp)
6823             cm_ReleaseSCache(scp);
6824         cm_ReleaseUser(userp);
6825         free(realPathp);
6826         return CM_ERROR_NOSUCHFILE;
6827     } else if (realDirFlag == 0 || realDirFlag == -1) {
6828         osi_assert(dscp != NULL);
6829         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6830                   osi_LogSaveString(smb_logp, lastNamep));
6831         openAction = 2;         /* created file */
6832         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6833         setAttr.clientModTime = time(NULL);
6834         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6835         if (code == 0) {
6836             created = 1;
6837             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6838                 smb_NotifyChange(FILE_ACTION_ADDED,
6839                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6840                                  dscp, lastNamep, NULL, TRUE);
6841         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6842             /* Not an exclusive create, and someone else tried
6843              * creating it already, then we open it anyway.  We
6844              * don't bother retrying after this, since if this next
6845              * fails, that means that the file was deleted after we
6846              * started this call.
6847              */
6848             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6849                               userp, &req, &scp);
6850             if (code == 0) {
6851                 if (createDisp == FILE_OVERWRITE_IF) {
6852                     setAttr.mask = CM_ATTRMASK_LENGTH;
6853                     setAttr.length.LowPart = 0;
6854                     setAttr.length.HighPart = 0;
6855
6856                     /* now watch for a symlink */
6857                     code = 0;
6858                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6859                         targetScp = 0;
6860                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6861                         if (code == 0) {
6862                             /* we have a more accurate file to use (the
6863                              * target of the symbolic link).  Otherwise,
6864                              * we'll just use the symlink anyway.
6865                              */
6866                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
6867                                       scp, targetScp);
6868                             cm_ReleaseSCache(scp);
6869                             scp = targetScp;
6870                         }
6871                     }
6872                     code = cm_SetAttr(scp, &setAttr, userp, &req);
6873                 }
6874             }   /* lookup succeeded */
6875         }
6876     } else {
6877         char *tp, *pp;
6878         char *cp; /* This component */
6879         int clen = 0; /* length of component */
6880         cm_scache_t *tscp1, *tscp2;
6881         int isLast = 0;
6882
6883         /* create directory */
6884         if ( !treeCreate ) 
6885             treeStartp = lastNamep;
6886         osi_assert(dscp != NULL);
6887         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6888                   osi_LogSaveString(smb_logp, treeStartp));
6889         openAction = 2;         /* created directory */
6890
6891         /* if the request is to create the root directory 
6892          * it will appear as a directory name of the nul-string
6893          * and a code of CM_ERROR_NOSUCHFILE
6894          */
6895         if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
6896             code = CM_ERROR_EXISTS;
6897
6898         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6899         setAttr.clientModTime = time(NULL);
6900
6901         pp = treeStartp;
6902         cp = spacep->data;
6903         tscp1 = dscp;
6904         cm_HoldSCache(tscp1);
6905         tscp2 = NULL;
6906
6907         while (pp && *pp) {
6908             tp = strchr(pp, '\\');
6909             if (!tp) {
6910                 strcpy(cp,pp);
6911                 clen = (int)strlen(cp);
6912                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
6913             } else {
6914                 clen = (int)(tp - pp);
6915                 strncpy(cp,pp,clen);
6916                 *(cp + clen) = 0;
6917                 tp++;
6918             }
6919             pp = tp;
6920
6921             if (clen == 0) 
6922                 continue; /* the supplied path can't have consecutive slashes either , but */
6923
6924             /* cp is the next component to be created. */
6925             code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6926             if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6927                 smb_NotifyChange(FILE_ACTION_ADDED,
6928                                   FILE_NOTIFY_CHANGE_DIR_NAME,
6929                                   tscp1, cp, NULL, TRUE);
6930             if (code == 0 || 
6931                  (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6932                 /* Not an exclusive create, and someone else tried
6933                  * creating it already, then we open it anyway.  We
6934                  * don't bother retrying after this, since if this next
6935                  * fails, that means that the file was deleted after we
6936                  * started this call.
6937                  */
6938                 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6939                                   userp, &req, &tscp2);
6940             }       
6941             if (code) 
6942                 break;
6943
6944             if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6945                 cm_ReleaseSCache(tscp1);
6946                 tscp1 = tscp2; /* Newly created directory will be next parent */
6947                 /* the hold is transfered to tscp1 from tscp2 */
6948             }
6949         }
6950
6951         if (dscp)
6952             cm_ReleaseSCache(dscp);
6953         dscp = tscp1;
6954         if (scp)
6955             cm_ReleaseSCache(scp);
6956         scp = tscp2;
6957         /* 
6958          * if we get here and code == 0, then scp is the last directory created, and dscp is the
6959          * parent of scp.
6960          */
6961     }
6962
6963     if (code) {
6964         /* something went wrong creating or truncating the file */
6965         if (ldp)
6966             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6967         if (scp) 
6968             cm_ReleaseSCache(scp);
6969         if (dscp) 
6970             cm_ReleaseSCache(dscp);
6971         cm_ReleaseUser(userp);
6972         free(realPathp);
6973         return code;
6974     }
6975
6976     /* make sure we have file vs. dir right (only applies for single component case) */
6977     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6978         /* now watch for a symlink */
6979         code = 0;
6980         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6981             cm_scache_t * targetScp = 0;
6982             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6983             if (code == 0) {
6984                 /* we have a more accurate file to use (the
6985                 * target of the symbolic link).  Otherwise,
6986                 * we'll just use the symlink anyway.
6987                 */
6988                 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
6989                 if (ldp)
6990                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6991                 cm_ReleaseSCache(scp);
6992                 scp = targetScp;
6993             }
6994         }
6995
6996         if (scp->fileType != CM_SCACHETYPE_FILE) {
6997             if (ldp)
6998                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6999             if (dscp)
7000                 cm_ReleaseSCache(dscp);
7001             cm_ReleaseSCache(scp);
7002             cm_ReleaseUser(userp);
7003             free(realPathp);
7004             return CM_ERROR_ISDIR;
7005         }
7006     }
7007
7008     /* (only applies to single component case) */
7009     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7010         if (ldp)
7011             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7012         cm_ReleaseSCache(scp);
7013         if (dscp)
7014             cm_ReleaseSCache(dscp);
7015         cm_ReleaseUser(userp);
7016         free(realPathp);
7017         return CM_ERROR_NOTDIR;
7018     }
7019
7020     /* open the file itself */
7021     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7022     osi_assert(fidp);
7023
7024     /* save a reference to the user */
7025     cm_HoldUser(userp);
7026     fidp->userp = userp;
7027
7028     /* If we are restricting sharing, we should do so with a suitable
7029        share lock. */
7030     if (scp->fileType == CM_SCACHETYPE_FILE &&
7031         !(fidflags & SMB_FID_SHARE_WRITE)) {
7032         cm_key_t key;
7033         LARGE_INTEGER LOffset, LLength;
7034         int sLockType;
7035
7036         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7037         LOffset.LowPart = SMB_FID_QLOCK_LOW;
7038         LLength.HighPart = 0;
7039         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7040
7041         if (fidflags & SMB_FID_SHARE_READ) {
7042             sLockType = LOCKING_ANDX_SHARED_LOCK;
7043         } else {
7044             sLockType = 0;
7045         }
7046
7047         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7048         
7049         lock_ObtainMutex(&scp->mx);
7050         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7051         lock_ReleaseMutex(&scp->mx);
7052
7053         if (code) {
7054             if (ldp)
7055                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7056             cm_ReleaseSCache(scp);
7057             if (dscp)
7058                 cm_ReleaseSCache(dscp);
7059             cm_ReleaseUser(userp);
7060             /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
7061             smb_CloseFID(vcp, fidp, NULL, 0);
7062             smb_ReleaseFID(fidp);
7063             free(realPathp);
7064             return code;
7065         }
7066     }
7067
7068     /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7069     if (ldp)
7070         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7071
7072     lock_ObtainMutex(&fidp->mx);
7073     /* save a pointer to the vnode */
7074     fidp->scp = scp;    /* Hold transfered to fidp->scp and no longer needed */
7075     lock_ObtainMutex(&scp->mx);
7076     scp->flags |= CM_SCACHEFLAG_SMB_FID;
7077     lock_ReleaseMutex(&scp->mx);
7078     osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7079
7080     fidp->flags = fidflags;
7081
7082     /* remember if the file was newly created */
7083     if (created)
7084         fidp->flags |= SMB_FID_CREATED;
7085
7086     /* save parent dir and pathname for delete or change notification */
7087     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7088         osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7089         fidp->flags |= SMB_FID_NTOPEN;
7090         fidp->NTopen_dscp = dscp;
7091         dscp = NULL;
7092         fidp->NTopen_pathp = strdup(lastNamep);
7093     }
7094     fidp->NTopen_wholepathp = realPathp;
7095     lock_ReleaseMutex(&fidp->mx);
7096
7097     /* we don't need this any longer */
7098     if (dscp) {
7099         cm_ReleaseSCache(dscp);
7100         dscp = NULL;
7101     }
7102
7103     cm_Open(scp, 0, userp);
7104
7105     /* set inp->fid so that later read calls in same msg can find fid */
7106     inp->fid = fidp->fid;
7107
7108     /* out parms */
7109     parmSlot = 2;
7110     lock_ObtainMutex(&scp->mx);
7111     smb_SetSMBParmByte(outp, parmSlot, 0);      /* oplock */
7112     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7113     smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7114     smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7115     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7116     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7117     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7118     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7119     smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7120     parmSlot += 2;
7121     smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7122     smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7123     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* filetype */
7124     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* dev state */
7125     smb_SetSMBParmByte(outp, parmSlot,
7126                         (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7127                          scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7128                          scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7129     lock_ReleaseMutex(&scp->mx);
7130     smb_SetSMBDataLength(outp, 0);
7131
7132     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
7133               osi_LogSaveString(smb_logp, realPathp));
7134
7135     cm_ReleaseUser(userp);
7136     smb_ReleaseFID(fidp);
7137
7138     /* Can't free realPathp if we get here since
7139        fidp->NTopen_wholepathp is pointing there */
7140
7141     /* leave scp held since we put it in fidp->scp */
7142     return 0;
7143 }       
7144
7145 /*
7146  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7147  * Instead, ultimately, would like to use a subroutine for common code.
7148  */
7149 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7150 {
7151     char *pathp, *realPathp;
7152     long code = 0;
7153     cm_space_t *spacep;
7154     cm_user_t *userp;
7155     cm_scache_t *dscp;          /* parent dir */
7156     cm_scache_t *scp;           /* file to create or open */
7157     cm_scache_t *targetScp;     /* if scp is a symlink */
7158     cm_attr_t setAttr;
7159     char *lastNamep;
7160     unsigned long nameLength;
7161     unsigned int flags;
7162     unsigned int requestOpLock;
7163     unsigned int requestBatchOpLock;
7164     unsigned int mustBeDir;
7165     unsigned int extendedRespRequired;
7166     int realDirFlag;
7167     unsigned int desiredAccess;
7168 #ifdef DEBUG_VERBOSE    
7169     unsigned int allocSize;
7170 #endif
7171     unsigned int shareAccess;
7172     unsigned int extAttributes;
7173     unsigned int createDisp;
7174 #ifdef DEBUG_VERBOSE
7175     unsigned int sdLen;
7176 #endif
7177     unsigned int createOptions;
7178     int initialModeBits;
7179     unsigned short baseFid;
7180     smb_fid_t *baseFidp;
7181     smb_fid_t *fidp;
7182     cm_scache_t *baseDirp;
7183     unsigned short openAction;
7184     int parmSlot;
7185     long fidflags;
7186     FILETIME ft;
7187     char *tidPathp;
7188     BOOL foundscp;
7189     int parmOffset, dataOffset;
7190     char *parmp;
7191     ULONG *lparmp;
7192     char *outData;
7193     cm_req_t req;
7194     int created = 0;
7195     cm_lock_data_t *ldp = NULL;
7196
7197     cm_InitReq(&req);
7198
7199     foundscp = FALSE;
7200     scp = NULL;
7201
7202     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7203         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7204     parmp = inp->data + parmOffset;
7205     lparmp = (ULONG *) parmp;
7206
7207     flags = lparmp[0];
7208     requestOpLock = flags & REQUEST_OPLOCK;
7209     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7210     mustBeDir = flags & OPEN_DIRECTORY;
7211     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7212
7213     /*
7214      * Why all of a sudden 32-bit FID?
7215      * We will reject all bits higher than 16.
7216      */
7217     if (lparmp[1] & 0xFFFF0000)
7218         return CM_ERROR_INVAL;
7219     baseFid = (unsigned short)lparmp[1];
7220     desiredAccess = lparmp[2];
7221 #ifdef DEBUG_VERBOSE
7222     allocSize = lparmp[3];
7223 #endif /* DEBUG_VERSOSE */
7224     extAttributes = lparmp[5];
7225     shareAccess = lparmp[6];
7226     createDisp = lparmp[7];
7227     createOptions = lparmp[8];
7228 #ifdef DEBUG_VERBOSE
7229     sdLen = lparmp[9];
7230 #endif
7231     nameLength = lparmp[11];
7232
7233 #ifdef DEBUG_VERBOSE
7234     osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7235     osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7236     osi_Log1(smb_logp,"... flags[%x]",flags);
7237 #endif
7238
7239     /* mustBeDir is never set; createOptions directory bit seems to be
7240      * more important
7241      */
7242     if (createOptions & FILE_DIRECTORY_FILE)
7243         realDirFlag = 1;
7244     else if (createOptions & FILE_NON_DIRECTORY_FILE)
7245         realDirFlag = 0;
7246     else
7247         realDirFlag = -1;
7248
7249     /*
7250      * compute initial mode bits based on read-only flag in
7251      * extended attributes
7252      */
7253     initialModeBits = 0666;
7254     if (extAttributes & SMB_ATTR_READONLY) 
7255         initialModeBits &= ~0222;
7256
7257     pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
7258     /* Sometimes path is not null-terminated, so we make a copy. */
7259     realPathp = malloc(nameLength+1);
7260     memcpy(realPathp, pathp, nameLength);
7261     realPathp[nameLength] = 0;
7262     if (smb_StoreAnsiFilenames)
7263         OemToChar(realPathp,realPathp);
7264
7265     spacep = cm_GetSpace();
7266     smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
7267
7268     /*
7269      * Nothing here to handle SMB_IOCTL_FILENAME.
7270      * Will add it if necessary.
7271      */
7272
7273 #ifdef DEBUG_VERBOSE
7274     {
7275         char *hexp, *asciip;
7276         asciip = (lastNamep? lastNamep : realPathp);
7277         hexp = osi_HexifyString( asciip );
7278         DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7279         free(hexp);
7280     }
7281 #endif
7282
7283     userp = smb_GetUserFromVCP(vcp, inp);
7284     if (!userp) {
7285         osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7286         free(realPathp);
7287         return CM_ERROR_INVAL;
7288     }
7289
7290     if (baseFid == 0) {
7291         baseFidp = NULL;
7292         baseDirp = cm_data.rootSCachep;
7293         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7294         if (code == CM_ERROR_TIDIPC) {
7295             /* Attempt to use a TID allocated for IPC.  The client
7296              * is probably looking for DCE RPC end points which we
7297              * don't support OR it could be looking to make a DFS
7298              * referral request. 
7299              */
7300             osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7301 #ifndef DFS_SUPPORT
7302             free(realPathp);
7303             cm_ReleaseUser(userp);
7304             return CM_ERROR_NOSUCHPATH;
7305 #endif 
7306         }
7307     } else {
7308         baseFidp = smb_FindFID(vcp, baseFid, 0);
7309         if (!baseFidp) {
7310             osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7311             free(realPathp);
7312             cm_ReleaseUser(userp);
7313             return CM_ERROR_INVAL;
7314         }       
7315         baseDirp = baseFidp->scp;
7316         tidPathp = NULL;
7317     }
7318
7319     /* compute open mode */
7320     fidflags = 0;
7321     if (desiredAccess & DELETE)
7322         fidflags |= SMB_FID_OPENDELETE;
7323     if (desiredAccess & AFS_ACCESS_READ)
7324         fidflags |= SMB_FID_OPENREAD_LISTDIR;
7325     if (desiredAccess & AFS_ACCESS_WRITE)
7326         fidflags |= SMB_FID_OPENWRITE;
7327     if (createOptions & FILE_DELETE_ON_CLOSE)
7328         fidflags |= SMB_FID_DELONCLOSE;
7329     if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7330         fidflags |= SMB_FID_SEQUENTIAL;
7331     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7332         fidflags |= SMB_FID_RANDOM;
7333
7334     /* And the share mode */
7335     if (shareAccess & FILE_SHARE_READ)
7336         fidflags |= SMB_FID_SHARE_READ;
7337     if (shareAccess & FILE_SHARE_WRITE)
7338         fidflags |= SMB_FID_SHARE_WRITE;
7339
7340     dscp = NULL;
7341     code = 0;
7342     if ( createDisp == FILE_OPEN || 
7343          createDisp == FILE_OVERWRITE ||
7344          createDisp == FILE_OVERWRITE_IF) {
7345         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7346                         userp, tidPathp, &req, &dscp);
7347         if (code == 0) {
7348 #ifdef DFS_SUPPORT
7349             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7350                 cm_ReleaseSCache(dscp);
7351                 cm_ReleaseUser(userp);
7352                 free(realPathp);
7353                 if (baseFidp)
7354                     smb_ReleaseFID(baseFidp);
7355                 if ( WANTS_DFS_PATHNAMES(inp) )
7356                     return CM_ERROR_PATH_NOT_COVERED;
7357                 else
7358                     return CM_ERROR_BADSHARENAME;
7359             }
7360 #endif /* DFS_SUPPORT */
7361             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7362                              userp, &req, &scp);
7363             if (code == CM_ERROR_NOSUCHFILE) {
7364                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
7365                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7366                 if (code == 0 && realDirFlag == 1) {
7367                     cm_ReleaseSCache(scp);
7368                     cm_ReleaseSCache(dscp);
7369                     cm_ReleaseUser(userp);
7370                     free(realPathp);
7371                     if (baseFidp)
7372                         smb_ReleaseFID(baseFidp);
7373                     return CM_ERROR_EXISTS;
7374                 }
7375             }
7376         } else 
7377             dscp = NULL;
7378     } else {
7379         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7380                         userp, tidPathp, &req, &scp);
7381 #ifdef DFS_SUPPORT
7382         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7383             cm_ReleaseSCache(scp);
7384             cm_ReleaseUser(userp);
7385             free(realPathp);
7386             if (baseFidp)
7387                 smb_ReleaseFID(baseFidp);
7388             if ( WANTS_DFS_PATHNAMES(inp) )
7389                 return CM_ERROR_PATH_NOT_COVERED;
7390             else
7391                 return CM_ERROR_BADSHARENAME;
7392         }
7393 #endif /* DFS_SUPPORT */
7394     }
7395
7396     if (code == 0) 
7397         foundscp = TRUE;
7398
7399     if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7400         /* look up parent directory */
7401         if ( !dscp ) {
7402             code = cm_NameI(baseDirp, spacep->data,
7403                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7404                              userp, tidPathp, &req, &dscp);
7405 #ifdef DFS_SUPPORT
7406             if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7407                 cm_ReleaseSCache(dscp);
7408                 cm_ReleaseUser(userp);
7409                 free(realPathp);
7410                 if (baseFidp)
7411                     smb_ReleaseFID(baseFidp);
7412                 if ( WANTS_DFS_PATHNAMES(inp) )
7413                     return CM_ERROR_PATH_NOT_COVERED;
7414                 else
7415                     return CM_ERROR_BADSHARENAME;
7416             }
7417 #endif /* DFS_SUPPORT */
7418         } else
7419             code = 0;
7420         
7421         cm_FreeSpace(spacep);
7422
7423         if (baseFidp)
7424             smb_ReleaseFID(baseFidp);
7425
7426         if (code) {
7427             cm_ReleaseUser(userp);
7428             free(realPathp);
7429             return code;
7430         }
7431
7432         if (!lastNamep)
7433             lastNamep = realPathp;
7434         else 
7435             lastNamep++;
7436
7437         if (!smb_IsLegalFilename(lastNamep))
7438             return CM_ERROR_BADNTFILENAME;
7439
7440         if (!foundscp) {
7441             if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7442                 code = cm_Lookup(dscp, lastNamep,
7443                                   CM_FLAG_FOLLOW, userp, &req, &scp);
7444             } else {
7445                 code = cm_Lookup(dscp, lastNamep,
7446                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7447                                  userp, &req, &scp);
7448             }
7449             if (code && code != CM_ERROR_NOSUCHFILE) {
7450                 cm_ReleaseSCache(dscp);
7451                 cm_ReleaseUser(userp);
7452                 free(realPathp);
7453                 return code;
7454             }
7455         }
7456     } else {
7457         if (baseFidp)
7458             smb_ReleaseFID(baseFidp);
7459         cm_FreeSpace(spacep);
7460     }
7461
7462     /* if we get here, if code is 0, the file exists and is represented by
7463      * scp.  Otherwise, we have to create it.  The dir may be represented
7464      * by dscp, or we may have found the file directly.  If code is non-zero,
7465      * scp is NULL.
7466      */
7467     if (code == 0) {
7468         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7469         if (code) {     
7470             if (dscp) 
7471                 cm_ReleaseSCache(dscp);
7472             cm_ReleaseSCache(scp);
7473             cm_ReleaseUser(userp);
7474             free(realPathp);
7475             return code;
7476         }
7477
7478         if (createDisp == FILE_CREATE) {
7479             /* oops, file shouldn't be there */
7480             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7481             if (dscp) 
7482                 cm_ReleaseSCache(dscp);
7483             cm_ReleaseSCache(scp);
7484             cm_ReleaseUser(userp);
7485             free(realPathp);
7486             return CM_ERROR_EXISTS;
7487         }
7488
7489         if (createDisp == FILE_OVERWRITE ||
7490             createDisp == FILE_OVERWRITE_IF) {
7491             setAttr.mask = CM_ATTRMASK_LENGTH;
7492             setAttr.length.LowPart = 0;
7493             setAttr.length.HighPart = 0;
7494
7495             /* now watch for a symlink */
7496             code = 0;
7497             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7498                 targetScp = 0;
7499                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7500                 if (code == 0) {
7501                     /* we have a more accurate file to use (the
7502                     * target of the symbolic link).  Otherwise,
7503                     * we'll just use the symlink anyway.
7504                     */
7505                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
7506                               scp, targetScp);
7507                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7508                     cm_ReleaseSCache(scp);
7509                     scp = targetScp;
7510                     code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7511                     if (code) {
7512                         if (dscp)
7513                             cm_ReleaseSCache(dscp);
7514                         if (scp)
7515                             cm_ReleaseSCache(scp);
7516                         cm_ReleaseUser(userp);
7517                         free(realPathp);
7518                         return code;
7519                     }
7520                 }
7521             }
7522             code = cm_SetAttr(scp, &setAttr, userp, &req);
7523             openAction = 3;     /* truncated existing file */
7524         }
7525         else openAction = 1;    /* found existing file */
7526     }
7527     else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7528         /* don't create if not found */
7529         if (dscp) 
7530             cm_ReleaseSCache(dscp);
7531         cm_ReleaseUser(userp);
7532         free(realPathp);
7533         return CM_ERROR_NOSUCHFILE;
7534     }
7535     else if (realDirFlag == 0 || realDirFlag == -1) {
7536         osi_assert(dscp != NULL);
7537         osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7538                   osi_LogSaveString(smb_logp, lastNamep));
7539         openAction = 2;         /* created file */
7540         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7541         setAttr.clientModTime = time(NULL);
7542         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7543                           &req);
7544         if (code == 0) {
7545             created = 1;
7546             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7547                 smb_NotifyChange(FILE_ACTION_ADDED,
7548                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7549                                  dscp, lastNamep, NULL, TRUE);
7550         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7551             /* Not an exclusive create, and someone else tried
7552              * creating it already, then we open it anyway.  We
7553              * don't bother retrying after this, since if this next
7554              * fails, that means that the file was deleted after we
7555              * started this call.
7556              */
7557             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7558                               userp, &req, &scp);
7559             if (code == 0) {
7560                 if (createDisp == FILE_OVERWRITE_IF) {
7561                     setAttr.mask = CM_ATTRMASK_LENGTH;
7562                     setAttr.length.LowPart = 0;
7563                     setAttr.length.HighPart = 0;
7564
7565                     /* now watch for a symlink */
7566                     code = 0;
7567                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7568                         targetScp = 0;
7569                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7570                         if (code == 0) {
7571                             /* we have a more accurate file to use (the
7572                             * target of the symbolic link).  Otherwise,
7573                             * we'll just use the symlink anyway.
7574                             */
7575                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
7576                                       scp, targetScp);
7577                             cm_ReleaseSCache(scp);
7578                             scp = targetScp;
7579                         }
7580                     }
7581                     code = cm_SetAttr(scp, &setAttr, userp, &req);
7582                 }       
7583             }   /* lookup succeeded */
7584         }
7585     } else {
7586         /* create directory */
7587         osi_assert(dscp != NULL);
7588         osi_Log1(smb_logp,
7589                   "smb_ReceiveNTTranCreate creating directory %s",
7590                   osi_LogSaveString(smb_logp, lastNamep));
7591         openAction = 2;         /* created directory */
7592         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7593         setAttr.clientModTime = time(NULL);
7594         code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7595         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7596             smb_NotifyChange(FILE_ACTION_ADDED,
7597                               FILE_NOTIFY_CHANGE_DIR_NAME,
7598                               dscp, lastNamep, NULL, TRUE);
7599         if (code == 0 ||
7600             (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7601             /* Not an exclusive create, and someone else tried
7602              * creating it already, then we open it anyway.  We
7603              * don't bother retrying after this, since if this next
7604              * fails, that means that the file was deleted after we
7605              * started this call.
7606              */
7607             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7608                               userp, &req, &scp);
7609         }       
7610     }
7611
7612     if (code) {
7613         /* something went wrong creating or truncating the file */
7614         if (ldp)
7615             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7616         if (scp) 
7617             cm_ReleaseSCache(scp);
7618         cm_ReleaseUser(userp);
7619         free(realPathp);
7620         return code;
7621     }
7622
7623     /* make sure we have file vs. dir right */
7624     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7625         /* now watch for a symlink */
7626         code = 0;
7627         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7628             targetScp = 0;
7629             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7630             if (code == 0) {
7631                 /* we have a more accurate file to use (the
7632                 * target of the symbolic link).  Otherwise,
7633                 * we'll just use the symlink anyway.
7634                 */
7635                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7636                           scp, targetScp);
7637                 if (ldp)
7638                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7639                 cm_ReleaseSCache(scp);
7640                 scp = targetScp;
7641             }
7642         }
7643
7644         if (scp->fileType != CM_SCACHETYPE_FILE) {
7645             if (ldp)
7646                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7647             cm_ReleaseSCache(scp);
7648             cm_ReleaseUser(userp);
7649             free(realPathp);
7650             return CM_ERROR_ISDIR;
7651         }
7652     }
7653
7654     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7655         if (ldp)
7656             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7657         cm_ReleaseSCache(scp);
7658         cm_ReleaseUser(userp);
7659         free(realPathp);
7660         return CM_ERROR_NOTDIR;
7661     }
7662
7663     /* open the file itself */
7664     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7665     osi_assert(fidp);
7666
7667     /* save a reference to the user */
7668     cm_HoldUser(userp);
7669     fidp->userp = userp;
7670
7671     /* If we are restricting sharing, we should do so with a suitable
7672        share lock. */
7673     if (scp->fileType == CM_SCACHETYPE_FILE &&
7674         !(fidflags & SMB_FID_SHARE_WRITE)) {
7675         cm_key_t key;
7676         LARGE_INTEGER LOffset, LLength;
7677         int sLockType;
7678
7679         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7680         LOffset.LowPart = SMB_FID_QLOCK_LOW;
7681         LLength.HighPart = 0;
7682         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7683
7684         if (fidflags & SMB_FID_SHARE_READ) {
7685             sLockType = LOCKING_ANDX_SHARED_LOCK;
7686         } else {
7687             sLockType = 0;
7688         }
7689
7690         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7691         
7692         lock_ObtainMutex(&scp->mx);
7693         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7694         lock_ReleaseMutex(&scp->mx);
7695
7696         if (code) {
7697             if (ldp)
7698                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7699             cm_ReleaseSCache(scp);
7700             cm_ReleaseUser(userp);
7701             /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
7702             smb_CloseFID(vcp, fidp, NULL, 0);
7703             smb_ReleaseFID(fidp);
7704             free(realPathp);
7705             return CM_ERROR_SHARING_VIOLATION;
7706         }
7707     }
7708
7709     /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
7710     if (ldp)
7711         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7712
7713     lock_ObtainMutex(&fidp->mx);
7714     /* save a pointer to the vnode */
7715     fidp->scp = scp;
7716     lock_ObtainMutex(&scp->mx);
7717     scp->flags |= CM_SCACHEFLAG_SMB_FID;
7718     lock_ReleaseMutex(&scp->mx);
7719     osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
7720
7721     fidp->flags = fidflags;
7722
7723     /* remember if the file was newly created */
7724     if (created)
7725         fidp->flags |= SMB_FID_CREATED;
7726
7727     /* save parent dir and pathname for deletion or change notification */
7728     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7729         fidp->flags |= SMB_FID_NTOPEN;
7730         fidp->NTopen_dscp = dscp;
7731         osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
7732         dscp = NULL;
7733         fidp->NTopen_pathp = strdup(lastNamep);
7734     }
7735     fidp->NTopen_wholepathp = realPathp;
7736     lock_ReleaseMutex(&fidp->mx);
7737
7738     /* we don't need this any longer */
7739     if (dscp) 
7740         cm_ReleaseSCache(dscp);
7741
7742     cm_Open(scp, 0, userp);
7743
7744     /* set inp->fid so that later read calls in same msg can find fid */
7745     inp->fid = fidp->fid;
7746
7747     /* check whether we are required to send an extended response */
7748     if (!extendedRespRequired) {
7749         /* out parms */
7750         parmOffset = 8*4 + 39;
7751         parmOffset += 1;        /* pad to 4 */
7752         dataOffset = parmOffset + 70;
7753
7754         parmSlot = 1;
7755         outp->oddByte = 1;
7756         /* Total Parameter Count */
7757         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7758         /* Total Data Count */
7759         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7760         /* Parameter Count */
7761         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7762         /* Parameter Offset */
7763         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7764         /* Parameter Displacement */
7765         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7766         /* Data Count */
7767         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7768         /* Data Offset */
7769         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7770         /* Data Displacement */
7771         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7772         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
7773         smb_SetSMBDataLength(outp, 70);
7774
7775         lock_ObtainMutex(&scp->mx);
7776         outData = smb_GetSMBData(outp, NULL);
7777         outData++;                      /* round to get to parmOffset */
7778         *outData = 0; outData++;        /* oplock */
7779         *outData = 0; outData++;        /* reserved */
7780         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7781         *((ULONG *)outData) = openAction; outData += 4;
7782         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
7783         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7784         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
7785         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
7786         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
7787         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
7788         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7789         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7790         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7791         *((USHORT *)outData) = 0; outData += 2; /* filetype */
7792         *((USHORT *)outData) = 0; outData += 2; /* dev state */
7793         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7794                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7795                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7796         outData += 2;   /* is a dir? */
7797         lock_ReleaseMutex(&scp->mx);
7798     } else {
7799         /* out parms */
7800         parmOffset = 8*4 + 39;
7801         parmOffset += 1;        /* pad to 4 */
7802         dataOffset = parmOffset + 104;
7803         
7804         parmSlot = 1;
7805         outp->oddByte = 1;
7806         /* Total Parameter Count */
7807         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7808         /* Total Data Count */
7809         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7810         /* Parameter Count */
7811         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7812         /* Parameter Offset */
7813         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7814         /* Parameter Displacement */
7815         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7816         /* Data Count */
7817         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7818         /* Data Offset */
7819         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7820         /* Data Displacement */
7821         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7822         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
7823         smb_SetSMBDataLength(outp, 105);
7824         
7825         lock_ObtainMutex(&scp->mx);
7826         outData = smb_GetSMBData(outp, NULL);
7827         outData++;                      /* round to get to parmOffset */
7828         *outData = 0; outData++;        /* oplock */
7829         *outData = 1; outData++;        /* response type */
7830         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7831         *((ULONG *)outData) = openAction; outData += 4;
7832         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
7833         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7834         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
7835         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
7836         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
7837         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
7838         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7839         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7840         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7841         *((USHORT *)outData) = 0; outData += 2; /* filetype */
7842         *((USHORT *)outData) = 0; outData += 2; /* dev state */
7843         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7844                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7845                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7846         outData += 1;   /* is a dir? */
7847         memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7848         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7849         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7850         lock_ReleaseMutex(&scp->mx);
7851     }
7852
7853     osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7854
7855     cm_ReleaseUser(userp);
7856     smb_ReleaseFID(fidp);
7857
7858     /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7859     /* leave scp held since we put it in fidp->scp */
7860     return 0;
7861 }
7862
7863 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7864         smb_packet_t *outp)
7865 {
7866     smb_packet_t *savedPacketp;
7867     ULONG filter; 
7868     USHORT fid, watchtree;
7869     smb_fid_t *fidp;
7870     cm_scache_t *scp;
7871         
7872     filter = smb_GetSMBParm(inp, 19) |
7873              (smb_GetSMBParm(inp, 20) << 16);
7874     fid = smb_GetSMBParm(inp, 21);
7875     watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
7876
7877     fidp = smb_FindFID(vcp, fid, 0);
7878     if (!fidp) {
7879         osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7880         return CM_ERROR_BADFD;
7881     }
7882
7883     /* Create a copy of the Directory Watch Packet to use when sending the
7884      * notification if in the future a matching change is detected.
7885      */
7886     savedPacketp = smb_CopyPacket(inp);
7887     smb_HoldVC(vcp);
7888     if (savedPacketp->vcp)
7889         smb_ReleaseVC(savedPacketp->vcp);
7890     savedPacketp->vcp = vcp;
7891
7892     /* Add the watch to the list of events to send notifications for */
7893     lock_ObtainMutex(&smb_Dir_Watch_Lock);
7894     savedPacketp->nextp = smb_Directory_Watches;
7895     smb_Directory_Watches = savedPacketp;
7896     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7897
7898     scp = fidp->scp;
7899     osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"", 
7900               fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7901     osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
7902              filter, fid, watchtree);
7903     if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
7904         osi_Log0(smb_logp, "      Notify Change File Name");
7905     if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
7906         osi_Log0(smb_logp, "      Notify Change Directory Name");
7907     if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
7908         osi_Log0(smb_logp, "      Notify Change Attributes");
7909     if (filter & FILE_NOTIFY_CHANGE_SIZE)
7910         osi_Log0(smb_logp, "      Notify Change Size");
7911     if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
7912         osi_Log0(smb_logp, "      Notify Change Last Write");
7913     if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
7914         osi_Log0(smb_logp, "      Notify Change Last Access");
7915     if (filter & FILE_NOTIFY_CHANGE_CREATION)
7916         osi_Log0(smb_logp, "      Notify Change Creation");
7917     if (filter & FILE_NOTIFY_CHANGE_EA)
7918         osi_Log0(smb_logp, "      Notify Change Extended Attributes");
7919     if (filter & FILE_NOTIFY_CHANGE_SECURITY)
7920         osi_Log0(smb_logp, "      Notify Change Security");
7921     if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
7922         osi_Log0(smb_logp, "      Notify Change Stream Name");
7923     if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
7924         osi_Log0(smb_logp, "      Notify Change Stream Size");
7925     if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
7926         osi_Log0(smb_logp, "      Notify Change Stream Write");
7927
7928     lock_ObtainMutex(&scp->mx);
7929     if (watchtree)
7930         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7931     else
7932         scp->flags |= CM_SCACHEFLAG_WATCHED;
7933     lock_ReleaseMutex(&scp->mx);
7934     smb_ReleaseFID(fidp);
7935
7936     outp->flags |= SMB_PACKETFLAG_NOSEND;
7937     return 0;
7938 }
7939
7940 unsigned char nullSecurityDesc[36] = {
7941     0x01,                               /* security descriptor revision */
7942     0x00,                               /* reserved, should be zero */
7943     0x00, 0x80,                         /* security descriptor control;
7944                                          * 0x8000 : self-relative format */
7945     0x14, 0x00, 0x00, 0x00,             /* offset of owner SID */
7946     0x1c, 0x00, 0x00, 0x00,             /* offset of group SID */
7947     0x00, 0x00, 0x00, 0x00,             /* offset of DACL would go here */
7948     0x00, 0x00, 0x00, 0x00,             /* offset of SACL would go here */
7949     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7950                                         /* "null SID" owner SID */
7951     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7952                                         /* "null SID" group SID */
7953 };      
7954
7955 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7956 {
7957     int parmOffset, parmCount, dataOffset, dataCount;
7958     int parmSlot;
7959     int maxData;
7960     char *outData;
7961     char *parmp;
7962     USHORT *sparmp;
7963     ULONG *lparmp;
7964     USHORT fid;
7965     ULONG securityInformation;
7966
7967     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7968         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7969     parmp = inp->data + parmOffset;
7970     sparmp = (USHORT *) parmp;
7971     lparmp = (ULONG *) parmp;
7972
7973     fid = sparmp[0];
7974     securityInformation = lparmp[1];
7975
7976     maxData = smb_GetSMBOffsetParm(inp, 7, 1)
7977         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7978
7979     if (maxData < 36)
7980         dataCount = 0;
7981     else
7982         dataCount = 36;
7983
7984     /* out parms */
7985     parmOffset = 8*4 + 39;
7986     parmOffset += 1;    /* pad to 4 */
7987     parmCount = 4;
7988     dataOffset = parmOffset + parmCount;
7989
7990     parmSlot = 1;
7991     outp->oddByte = 1;
7992     /* Total Parameter Count */
7993     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7994     /* Total Data Count */
7995     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7996     /* Parameter Count */
7997     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7998     /* Parameter Offset */
7999     smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8000     /* Parameter Displacement */
8001     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8002     /* Data Count */
8003     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8004     /* Data Offset */
8005     smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8006     /* Data Displacement */
8007     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8008     smb_SetSMBParmByte(outp, parmSlot, 0);      /* Setup Count */
8009     smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8010
8011     outData = smb_GetSMBData(outp, NULL);
8012     outData++;                  /* round to get to parmOffset */
8013     *((ULONG *)outData) = 36; outData += 4;     /* length */
8014
8015     if (maxData >= 36) {
8016         memcpy(outData, nullSecurityDesc, 36);
8017         outData += 36;
8018         return 0;
8019     } else
8020         return CM_ERROR_BUFFERTOOSMALL;
8021 }
8022
8023 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8024 {
8025     unsigned short function;
8026
8027     function = smb_GetSMBParm(inp, 18);
8028
8029     osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8030
8031     /* We can handle long names */
8032     if (vcp->flags & SMB_VCFLAG_USENT)
8033         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8034         
8035     switch (function) {
8036     case 1: 
8037         return smb_ReceiveNTTranCreate(vcp, inp, outp);
8038     case 2:
8039         osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8040         break;
8041     case 3:
8042         osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8043         break;
8044     case 4:
8045         return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8046     case 5:
8047         osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8048         break;
8049     case 6:
8050         return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8051     }
8052     return CM_ERROR_INVAL;
8053 }
8054
8055 /*
8056  * smb_NotifyChange -- find relevant change notification messages and
8057  *                     reply to them
8058  *
8059  * If we don't know the file name (i.e. a callback break), filename is
8060  * NULL, and we return a zero-length list.
8061  *
8062  * At present there is not a single call to smb_NotifyChange that 
8063  * has the isDirectParent parameter set to FALSE.  
8064  */
8065 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8066         cm_scache_t *dscp, char *filename, char *otherFilename,
8067         BOOL isDirectParent)
8068 {
8069     smb_packet_t *watch, *lastWatch, *nextWatch;
8070     ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
8071     char *outData, *oldOutData;
8072     ULONG filter;
8073     USHORT fid, wtree;
8074     ULONG maxLen;
8075     BOOL twoEntries = FALSE;
8076     ULONG otherNameLen, oldParmCount = 0;
8077     DWORD otherAction;
8078     smb_fid_t *fidp;
8079
8080     /* Get ready for rename within directory */
8081     if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8082         twoEntries = TRUE;
8083         otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8084     }
8085
8086     osi_Log4(smb_logp,"in smb_NotifyChange for file [%s] dscp [%p] notification 0x%x parent %d",
8087              osi_LogSaveString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8088     if (action == 0)
8089         osi_Log0(smb_logp,"      FILE_ACTION_NONE");
8090     if (action == FILE_ACTION_ADDED)
8091         osi_Log0(smb_logp,"      FILE_ACTION_ADDED");
8092     if (action == FILE_ACTION_REMOVED)
8093         osi_Log0(smb_logp,"      FILE_ACTION_REMOVED");
8094     if (action == FILE_ACTION_MODIFIED)
8095         osi_Log0(smb_logp,"      FILE_ACTION_MODIFIED");
8096     if (action == FILE_ACTION_RENAMED_OLD_NAME)
8097         osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_OLD_NAME");
8098     if (action == FILE_ACTION_RENAMED_NEW_NAME)
8099         osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_NEW_NAME");
8100
8101     lock_ObtainMutex(&smb_Dir_Watch_Lock);
8102     watch = smb_Directory_Watches;
8103     while (watch) {
8104         filter = smb_GetSMBParm(watch, 19)
8105             | (smb_GetSMBParm(watch, 20) << 16);
8106         fid = smb_GetSMBParm(watch, 21);
8107         wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8108
8109         maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8110             | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8111
8112         /*
8113          * Strange hack - bug in NT Client and NT Server that we must emulate?
8114          */
8115         if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8116             filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8117
8118         fidp = smb_FindFID(watch->vcp, fid, 0);
8119         if (!fidp) {
8120             osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8121             lastWatch = watch;
8122             watch = watch->nextp;
8123             continue;
8124         }       
8125         if (fidp->scp != dscp
8126              || (filter & notifyFilter) == 0
8127              || (!isDirectParent && !wtree)) {
8128             osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8129             smb_ReleaseFID(fidp);
8130             lastWatch = watch;
8131             watch = watch->nextp;
8132             continue;
8133         }
8134         smb_ReleaseFID(fidp);
8135
8136         osi_Log4(smb_logp,
8137                   "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
8138                   fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
8139         if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8140             osi_Log0(smb_logp, "      Notify Change File Name");
8141         if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8142             osi_Log0(smb_logp, "      Notify Change Directory Name");
8143         if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8144             osi_Log0(smb_logp, "      Notify Change Attributes");
8145         if (filter & FILE_NOTIFY_CHANGE_SIZE)
8146             osi_Log0(smb_logp, "      Notify Change Size");
8147         if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8148             osi_Log0(smb_logp, "      Notify Change Last Write");
8149         if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8150             osi_Log0(smb_logp, "      Notify Change Last Access");
8151         if (filter & FILE_NOTIFY_CHANGE_CREATION)
8152             osi_Log0(smb_logp, "      Notify Change Creation");
8153         if (filter & FILE_NOTIFY_CHANGE_EA)
8154             osi_Log0(smb_logp, "      Notify Change Extended Attributes");
8155         if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8156             osi_Log0(smb_logp, "      Notify Change Security");
8157         if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8158             osi_Log0(smb_logp, "      Notify Change Stream Name");
8159         if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8160             osi_Log0(smb_logp, "      Notify Change Stream Size");
8161         if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8162             osi_Log0(smb_logp, "      Notify Change Stream Write");
8163                      
8164         /* A watch can only be notified once.  Remove it from the list */
8165         nextWatch = watch->nextp;
8166         if (watch == smb_Directory_Watches)
8167             smb_Directory_Watches = nextWatch;
8168         else
8169             lastWatch->nextp = nextWatch;
8170
8171         /* Turn off WATCHED flag in dscp */
8172         lock_ObtainMutex(&dscp->mx);
8173         if (wtree)
8174             dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8175         else
8176             dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8177         lock_ReleaseMutex(&dscp->mx);
8178
8179         /* Convert to response packet */
8180         ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
8181         ((smb_t *) watch)->wct = 0;
8182
8183         /* out parms */
8184         if (filename == NULL)
8185             parmCount = 0;
8186         else {
8187             nameLen = (ULONG)strlen(filename);
8188             parmCount = 3*4 + nameLen*2;
8189             parmCount = (parmCount + 3) & ~3;   /* pad to 4 */
8190             if (twoEntries) {
8191                 otherNameLen = (ULONG)strlen(otherFilename);
8192                 oldParmCount = parmCount;
8193                 parmCount += 3*4 + otherNameLen*2;
8194                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8195             }
8196             if (maxLen < parmCount)
8197                 parmCount = 0;  /* not enough room */
8198         }
8199         parmOffset = 8*4 + 39;
8200         parmOffset += 1;                        /* pad to 4 */
8201         dataOffset = parmOffset + parmCount;
8202
8203         parmSlot = 1;
8204         watch->oddByte = 1;
8205         /* Total Parameter Count */
8206         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8207         /* Total Data Count */
8208         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8209         /* Parameter Count */
8210         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8211         /* Parameter Offset */
8212         smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8213         /* Parameter Displacement */
8214         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8215         /* Data Count */
8216         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8217         /* Data Offset */
8218         smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8219         /* Data Displacement */
8220         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8221         smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8222         smb_SetSMBDataLength(watch, parmCount + 1);
8223
8224         if (parmCount != 0) {
8225             char * p;
8226             outData = smb_GetSMBData(watch, NULL);
8227             outData++;  /* round to get to parmOffset */
8228             oldOutData = outData;
8229             *((DWORD *)outData) = oldParmCount; outData += 4;
8230             /* Next Entry Offset */
8231             *((DWORD *)outData) = action; outData += 4;
8232             /* Action */
8233             *((DWORD *)outData) = nameLen*2; outData += 4;
8234             /* File Name Length */
8235             p = strdup(filename);
8236             if (smb_StoreAnsiFilenames)
8237                 CharToOem(p,p);
8238             mbstowcs((WCHAR *)outData, p, nameLen);
8239             free(p);
8240             /* File Name */
8241             if (twoEntries) {
8242                 outData = oldOutData + oldParmCount;
8243                 *((DWORD *)outData) = 0; outData += 4;
8244                 /* Next Entry Offset */
8245                 *((DWORD *)outData) = otherAction; outData += 4;
8246                 /* Action */
8247                 *((DWORD *)outData) = otherNameLen*2;
8248                 outData += 4;   /* File Name Length */
8249                 p = strdup(otherFilename);
8250                 if (smb_StoreAnsiFilenames)
8251                     CharToOem(p,p);
8252                 mbstowcs((WCHAR *)outData, p, otherNameLen);    /* File Name */
8253                 free(p);
8254             }       
8255         }       
8256
8257         /*
8258          * If filename is null, we don't know the cause of the
8259          * change notification.  We return zero data (see above),
8260          * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8261          * (= 0x010C).  We set the error code here by hand, without
8262          * modifying wct and bcc.
8263          */
8264         if (filename == NULL) {
8265             ((smb_t *) watch)->rcls = 0x0C;
8266             ((smb_t *) watch)->reh = 0x01;
8267             ((smb_t *) watch)->errLow = 0;
8268             ((smb_t *) watch)->errHigh = 0;
8269             /* Set NT Status codes flag */
8270             ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8271         }
8272
8273         smb_SendPacket(watch->vcp, watch);
8274         smb_FreePacket(watch);
8275         watch = nextWatch;
8276     }
8277     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8278 }       
8279
8280 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8281 {
8282     unsigned char *replyWctp;
8283     smb_packet_t *watch, *lastWatch;
8284     USHORT fid, watchtree;
8285     smb_fid_t *fidp;
8286     cm_scache_t *scp;
8287
8288     osi_Log0(smb_logp, "SMB3 receive NT cancel");
8289
8290     lock_ObtainMutex(&smb_Dir_Watch_Lock);
8291     watch = smb_Directory_Watches;
8292     while (watch) {
8293         if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8294              && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8295              && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8296              && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8297             if (watch == smb_Directory_Watches)
8298                 smb_Directory_Watches = watch->nextp;
8299             else
8300                 lastWatch->nextp = watch->nextp;
8301             lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8302
8303             /* Turn off WATCHED flag in scp */
8304             fid = smb_GetSMBParm(watch, 21);
8305             watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8306
8307             if (vcp != watch->vcp)
8308                 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x", 
8309                           vcp, watch->vcp);
8310
8311             fidp = smb_FindFID(vcp, fid, 0);
8312             if (fidp) {
8313                 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s", 
8314                           fid, watchtree,
8315                           osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
8316
8317                 scp = fidp->scp;
8318                 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8319                 lock_ObtainMutex(&scp->mx);
8320                 if (watchtree)
8321                     scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8322                 else
8323                     scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8324                 lock_ReleaseMutex(&scp->mx);
8325                 smb_ReleaseFID(fidp);
8326             } else {
8327                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8328             }
8329
8330             /* assume STATUS32; return 0xC0000120 (CANCELED) */
8331             replyWctp = watch->wctp;
8332             *replyWctp++ = 0;
8333             *replyWctp++ = 0;
8334             *replyWctp++ = 0;
8335             ((smb_t *)watch)->rcls = 0x20;
8336             ((smb_t *)watch)->reh = 0x1;
8337             ((smb_t *)watch)->errLow = 0;
8338             ((smb_t *)watch)->errHigh = 0xC0;
8339             ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8340             smb_SendPacket(vcp, watch);
8341             smb_FreePacket(watch);
8342             return 0;
8343         }
8344         lastWatch = watch;
8345         watch = watch->nextp;
8346     }
8347     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8348
8349     return 0;
8350 }
8351
8352 /*
8353  * NT rename also does hard links.
8354  */
8355
8356 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8357 #define RENAME_FLAG_HARD_LINK                0x103
8358 #define RENAME_FLAG_RENAME                   0x104
8359 #define RENAME_FLAG_COPY                     0x105
8360
8361 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8362 {
8363     char *oldPathp, *newPathp;
8364     long code = 0;
8365     char * tp;
8366     int attrs;
8367     int rename_type;
8368
8369     attrs = smb_GetSMBParm(inp, 0);
8370     rename_type = smb_GetSMBParm(inp, 1);
8371
8372     if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8373         osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8374         return CM_ERROR_NOACCESS;
8375     }
8376
8377     tp = smb_GetSMBData(inp, NULL);
8378     oldPathp = smb_ParseASCIIBlock(tp, &tp);
8379     if (smb_StoreAnsiFilenames)
8380         OemToChar(oldPathp,oldPathp);
8381     newPathp = smb_ParseASCIIBlock(tp, &tp);
8382     if (smb_StoreAnsiFilenames)
8383         OemToChar(newPathp,newPathp);
8384
8385     osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
8386              osi_LogSaveString(smb_logp, oldPathp),
8387              osi_LogSaveString(smb_logp, newPathp),
8388              ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8389
8390     if (rename_type == RENAME_FLAG_RENAME) {
8391         code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8392     } else { /* RENAME_FLAG_HARD_LINK */
8393         code = smb_Link(vcp,inp,oldPathp,newPathp);
8394     }
8395     return code;
8396 }
8397
8398 void smb3_Init()
8399 {
8400     lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8401 }
8402
8403 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
8404 {
8405     smb_username_t *unp;
8406     cm_user_t *     userp;
8407
8408     unp = smb_FindUserByName(usern, machine, flags);
8409     if (!unp->userp) {
8410         lock_ObtainMutex(&unp->mx);
8411         unp->userp = cm_NewUser();
8412         lock_ReleaseMutex(&unp->mx);
8413         osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8414     }  else     {
8415         osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8416     }
8417     userp = unp->userp;
8418     cm_HoldUser(userp);
8419     smb_ReleaseUsername(unp);
8420     return userp;
8421 }
8422