afslogon-wix-cleanup-20040715
[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 #define SECURITY_WIN32
16 #include <security.h>
17 #endif /* !DJGPP */
18 #include <stdlib.h>
19 #include <malloc.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <time.h>
23
24 #include <osi.h>
25
26 #include "afsd.h"
27
28 #include "smb.h"
29
30 extern osi_hyper_t hzero;
31
32 smb_packet_t *smb_Directory_Watches = NULL;
33 osi_mutex_t smb_Dir_Watch_Lock;
34
35 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
36
37 /* protected by the smb_globalLock */
38 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
39
40 /* retrieve a held reference to a user structure corresponding to an incoming
41  * request */
42 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
43 {
44         smb_user_t *uidp;
45     cm_user_t *up = NULL;
46         
47     uidp = smb_FindUID(vcp, inp->uid, 0);
48     if (!uidp) return NULL;
49         
50         lock_ObtainMutex(&uidp->mx);
51     if (uidp->unp) {
52         up = uidp->unp->userp;
53         cm_HoldUser(up);
54     }
55         lock_ReleaseMutex(&uidp->mx);
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                 attrs = SMB_ATTR_DIRECTORY;
74         else
75                 attrs = 0;
76         /*
77          * We used to mark a file RO if it was in an RO volume, but that
78          * turns out to be impolitic in NT.  See defect 10007.
79          */
80 #ifdef notdef
81         if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
82 #endif
83         if ((scp->unixModeBits & 0222) == 0)
84                 attrs |= SMB_ATTR_READONLY;             /* Read-only */
85
86         if (attrs == 0)
87                 attrs = SMB_ATTR_NORMAL;                /* FILE_ATTRIBUTE_NORMAL */
88
89         return attrs;
90 }
91
92 int smb_V3IsStarMask(char *maskp)
93 {
94     char tc;
95
96         while (tc = *maskp++)
97         if (tc == '?' || tc == '*') 
98             return 1;
99         return 0;
100 }
101
102 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
103 {
104     if (chainpp) {
105                 /* skip over null-terminated string */
106                 *chainpp = inp + strlen(inp) + 1;
107     }
108     return inp;
109 }   
110
111 /*DEBUG do not checkin*/
112 void OutputDebugF(char * format, ...) {
113 #ifdef COMMENT
114     va_list args;
115     int len;
116     char * buffer;
117
118     va_start( args, format );
119     len = _vscprintf( format, args ) // _vscprintf doesn't count
120                                + 3; // terminating '\0' + '\n'
121     buffer = malloc( len * sizeof(char) );
122     vsprintf( buffer, format, args );
123     strcat(buffer, "\n");
124     OutputDebugString(buffer);
125     free( buffer );
126 #endif
127 }
128
129 void OutputDebugHexDump(unsigned char * buffer, int len) {
130 #ifdef COMMENT
131     int i,j,k;
132     char buf[256];
133     static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
134
135     OutputDebugF("Hexdump length [%d]",len);
136
137     for(i=0;i<len;i++) {
138         if(!(i%16)) {
139             if(i)
140                 OutputDebugString(buf);
141             sprintf(buf,"%5x",i);
142             memset(buf+5,' ',80);
143             buf[85] = 0;
144             strcat(buf,"\n");
145         }
146
147         j = (i%16);
148         j = j*3 + 7 + ((j>7)?1:0);
149         k = buffer[i];
150
151         buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
152
153         j = (i%16);
154         j = j + 56 + ((j>7)?1:0);
155
156         buf[j] = (k>32 && k<127)?k:'.';
157     }    
158     if(i)
159         OutputDebugString(buf);
160 #endif
161 }   
162 /**/
163
164 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
165 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength){
166     SECURITY_STATUS status, istatus;
167         CredHandle creds = {0,0};
168         TimeStamp expiry;
169         SecBufferDesc secOut;
170         SecBuffer secTok;
171         CtxtHandle ctx;
172         ULONG flags;
173
174         *secBlob = NULL;
175         *secBlobLength = 0;
176
177     OutputDebugF("Negotiating Extended Security");
178
179         status = AcquireCredentialsHandle(
180                 NULL,
181                 SMB_EXT_SEC_PACKAGE_NAME,
182                 SECPKG_CRED_INBOUND,
183                 NULL,
184                 NULL,
185                 NULL,
186                 NULL,
187                 &creds,
188                 &expiry);
189
190         if (status != SEC_E_OK) {
191                 /* Really bad. We return an empty security blob */
192                 OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
193                 goto nes_0;
194         }
195
196         secOut.cBuffers = 1;
197         secOut.pBuffers = &secTok;
198         secOut.ulVersion = SECBUFFER_VERSION;
199
200         secTok.BufferType = SECBUFFER_TOKEN;
201         secTok.cbBuffer = 0;
202         secTok.pvBuffer = NULL;
203
204         ctx.dwLower = ctx.dwUpper = 0;
205
206         status = AcceptSecurityContext(
207                 &creds,
208                 NULL,
209                 NULL,
210         ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
211                 SECURITY_NETWORK_DREP,
212                 &ctx,
213                 &secOut,
214                 &flags,
215                 &expiry
216                 );
217
218         if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
219                 OutputDebugF("Completing token...");
220                 istatus = CompleteAuthToken(&ctx, &secOut);
221         if ( istatus != SEC_E_OK )
222             OutputDebugF("Token completion failed: %x", istatus);
223         }
224
225         if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
226                 if (secTok.pvBuffer) {
227                         *secBlobLength = secTok.cbBuffer;
228                         *secBlob = malloc( secTok.cbBuffer );
229                         memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
230                 }
231         } else {
232         if ( status != SEC_E_OK )
233             OutputDebugF("AcceptSecurityContext status != CONTINUE  %lX", status);
234     }
235
236     /* Discard partial security context */
237     DeleteSecurityContext(&ctx);
238
239         if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
240
241         /* Discard credentials handle.  We'll reacquire one when we get the session setup X */
242         FreeCredentialsHandle(&creds);
243
244   nes_0:
245         return;
246 }
247
248 struct smb_ext_context {
249         CredHandle creds;
250         CtxtHandle ctx;
251         int partialTokenLen;
252         void * partialToken;
253 };
254
255 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
256     SECURITY_STATUS status, istatus;
257         CredHandle creds;
258         TimeStamp expiry;
259         long code = 0;
260         SecBufferDesc secBufIn;
261         SecBuffer secTokIn;
262         SecBufferDesc secBufOut;
263         SecBuffer secTokOut;
264         CtxtHandle ctx;
265         struct smb_ext_context * secCtx = NULL;
266         struct smb_ext_context * newSecCtx = NULL;
267         void * assembledBlob = NULL;
268         int assembledBlobLength = 0;
269         ULONG flags;
270
271         OutputDebugF("In smb_AuthenticateUserExt");
272
273         *secBlobOut = NULL;
274         *secBlobOutLength = 0;
275
276         if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
277                 secCtx = vcp->secCtx;
278                 lock_ObtainMutex(&vcp->mx);
279                 vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
280                 vcp->secCtx = NULL;
281                 lock_ReleaseMutex(&vcp->mx);
282         }
283
284     if (secBlobIn) {
285         OutputDebugF("Received incoming token:");
286         OutputDebugHexDump(secBlobIn,secBlobInLength);
287     }
288     
289     if (secCtx) {
290         OutputDebugF("Continuing with existing context.");              
291         creds = secCtx->creds;
292         ctx = secCtx->ctx;
293
294                 if (secCtx->partialToken) {
295                         assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
296                         assembledBlob = malloc(assembledBlobLength);
297             memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
298                         memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
299                 }
300         } else {
301                 status = AcquireCredentialsHandle(
302                         NULL,
303                         SMB_EXT_SEC_PACKAGE_NAME,
304                         SECPKG_CRED_INBOUND,
305                         NULL,
306                         NULL,
307                         NULL,
308                         NULL,
309                         &creds,
310                         &expiry);
311
312                 if (status != SEC_E_OK) {
313                         OutputDebugF("Can't acquire Credentials handle [%lX]", status);
314                         code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
315                         goto aue_0;
316                 }
317
318                 ctx.dwLower = 0;
319                 ctx.dwUpper = 0;
320         }
321
322     secBufIn.cBuffers = 1;
323         secBufIn.pBuffers = &secTokIn;
324         secBufIn.ulVersion = SECBUFFER_VERSION;
325
326         secTokIn.BufferType = SECBUFFER_TOKEN;
327         if (assembledBlob) {
328                 secTokIn.cbBuffer = assembledBlobLength;
329                 secTokIn.pvBuffer = assembledBlob;
330         } else {
331                 secTokIn.cbBuffer = secBlobInLength;
332                 secTokIn.pvBuffer = secBlobIn;
333         }
334
335         secBufOut.cBuffers = 1;
336         secBufOut.pBuffers = &secTokOut;
337         secBufOut.ulVersion = SECBUFFER_VERSION;
338
339         secTokOut.BufferType = SECBUFFER_TOKEN;
340         secTokOut.cbBuffer = 0;
341         secTokOut.pvBuffer = NULL;
342
343         status = AcceptSecurityContext(
344                 &creds,
345                 ((secCtx)?&ctx:NULL),
346                 &secBufIn,
347                 ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR     | ASC_REQ_ALLOCATE_MEMORY,
348                 SECURITY_NETWORK_DREP,
349                 &ctx,
350                 &secBufOut,
351                 &flags,
352                 &expiry
353                 );
354
355         if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
356                 OutputDebugF("Completing token...");
357                 istatus = CompleteAuthToken(&ctx, &secBufOut);
358         if ( istatus != SEC_E_OK )
359             OutputDebugF("Token completion failed: %lX", istatus);
360         }
361
362         if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
363                 OutputDebugF("Continue needed");
364
365                 newSecCtx = malloc(sizeof(*newSecCtx));
366
367                 newSecCtx->creds = creds;
368                 newSecCtx->ctx = ctx;
369                 newSecCtx->partialToken = NULL;
370                 newSecCtx->partialTokenLen = 0;
371
372                 lock_ObtainMutex( &vcp->mx );
373                 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
374                 vcp->secCtx = newSecCtx;
375                 lock_ReleaseMutex( &vcp->mx );
376
377                 code = CM_ERROR_GSSCONTINUE;
378         }
379
380         if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK || 
381          status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) && 
382         secTokOut.pvBuffer) {
383                 OutputDebugF("Need to send token back to client");
384
385                 *secBlobOutLength = secTokOut.cbBuffer;
386                 *secBlobOut = malloc(secTokOut.cbBuffer);
387                 memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
388
389         OutputDebugF("Outgoing token:");
390         OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
391         } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
392                 OutputDebugF("Incomplete message");
393
394                 newSecCtx = malloc(sizeof(*newSecCtx));
395
396                 newSecCtx->creds = creds;
397                 newSecCtx->ctx = ctx;
398                 newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
399                 memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
400                 newSecCtx->partialTokenLen = secTokOut.cbBuffer;
401
402                 lock_ObtainMutex( &vcp->mx );
403                 vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
404                 vcp->secCtx = newSecCtx;
405                 lock_ReleaseMutex( &vcp->mx );
406
407                 code = CM_ERROR_GSSCONTINUE;
408         }
409
410         if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
411                 /* woo hoo! */
412                 SecPkgContext_Names names;
413
414                 OutputDebugF("Authentication completed");
415         OutputDebugF("Returned flags : [%lX]", flags);
416
417                 if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
418             OutputDebugF("Received name [%s]", names.sUserName);
419             strcpy(usern, names.sUserName);
420             strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
421             FreeContextBuffer(names.sUserName);
422         } else {
423             /* Force the user to retry if the context is invalid */
424             OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
425             code = CM_ERROR_BADPASSWORD; 
426         }
427         } else if (!code) {
428         switch ( status ) {
429         case SEC_E_INVALID_TOKEN:
430             OutputDebugF("Returning bad password :: INVALID_TOKEN");
431             break;
432         case SEC_E_INVALID_HANDLE:
433             OutputDebugF("Returning bad password :: INVALID_HANDLE");
434             break;
435         case SEC_E_LOGON_DENIED:
436             OutputDebugF("Returning bad password :: LOGON_DENIED");
437             break;
438         case SEC_E_UNKNOWN_CREDENTIALS:
439             OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
440             break;
441         case SEC_E_NO_CREDENTIALS:
442             OutputDebugF("Returning bad password :: NO_CREDENTIALS");
443             break;
444         case SEC_E_CONTEXT_EXPIRED:
445             OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
446             break;
447         case SEC_E_INCOMPLETE_CREDENTIALS:
448             OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
449             break;
450         case SEC_E_WRONG_PRINCIPAL:
451             OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
452             break;
453         case SEC_E_TIME_SKEW:
454             OutputDebugF("Returning bad password :: TIME_SKEW");
455             break;
456         default:
457             OutputDebugF("Returning bad password :: Status == %lX", status);
458         }
459                 code = CM_ERROR_BADPASSWORD;
460         }
461
462         if (secCtx) {
463                 if (secCtx->partialToken) free(secCtx->partialToken);
464                 free(secCtx);
465         }
466
467         if (assembledBlob) {
468                 free(assembledBlob);
469         }
470
471         if (secTokOut.pvBuffer)
472                 FreeContextBuffer(secTokOut.pvBuffer);
473
474         if (code != CM_ERROR_GSSCONTINUE) {
475                 DeleteSecurityContext(&ctx);
476                 FreeCredentialsHandle(&creds);
477         }
478
479   aue_0:
480         return code;
481 }
482
483 #define P_LEN 256
484 #define P_RESP_LEN 128
485
486 /* LsaLogonUser expects input parameters to be in a contiguous block of memory. 
487    So put stuff in a struct. */
488 struct Lm20AuthBlob {
489         MSV1_0_LM20_LOGON lmlogon;
490         BYTE ciResponse[P_RESP_LEN];    /* Unicode representation */
491         BYTE csResponse[P_RESP_LEN];    /* ANSI representation */
492         WCHAR accountNameW[P_LEN];
493         WCHAR primaryDomainW[P_LEN];
494         WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
495         TOKEN_GROUPS tgroups;
496         TOKEN_SOURCE tsource;
497 };
498
499 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength) {
500
501         NTSTATUS nts, ntsEx;
502         struct Lm20AuthBlob lmAuth;
503         PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
504         QUOTA_LIMITS quotaLimits;
505         DWORD size;
506         ULONG lmprofilepSize;
507         LUID lmSession;
508         HANDLE lmToken;
509
510         OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
511         OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
512
513         if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
514                 OutputDebugF("ciPwdLength or csPwdLength is too long");
515                 return CM_ERROR_BADPASSWORD;
516         }
517
518         memset(&lmAuth,0,sizeof(lmAuth));
519
520         lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
521         
522         lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
523         mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
524         lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
525         lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
526
527         lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
528         mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
529         lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
530         lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
531
532         lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
533         lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
534         size = MAX_COMPUTERNAME_LENGTH + 1;
535         GetComputerNameW(lmAuth.workstationW, &size);
536     lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
537
538         memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
539
540         lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
541         lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
542         lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
543         memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
544
545         lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
546         lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
547         lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
548         memcpy(lmAuth.csResponse, csPwd, csPwdLength);
549
550         lmAuth.lmlogon.ParameterControl = 0;
551
552         lmAuth.tgroups.GroupCount = 0;
553         lmAuth.tgroups.Groups[0].Sid = NULL;
554         lmAuth.tgroups.Groups[0].Attributes = 0;
555
556         lmAuth.tsource.SourceIdentifier.HighPart = 0;
557         lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
558         strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
559
560         nts = LsaLogonUser(
561                 smb_lsaHandle,
562                 &smb_lsaLogonOrigin,
563                 Network, /*3*/
564         smb_lsaSecPackage,
565                 &lmAuth,
566                 sizeof(lmAuth),
567         &lmAuth.tgroups,
568                 &lmAuth.tsource,
569                 &lmprofilep,
570                 &lmprofilepSize,
571                 &lmSession,
572                 &lmToken,
573                 &quotaLimits,
574                 &ntsEx);
575
576         OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
577         OutputDebugF("Extended status is 0x%lX", ntsEx);
578
579         if (nts == ERROR_SUCCESS) {
580                 /* free the token */
581                 LsaFreeReturnBuffer(lmprofilep);
582         CloseHandle(lmToken);
583                 return 0;
584         } else {
585                 /* No AFS for you */
586                 if (nts == 0xC000015BL)
587                         return CM_ERROR_BADLOGONTYPE;
588                 else /* our catchall is a bad password though we could be more specific */
589                         return CM_ERROR_BADPASSWORD;
590         }
591 }
592
593 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
594 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName) {
595
596         char * atsign;
597         const char * domain;
598
599         /* check if we have sane input */
600         if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
601                 return 1;
602
603         /* we could get : [accountName][domainName]
604            [user][domain]
605            [user@domain][]
606            [user][]/[user][?]
607            [][]/[][?] */
608
609         atsign = strchr(accountName, '@');
610
611         if (atsign) /* [user@domain][] -> [user@domain][domain] */
612                 domain = atsign + 1;
613         else
614                 domain = domainName;
615
616         /* if for some reason the client doesn't know what domain to use,
617                    it will either return an empty string or a '?' */
618         if (!domain[0] || domain[0] == '?')
619                 /* Empty domains and empty usernames are usually sent from tokenless contexts.
620                    This way such logins will get an empty username (easy to check).  I don't know 
621                    when a non-empty username would be supplied with an anonymous domain, but *shrug* */
622                 strcpy(usern,accountName);
623         else {
624                 /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
625                 strcpy(usern,domain);
626                 strcat(usern,"\\");
627                 if (atsign)
628                         strncat(usern,accountName,atsign - accountName);
629                 else
630                         strcat(usern,accountName);
631         }
632
633         strlwr(usern);
634
635         return 0;
636 }
637
638 /* When using SMB auth, all SMB sessions have to pass through here first to
639  * authenticate the user. 
640  * Caveat: If not use the SMB auth the protocol does not require sending a
641  * session setup packet, which means that we can't rely on a UID in subsequent
642  * packets.  Though in practice we get one anyway.
643  */
644 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
645 {
646     char *tp;
647     smb_user_t *uidp;
648     unsigned short newUid;
649     unsigned long caps = 0;
650     cm_user_t *userp;
651     smb_username_t *unp;
652     char *s1 = " ";
653     long code = 0; 
654     char usern[SMB_MAX_USERNAME_LENGTH];
655     char *secBlobOut = NULL;
656     int  secBlobOutLength = 0;
657
658     /* Check for bad conns */
659     if (vcp->flags & SMB_VCFLAG_REMOTECONN)
660         return CM_ERROR_REMOTECONN;
661
662     if (vcp->flags & SMB_VCFLAG_USENT) {
663         if (smb_authType == SMB_AUTH_EXTENDED) {
664             /* extended authentication */
665             char *secBlobIn;
666             int secBlobInLength;
667         
668             if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
669                 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
670             }
671
672             secBlobInLength = smb_GetSMBParm(inp, 7);
673             secBlobIn = smb_GetSMBData(inp, NULL);
674
675             code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
676
677             if (code == CM_ERROR_GSSCONTINUE) {
678                 smb_SetSMBParm(outp, 2, 0);
679                 smb_SetSMBParm(outp, 3, secBlobOutLength);
680                 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
681                 tp = smb_GetSMBData(outp, NULL);
682                 if (secBlobOutLength) {
683                     memcpy(tp, secBlobOut, secBlobOutLength);
684                     free(secBlobOut);
685                     tp += secBlobOutLength;
686                 }       
687                 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
688                 tp += smb_ServerOSLength;
689                 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
690                 tp += smb_ServerLanManagerLength;
691                 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
692                 tp += smb_ServerDomainNameLength;
693             }
694
695             /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
696         } else {
697             unsigned ciPwdLength, csPwdLength;
698             char *ciPwd, *csPwd;
699             char *accountName;
700             char *primaryDomain;
701             int  datalen;
702
703             /* TODO: parse for extended auth as well */
704             ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
705             csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
706
707             tp = smb_GetSMBData(inp, &datalen);
708
709             OutputDebugF("Session packet data size [%d]",datalen);
710
711             ciPwd = tp;
712             tp += ciPwdLength;
713             csPwd = tp;
714             tp += csPwdLength;
715
716             accountName = smb_ParseString(tp, &tp);
717             primaryDomain = smb_ParseString(tp, NULL);
718
719             if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
720                 /* shouldn't happen */
721                 code = CM_ERROR_BADSMB;
722                 goto after_read_packet;
723             }
724
725             /* capabilities are only valid for first session packet */
726             if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
727                 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
728             }
729
730             if (smb_authType == SMB_AUTH_NTLM) {
731                 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
732             }
733         }
734     }  else { /* V3 */
735         unsigned ciPwdLength;
736         char *ciPwd;
737                 char *accountName;
738                 char *primaryDomain;
739
740                 ciPwdLength = smb_GetSMBParm(inp, 7);
741         tp = smb_GetSMBData(inp, NULL);
742                 ciPwd = tp;
743                 tp += ciPwdLength;
744
745                 accountName = smb_ParseString(tp, &tp);
746                 primaryDomain = smb_ParseString(tp, NULL);
747
748                 if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
749                         /* shouldn't happen */
750                         code = CM_ERROR_BADSMB;
751             goto after_read_packet;
752                 }
753
754         /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
755          * to NTLM.
756          */
757                 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
758                         code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
759                 }
760         }
761
762   after_read_packet:
763         /* note down that we received a session setup X and set the capabilities flag */
764         if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
765                 lock_ObtainMutex(&vcp->mx);
766                 vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
767         /* for the moment we can only deal with NTSTATUS */
768         if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
769             vcp->flags |= SMB_VCFLAG_STATUS32;
770         }
771                 lock_ReleaseMutex(&vcp->mx);
772         }
773
774         /* code would be non-zero if there was an authentication failure.
775            Ideally we would like to invalidate the uid for this session or break
776            early to avoid accidently stealing someone else's tokens. */
777
778         if (code) {
779                 return code;
780         }
781
782         OutputDebugF("Received username=[%s]", usern);
783
784     /* On Windows 2000, this function appears to be called more often than
785        it is expected to be called. This resulted in multiple smb_user_t
786        records existing all for the same user session which results in all
787        of the users tokens disappearing.
788
789        To avoid this problem, we look for an existing smb_user_t record
790        based on the users name, and use that one if we find it.
791     */
792
793     uidp = smb_FindUserByNameThisSession(vcp, usern);
794     if (uidp) {   /* already there, so don't create a new one */
795         unp = uidp->unp;
796         userp = unp->userp;
797         newUid = (unsigned short)uidp->userID;  /* For some reason these are different types!*/
798                 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"FindUserByName:Lana[%d],lsn[%d],userid[%d],name[%s]",vcp->lana,vcp->lsn,newUid,usern);
799                 osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
800         smb_ReleaseUID(uidp);
801     }
802     else {
803       /* do a global search for the username/machine name pair */
804         unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
805
806         /* Create a new UID and cm_user_t structure */
807         userp = unp->userp;
808         if (!userp)
809             userp = cm_NewUser();
810         lock_ObtainMutex(&vcp->mx);
811         if (!vcp->uidCounter)
812             vcp->uidCounter++; /* handle unlikely wraparounds */
813         newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
814         lock_ReleaseMutex(&vcp->mx);
815
816         /* Create a new smb_user_t structure and connect them up */
817         lock_ObtainMutex(&unp->mx);
818         unp->userp = userp;
819         lock_ReleaseMutex(&unp->mx);
820
821         uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
822         lock_ObtainMutex(&uidp->mx);
823         uidp->unp = unp;
824                 osi_LogEvent("AFS smb_ReceiveV3SessionSetupX",NULL,"MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d],TicketKTCName[%s]",(int)vcp,vcp->lana,vcp->lsn,newUid,usern);
825                 osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
826         lock_ReleaseMutex(&uidp->mx);
827         smb_ReleaseUID(uidp);
828     }
829
830     /* Return UID to the client */
831     ((smb_t *)outp)->uid = newUid;
832     /* Also to the next chained message */
833     ((smb_t *)inp)->uid = newUid;
834
835     osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
836              osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
837
838     smb_SetSMBParm(outp, 2, 0);
839
840     if (vcp->flags & SMB_VCFLAG_USENT) {
841         if (smb_authType == SMB_AUTH_EXTENDED) {
842             smb_SetSMBParm(outp, 3, secBlobOutLength);
843             smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
844             tp = smb_GetSMBData(outp, NULL);
845             if (secBlobOutLength) {
846                 memcpy(tp, secBlobOut, secBlobOutLength);
847                 free(secBlobOut);
848                 tp += secBlobOutLength;
849             }   
850             memcpy(tp,smb_ServerOS,smb_ServerOSLength);
851             tp += smb_ServerOSLength;
852             memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
853             tp += smb_ServerLanManagerLength;
854             memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
855             tp += smb_ServerDomainNameLength;
856         } else {
857             smb_SetSMBDataLength(outp, 0);
858         }
859     } else {
860         if (smb_authType == SMB_AUTH_EXTENDED) {
861             smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
862             tp = smb_GetSMBData(outp, NULL);
863             memcpy(tp,smb_ServerOS,smb_ServerOSLength);
864             tp += smb_ServerOSLength;
865             memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
866             tp += smb_ServerLanManagerLength;
867             memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
868             tp += smb_ServerDomainNameLength;
869         } else {
870             smb_SetSMBDataLength(outp, 0);
871         }
872     }
873
874     return 0;
875 }
876
877 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
878 {
879         smb_user_t *uidp;
880
881         /* don't get tokens from this VC */
882         vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
883
884         inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
885
886         /* find the tree and free it */
887     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
888     /* TODO: smb_ReleaseUID() ? */
889     if (uidp) {
890                 char *s1 = NULL, *s2 = NULL;
891
892                 if (s2 == NULL) s2 = " ";
893                 if (s1 == NULL) {s1 = s2; s2 = " ";}
894
895                 osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
896                  osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "), s1, s2);
897
898                 lock_ObtainMutex(&uidp->mx);
899                 uidp->flags |= SMB_USERFLAG_DELETE;
900                 /*
901                  * it doesn't get deleted right away
902                  * because the vcp points to it
903                  */
904         lock_ReleaseMutex(&uidp->mx);
905     }
906         else    
907                 osi_Log0(smb_logp, "SMB3 user logoffX");
908
909     smb_SetSMBDataLength(outp, 0);
910     return 0;
911 }
912
913 #define SMB_SUPPORT_SEARCH_BITS        0x0001
914
915 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
916 {
917     smb_tid_t *tidp;
918     smb_user_t *uidp;
919     unsigned short newTid;
920     char shareName[256];
921         char *sharePath;
922         int shareFound;
923     char *tp;
924     char *pathp;
925     char *passwordp;
926         char *servicep;
927     cm_user_t *userp;
928         
929         osi_Log0(smb_logp, "SMB3 receive tree connect");
930
931         /* parse input parameters */
932         tp = smb_GetSMBData(inp, NULL);
933     passwordp = smb_ParseString(tp, &tp);
934         pathp = smb_ParseString(tp, &tp);
935         servicep = smb_ParseString(tp, &tp);
936
937         tp = strrchr(pathp, '\\');
938     if (!tp) {
939         return CM_ERROR_BADSMB;
940     }
941     strcpy(shareName, tp+1);
942
943         if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0)
944                 return CM_ERROR_NOIPC;
945
946     userp = smb_GetUser(vcp, inp);
947
948         lock_ObtainMutex(&vcp->mx);
949     newTid = vcp->tidCounter++;
950         lock_ReleaseMutex(&vcp->mx);
951         
952         tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
953     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
954         shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
955     if (uidp)
956         smb_ReleaseUID(uidp);
957         if (!shareFound) {
958                 smb_ReleaseTID(tidp);
959                 return CM_ERROR_BADSHARENAME;
960         }
961     lock_ObtainMutex(&tidp->mx);
962     tidp->userp = userp;
963         tidp->pathname = sharePath;
964     lock_ReleaseMutex(&tidp->mx);
965     smb_ReleaseTID(tidp);
966
967         if (vcp->flags & SMB_VCFLAG_USENT)
968     {
969         int policy = smb_FindShareCSCPolicy(shareName);
970         smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
971     }
972
973         ((smb_t *)outp)->tid = newTid;
974         ((smb_t *)inp)->tid = newTid;
975         tp = smb_GetSMBData(outp, NULL);
976     *tp++ = 'A';
977     *tp++ = ':';
978     *tp++ = 0;
979     smb_SetSMBDataLength(outp, 3);
980
981     osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
982     return 0;
983 }
984
985 /* must be called with global tran lock held */
986 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
987 {
988         smb_tran2Packet_t *tp;
989     smb_t *smbp;
990         
991     smbp = (smb_t *) inp->data;
992         for(tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
993                 if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
994             return tp;
995     }
996     return NULL;
997 }
998
999 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1000         int totalParms, int totalData)
1001 {
1002         smb_tran2Packet_t *tp;
1003     smb_t *smbp;
1004         
1005     smbp = (smb_t *) inp->data;
1006         tp = malloc(sizeof(*tp));
1007     memset(tp, 0, sizeof(*tp));
1008     tp->vcp = vcp;
1009     smb_HoldVC(vcp);
1010     tp->curData = tp->curParms = 0;
1011     tp->totalData = totalData;
1012     tp->totalParms = totalParms;
1013     tp->tid = smbp->tid;
1014     tp->mid = smbp->mid;
1015     tp->uid = smbp->uid;
1016     tp->pid = smbp->pid;
1017         tp->res[0] = smbp->res[0];
1018         osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1019     tp->opcode = smb_GetSMBParm(inp, 14);
1020         if (totalParms != 0)
1021         tp->parmsp = malloc(totalParms);
1022         if (totalData != 0)
1023         tp->datap = malloc(totalData);
1024         tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1025     return tp;
1026 }
1027
1028 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1029         smb_tran2Packet_t *inp, smb_packet_t *outp,
1030         int totalParms, int totalData)
1031 {
1032         smb_tran2Packet_t *tp;
1033         unsigned short parmOffset;
1034         unsigned short dataOffset;
1035         unsigned short dataAlign;
1036         
1037         tp = malloc(sizeof(*tp));
1038     memset(tp, 0, sizeof(*tp));
1039     tp->vcp = NULL;
1040     tp->curData = tp->curParms = 0;
1041     tp->totalData = totalData;
1042     tp->totalParms = totalParms;
1043         tp->oldTotalParms = totalParms;
1044     tp->tid = inp->tid;
1045     tp->mid = inp->mid;
1046     tp->uid = inp->uid;
1047     tp->pid = inp->pid;
1048         tp->res[0] = inp->res[0];
1049     tp->opcode = inp->opcode;
1050
1051         /*
1052          * We calculate where the parameters and data will start.
1053          * This calculation must parallel the calculation in
1054          * smb_SendTran2Packet.
1055          */
1056
1057         parmOffset = 10*2 + 35;
1058         parmOffset++;                   /* round to even */
1059         tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1060
1061         dataOffset = parmOffset + totalParms;
1062         dataAlign = dataOffset & 2;     /* quad-align */
1063         dataOffset += dataAlign;
1064         tp->datap = outp->data + dataOffset;
1065
1066     return tp;
1067 }
1068
1069 /* free a tran2 packet; must be called with smb_globalLock held */
1070 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1071 {
1072     if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1073         if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1074                 if (t2p->parmsp)
1075                         free(t2p->parmsp);
1076                 if (t2p->datap)
1077                         free(t2p->datap);
1078         }
1079     free(t2p);
1080 }
1081
1082 /* called with a VC, an input packet to respond to, and an error code.
1083  * sends an error response.
1084  */
1085 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1086         smb_packet_t *tp, long code)
1087 {
1088     smb_t *smbp;
1089     unsigned short errCode;
1090     unsigned char errClass;
1091         unsigned long NTStatus;
1092
1093     if (vcp->flags & SMB_VCFLAG_STATUS32)
1094                 smb_MapNTError(code, &NTStatus);
1095         else
1096                 smb_MapCoreError(code, vcp, &errCode, &errClass);
1097
1098     smb_FormatResponsePacket(vcp, NULL, tp);
1099     smbp = (smb_t *) tp;
1100
1101         /* We can handle long names */
1102         if (vcp->flags & SMB_VCFLAG_USENT)
1103                 smbp->flg2 |= 0x40;     /* IS_LONG_NAME */
1104         
1105     /* now copy important fields from the tran 2 packet */
1106     smbp->com = 0x32;           /* tran 2 response */
1107     smbp->tid = t2p->tid;
1108     smbp->mid = t2p->mid;
1109     smbp->pid = t2p->pid;
1110     smbp->uid = t2p->uid;
1111         smbp->res[0] = t2p->res[0];
1112         if (vcp->flags & SMB_VCFLAG_STATUS32) {
1113                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
1114                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1115                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1116                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1117                 smbp->flg2 |= 0x4000;
1118         }
1119         else {
1120         smbp->rcls = errClass;
1121                 smbp->errLow = (unsigned char) (errCode & 0xff);
1122                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1123         }
1124         
1125     /* send packet */
1126     smb_SendPacket(vcp, tp);
1127 }        
1128
1129 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1130 {
1131     smb_t *smbp;
1132     unsigned short parmOffset;
1133         unsigned short dataOffset;
1134         unsigned short totalLength;
1135         unsigned short dataAlign;
1136     char *datap;
1137         
1138     smb_FormatResponsePacket(vcp, NULL, tp);
1139     smbp = (smb_t *) tp;
1140
1141         /* We can handle long names */
1142         if (vcp->flags & SMB_VCFLAG_USENT)
1143                 smbp->flg2 |= 0x40;     /* IS_LONG_NAME */
1144
1145     /* now copy important fields from the tran 2 packet */
1146     smbp->com = 0x32;           /* tran 2 response */
1147     smbp->tid = t2p->tid;
1148     smbp->mid = t2p->mid;
1149     smbp->pid = t2p->pid;
1150     smbp->uid = t2p->uid;
1151         smbp->res[0] = t2p->res[0];
1152
1153     totalLength = 1 + t2p->totalData + t2p->totalParms;
1154
1155     /* now add the core parameters (tran2 info) to the packet */
1156     smb_SetSMBParm(tp, 0, t2p->totalParms);     /* parm bytes */
1157     smb_SetSMBParm(tp, 1, t2p->totalData);      /* data bytes */
1158     smb_SetSMBParm(tp, 2, 0);           /* reserved */
1159     smb_SetSMBParm(tp, 3, t2p->totalParms);     /* parm bytes in this packet */
1160         parmOffset = 10*2 + 35;                 /* parm offset in packet */
1161         parmOffset++;                           /* round to even */
1162     smb_SetSMBParm(tp, 4, parmOffset);  /* 11 parm words plus *
1163     * hdr, bcc and wct */
1164     smb_SetSMBParm(tp, 5, 0);           /* parm displacement */
1165     smb_SetSMBParm(tp, 6, t2p->totalData);      /* data in this packet */
1166         dataOffset = parmOffset + t2p->oldTotalParms;
1167         dataAlign = dataOffset & 2;             /* quad-align */
1168         dataOffset += dataAlign;
1169     smb_SetSMBParm(tp, 7, dataOffset);  /* offset of data */
1170     smb_SetSMBParm(tp, 8, 0);           /* data displacement */
1171     smb_SetSMBParm(tp, 9, 0);           /* low: setup word count *
1172     * high: resvd */
1173
1174     datap = smb_GetSMBData(tp, NULL);
1175         *datap++ = 0;                           /* we rounded to even */
1176
1177         totalLength += dataAlign;
1178     smb_SetSMBDataLength(tp, totalLength);
1179         
1180     /* next, send the datagram */
1181     smb_SendPacket(vcp, tp);
1182 }   
1183
1184 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1185 {
1186     smb_tran2Packet_t *asp;
1187     int totalParms;
1188     int totalData;
1189     int parmDisp;
1190     int dataDisp;
1191     int parmOffset;
1192     int dataOffset;
1193     int parmCount;
1194     int dataCount;
1195     int firstPacket;
1196     long code = 0;
1197
1198         /* We sometimes see 0 word count.  What to do? */
1199         if (*inp->wctp == 0) {
1200 #ifndef DJGPP
1201                 HANDLE h;
1202                 char *ptbuf[1];
1203
1204                 osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
1205
1206                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1207                 ptbuf[0] = "Transaction2 word count = 0";
1208                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1209                             1, inp->ncb_length, ptbuf, inp);
1210                 DeregisterEventSource(h);
1211 #else /* DJGPP */
1212                 osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
1213 #endif /* !DJGPP */
1214
1215         smb_SetSMBDataLength(outp, 0);
1216         smb_SendPacket(vcp, outp);
1217                 return 0;
1218         }
1219
1220     totalParms = smb_GetSMBParm(inp, 0);
1221     totalData = smb_GetSMBParm(inp, 1);
1222         
1223     firstPacket = (inp->inCom == 0x32);
1224         
1225         /* find the packet we're reassembling */
1226         lock_ObtainWrite(&smb_globalLock);
1227     asp = smb_FindTran2Packet(vcp, inp);
1228     if (!asp) {
1229         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1230         }
1231     lock_ReleaseWrite(&smb_globalLock);
1232         
1233     /* now merge in this latest packet; start by looking up offsets */
1234         if (firstPacket) {
1235                 parmDisp = dataDisp = 0;
1236         parmOffset = smb_GetSMBParm(inp, 10);
1237         dataOffset = smb_GetSMBParm(inp, 12);
1238         parmCount = smb_GetSMBParm(inp, 9);
1239         dataCount = smb_GetSMBParm(inp, 11);
1240                 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1241         asp->maxReturnData = smb_GetSMBParm(inp, 3);
1242
1243                 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1244                  totalData, dataCount, asp->maxReturnData);
1245     }
1246     else {
1247         parmDisp = smb_GetSMBParm(inp, 4);
1248         parmOffset = smb_GetSMBParm(inp, 3);
1249         dataDisp = smb_GetSMBParm(inp, 7);
1250         dataOffset = smb_GetSMBParm(inp, 6);
1251         parmCount = smb_GetSMBParm(inp, 2);
1252         dataCount = smb_GetSMBParm(inp, 5);
1253
1254         osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1255                  parmCount, dataCount);
1256     }   
1257
1258     /* now copy the parms and data */
1259     if ( parmCount != 0 )
1260     {
1261         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1262     }
1263     if ( dataCount != 0 ) {
1264         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1265     }
1266
1267     /* account for new bytes */
1268     asp->curData += dataCount;
1269     asp->curParms += parmCount;
1270
1271     /* finally, if we're done, remove the packet from the queue and dispatch it */
1272     if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
1273                 /* we've received it all */
1274         lock_ObtainWrite(&smb_globalLock);
1275                 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1276         lock_ReleaseWrite(&smb_globalLock);
1277
1278         /* now dispatch it */
1279         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1280             osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1281             osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1282             code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1283         }
1284         else {
1285             osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1286             osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1287             code = CM_ERROR_BADOP;
1288         }
1289
1290                 /* if an error is returned, we're supposed to send an error packet,
1291          * otherwise the dispatched function already did the data sending.
1292          * We give dispatched proc the responsibility since it knows how much
1293          * space to allocate.
1294          */
1295         if (code != 0) {
1296             smb_SendTran2Error(vcp, asp, outp, code);
1297         }
1298
1299                 /* free the input tran 2 packet */
1300                 lock_ObtainWrite(&smb_globalLock);
1301         smb_FreeTran2Packet(asp);
1302                 lock_ReleaseWrite(&smb_globalLock);
1303     }
1304     else if (firstPacket) {
1305                 /* the first packet in a multi-packet request, we need to send an
1306          * ack to get more data.
1307          */
1308         smb_SetSMBDataLength(outp, 0);
1309         smb_SendPacket(vcp, outp);
1310     }
1311
1312         return 0;
1313 }
1314
1315 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1316 {
1317         char *pathp;
1318     smb_tran2Packet_t *outp;
1319     long code = 0;
1320         cm_space_t *spacep;
1321     int excl;
1322     cm_user_t *userp;
1323     cm_scache_t *dscp;          /* dir we're dealing with */
1324     cm_scache_t *scp;           /* file we're creating */
1325     cm_attr_t setAttr;
1326     int initialModeBits;
1327     smb_fid_t *fidp;
1328     int attributes;
1329     char *lastNamep;
1330     long dosTime;
1331     int openFun;
1332     int trunc;
1333     int openMode;
1334     int extraInfo;
1335     int openAction;
1336     int parmSlot;                       /* which parm we're dealing with */
1337     long returnEALength;
1338         char *tidPathp;
1339         cm_req_t req;
1340
1341         cm_InitReq(&req);
1342
1343     scp = NULL;
1344         
1345         extraInfo = (p->parmsp[0] & 1); /* return extra info */
1346     returnEALength = (p->parmsp[0] & 8);        /* return extended attr length */
1347
1348         openFun = p->parmsp[6];         /* open function */
1349     excl = ((openFun & 3) == 0);
1350     trunc = ((openFun & 3) == 2);       /* truncate it */
1351         openMode = (p->parmsp[1] & 0x7);
1352     openAction = 0;                     /* tracks what we did */
1353
1354     attributes = p->parmsp[3];
1355     dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
1356         
1357         /* compute initial mode bits based on read-only flag in attributes */
1358     initialModeBits = 0666;
1359     if (attributes & 1) initialModeBits &= ~0222;
1360         
1361     pathp = (char *) (&p->parmsp[14]);
1362         
1363     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
1364
1365         spacep = cm_GetSpace();
1366     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1367
1368         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
1369                 /* special case magic file name for receiving IOCTL requests
1370          * (since IOCTL calls themselves aren't getting through).
1371          */
1372         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
1373         smb_SetupIoctlFid(fidp, spacep);
1374
1375         /* copy out remainder of the parms */
1376                 parmSlot = 0;
1377                 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
1378                 if (extraInfo) {
1379             outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
1380             outp->parmsp[parmSlot] = 0; parmSlot++;     /* mod time */
1381             outp->parmsp[parmSlot] = 0; parmSlot++;
1382             outp->parmsp[parmSlot] = 0; parmSlot++;     /* len */
1383             outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
1384             outp->parmsp[parmSlot] = openMode; parmSlot++;
1385             outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
1386             outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
1387                 }   
1388                 /* and the final "always present" stuff */
1389         outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
1390                 /* next write out the "unique" ID */
1391                 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
1392                 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
1393         outp->parmsp[parmSlot] = 0; parmSlot++;
1394                 if (returnEALength) {
1395                         outp->parmsp[parmSlot] = 0; parmSlot++;
1396                         outp->parmsp[parmSlot] = 0; parmSlot++;
1397         }
1398                 
1399         outp->totalData = 0;
1400         outp->totalParms = parmSlot * 2;
1401                 
1402         smb_SendTran2Packet(vcp, outp, op);
1403                 
1404         smb_FreeTran2Packet(outp);
1405
1406                 /* and clean up fid reference */
1407         smb_ReleaseFID(fidp);
1408         return 0;
1409     }
1410
1411 #ifdef DEBUG_VERBOSE
1412         {
1413                 char *hexp, *asciip;
1414                 asciip = (lastNamep ? lastNamep : pathp);
1415                 hexp = osi_HexifyString( asciip );
1416                 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
1417                 free(hexp);
1418         }
1419 #endif
1420
1421         userp = smb_GetTran2User(vcp, p);
1422     /* In the off chance that userp is NULL, we log and abandon */
1423     if (!userp) {
1424         osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
1425         smb_FreeTran2Packet(outp);
1426         return CM_ERROR_BADSMB;
1427     }
1428
1429         tidPathp = smb_GetTIDPath(vcp, p->tid);
1430
1431         dscp = NULL;
1432         code = cm_NameI(cm_rootSCachep, pathp,
1433                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
1434                     userp, tidPathp, &req, &scp);
1435         if (code != 0) {
1436                 code = cm_NameI(cm_rootSCachep, spacep->data,
1437                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
1438                         userp, tidPathp, &req, &dscp);
1439                 cm_FreeSpace(spacep);
1440
1441         if (code) {
1442             cm_ReleaseUser(userp);
1443                         smb_FreeTran2Packet(outp);
1444             return code;
1445         }
1446         
1447         /* otherwise, scp points to the parent directory.  Do a lookup,
1448                  * and truncate the file if we find it, otherwise we create the
1449                  * file.
1450          */
1451         if (!lastNamep) lastNamep = pathp;
1452         else lastNamep++;
1453         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
1454                          &req, &scp);
1455         if (code && code != CM_ERROR_NOSUCHFILE) {
1456                         cm_ReleaseSCache(dscp);
1457             cm_ReleaseUser(userp);
1458                         smb_FreeTran2Packet(outp);
1459             return code;
1460         }
1461         }
1462     else {
1463         cm_FreeSpace(spacep);
1464         }
1465         
1466     /* if we get here, if code is 0, the file exists and is represented by
1467      * scp.  Otherwise, we have to create it.
1468      */
1469         if (code == 0) {
1470         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
1471         if (code) {
1472             if (dscp) cm_ReleaseSCache(dscp);
1473             cm_ReleaseSCache(scp);
1474             cm_ReleaseUser(userp);
1475                         smb_FreeTran2Packet(outp);
1476             return code;
1477         }
1478
1479                 if (excl) {
1480                         /* oops, file shouldn't be there */
1481             if (dscp) cm_ReleaseSCache(dscp);
1482             cm_ReleaseSCache(scp);
1483             cm_ReleaseUser(userp);
1484                         smb_FreeTran2Packet(outp);
1485             return CM_ERROR_EXISTS;
1486         }
1487
1488                 if (trunc) {
1489                         setAttr.mask = CM_ATTRMASK_LENGTH;
1490             setAttr.length.LowPart = 0;
1491             setAttr.length.HighPart = 0;
1492                         code = cm_SetAttr(scp, &setAttr, userp, &req);
1493             openAction = 3;     /* truncated existing file */
1494                 }   
1495         else openAction = 1;    /* found existing file */
1496     }
1497         else if (!(openFun & SMB_ATTR_DIRECTORY)) {
1498                 /* don't create if not found */
1499         if (dscp) cm_ReleaseSCache(dscp);
1500         osi_assert(scp == NULL);
1501         cm_ReleaseUser(userp);
1502                 smb_FreeTran2Packet(outp);
1503         return CM_ERROR_NOSUCHFILE;
1504     }
1505     else {
1506                 osi_assert(dscp != NULL && scp == NULL);
1507                 openAction = 2; /* created file */
1508                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
1509                 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
1510         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
1511                          &req);
1512                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
1513                         smb_NotifyChange(FILE_ACTION_ADDED,
1514                              FILE_NOTIFY_CHANGE_FILE_NAME,  
1515                              dscp, lastNamep, NULL, TRUE);
1516         if (!excl && code == CM_ERROR_EXISTS) {
1517                         /* not an exclusive create, and someone else tried
1518                          * creating it already, then we open it anyway.  We
1519                          * don't bother retrying after this, since if this next
1520                          * fails, that means that the file was deleted after we
1521                          * started this call.
1522              */
1523             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
1524                              userp, &req, &scp);
1525             if (code == 0) {
1526                 if (trunc) {
1527                                         setAttr.mask = CM_ATTRMASK_LENGTH;
1528                     setAttr.length.LowPart = 0;
1529                     setAttr.length.HighPart = 0;
1530                     code = cm_SetAttr(scp, &setAttr, userp,
1531                                       &req);
1532                 }   
1533                         }       /* lookup succeeded */
1534         }
1535     }
1536         
1537         /* we don't need this any longer */
1538         if (dscp) cm_ReleaseSCache(dscp);
1539
1540     if (code) {
1541                 /* something went wrong creating or truncating the file */
1542         if (scp) cm_ReleaseSCache(scp);
1543         cm_ReleaseUser(userp);
1544                 smb_FreeTran2Packet(outp);
1545         return code;
1546     }
1547         
1548         /* make sure we're about to open a file */
1549         if (scp->fileType != CM_SCACHETYPE_FILE) {
1550                 cm_ReleaseSCache(scp);
1551                 cm_ReleaseUser(userp);
1552                 smb_FreeTran2Packet(outp);
1553                 return CM_ERROR_ISDIR;
1554         }
1555
1556     /* now all we have to do is open the file itself */
1557     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
1558     osi_assert(fidp);
1559         
1560         /* save a pointer to the vnode */
1561     fidp->scp = scp;
1562         
1563         /* compute open mode */
1564     if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
1565     if (openMode == 1 || openMode == 2)
1566         fidp->flags |= SMB_FID_OPENWRITE;
1567
1568         smb_ReleaseFID(fidp);
1569         
1570         cm_Open(scp, 0, userp);
1571
1572     /* copy out remainder of the parms */
1573         parmSlot = 0;
1574         outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
1575         lock_ObtainMutex(&scp->mx);
1576         if (extraInfo) {
1577         outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
1578                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1579         outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
1580         outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
1581         outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
1582         parmSlot++;
1583         outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
1584         parmSlot++;
1585         outp->parmsp[parmSlot] = openMode; parmSlot++;
1586         outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
1587         outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
1588         }   
1589         /* and the final "always present" stuff */
1590     outp->parmsp[parmSlot] = openAction; parmSlot++;
1591         /* next write out the "unique" ID */
1592         outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
1593         outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
1594     outp->parmsp[parmSlot] = 0; parmSlot++;
1595     if (returnEALength) {
1596                 outp->parmsp[parmSlot] = 0; parmSlot++;
1597                 outp->parmsp[parmSlot] = 0; parmSlot++;
1598     }
1599         lock_ReleaseMutex(&scp->mx);
1600         outp->totalData = 0;            /* total # of data bytes */
1601     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
1602
1603         smb_SendTran2Packet(vcp, outp, op);
1604         
1605     smb_FreeTran2Packet(outp);
1606
1607     cm_ReleaseUser(userp);
1608     /* leave scp held since we put it in fidp->scp */
1609     return 0;
1610 }   
1611
1612 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1613 {
1614     return CM_ERROR_BADOP;
1615 }
1616
1617 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1618 {
1619     return CM_ERROR_BADOP;
1620 }
1621
1622 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1623 {
1624         smb_tran2Packet_t *outp;
1625     smb_tran2QFSInfo_t qi;
1626         int responseSize;
1627         osi_hyper_t temp;
1628         static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
1629         
1630         osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
1631
1632         switch (p->parmsp[0]) {
1633         case 1: responseSize = sizeof(qi.u.allocInfo); break;
1634         case 2: responseSize = sizeof(qi.u.volumeInfo); break;
1635         case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
1636         case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
1637         case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
1638         case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
1639         default: return CM_ERROR_INVAL;
1640         }
1641
1642     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
1643         switch (p->parmsp[0]) {
1644         case 1:
1645                 /* alloc info */
1646         qi.u.allocInfo.FSID = 0;
1647         qi.u.allocInfo.sectorsPerAllocUnit = 1;
1648         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
1649         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
1650         qi.u.allocInfo.bytesPerSector = 1024;
1651                 break;
1652
1653     case 2:
1654                 /* volume info */
1655         qi.u.volumeInfo.vsn = 1234;
1656         qi.u.volumeInfo.vnCount = 4;
1657                 /* we're supposed to pad it out with zeroes to the end */
1658                 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
1659         memcpy(qi.u.volumeInfo.label, "AFS", 4);
1660                 break;
1661
1662         case 0x102:
1663                 /* FS volume info */
1664                 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
1665                 qi.u.FSvolumeInfo.vsn = 1234;
1666                 qi.u.FSvolumeInfo.vnCount = 8;
1667                 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
1668                 break;
1669
1670         case 0x103:
1671                 /* FS size info */
1672                 temp.HighPart = 0;
1673                 temp.LowPart = 0x7fffffff;
1674                 qi.u.FSsizeInfo.totalAllocUnits = temp;
1675                 temp.LowPart = 0x3fffffff;
1676                 qi.u.FSsizeInfo.availAllocUnits = temp;
1677                 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
1678                 qi.u.FSsizeInfo.bytesPerSector = 1024;
1679                 break;
1680
1681         case 0x104:
1682                 /* FS device info */
1683                 qi.u.FSdeviceInfo.devType = 0;  /* don't have a number */
1684                 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
1685                 break;
1686
1687         case 0x105:
1688                 /* FS attribute info */
1689                 /* attributes, defined in WINNT.H:
1690                  *      FILE_CASE_SENSITIVE_SEARCH      0x1
1691                  *      FILE_CASE_PRESERVED_NAMES       0x2
1692                  *      <no name defined>               0x4000
1693                  *         If bit 0x4000 is not set, Windows 95 thinks
1694                  *         we can't handle long (non-8.3) names,
1695                  *         despite our protestations to the contrary.
1696                  */
1697                 qi.u.FSattributeInfo.attributes = 0x4003;
1698                 qi.u.FSattributeInfo.maxCompLength = 255;
1699                 qi.u.FSattributeInfo.FSnameLength = 6;
1700                 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
1701                 break;
1702     }
1703         
1704         /* copy out return data, and set corresponding sizes */
1705         outp->totalParms = 0;
1706     outp->totalData = responseSize;
1707     memcpy(outp->datap, &qi, responseSize);
1708
1709         /* send and free the packets */
1710         smb_SendTran2Packet(vcp, outp, op);
1711     smb_FreeTran2Packet(outp);
1712
1713     return 0;
1714 }
1715
1716 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1717 {
1718     return CM_ERROR_BADOP;
1719 }
1720
1721 struct smb_ShortNameRock {
1722         char *maskp;
1723         unsigned int vnode;
1724         char *shortName;
1725         size_t shortNameLen;
1726 };
1727
1728 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
1729         osi_hyper_t *offp)
1730 {
1731         struct smb_ShortNameRock *rockp;
1732         char *shortNameEnd;
1733
1734         rockp = vrockp;
1735         /* compare both names and vnodes, though probably just comparing vnodes
1736          * would be safe enough.
1737          */
1738         if (cm_stricmp(dep->name, rockp->maskp) != 0)
1739                 return 0;
1740         if (ntohl(dep->fid.vnode) != rockp->vnode)
1741                 return 0;
1742         /* This is the entry */
1743         cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
1744         rockp->shortNameLen = shortNameEnd - rockp->shortName;
1745         return CM_ERROR_STOPNOW;
1746 }
1747
1748 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
1749         char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
1750 {
1751         struct smb_ShortNameRock rock;
1752         char *lastNamep;
1753         cm_space_t *spacep;
1754         cm_scache_t *dscp;
1755         int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
1756         long code = 0;
1757         osi_hyper_t thyper;
1758
1759         spacep = cm_GetSpace();
1760         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1761
1762         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
1763                      reqp, &dscp);
1764         cm_FreeSpace(spacep);
1765         if (code) return code;
1766
1767         if (!lastNamep) lastNamep = pathp;
1768         else lastNamep++;
1769         thyper.LowPart = 0;
1770         thyper.HighPart = 0;
1771         rock.shortName = shortName;
1772         rock.vnode = vnode;
1773         rock.maskp = lastNamep;
1774         code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
1775                         reqp, NULL);
1776
1777         cm_ReleaseSCache(dscp);
1778
1779         if (code == 0)
1780                 return CM_ERROR_NOSUCHFILE;
1781         if (code == CM_ERROR_STOPNOW) {
1782                 *shortNameLenp = rock.shortNameLen;
1783                 return 0;
1784         }
1785         return code;
1786 }
1787
1788 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
1789 {
1790         smb_tran2Packet_t *outp;
1791     unsigned long dosTime;
1792         FILETIME ft;
1793     unsigned short infoLevel;
1794     int nbytesRequired;
1795     unsigned short attributes;
1796         unsigned long extAttributes;
1797         char shortName[13];
1798         unsigned int len;
1799     cm_user_t *userp;
1800         cm_space_t *spacep;
1801     cm_scache_t *scp, *dscp;
1802     long code = 0;
1803     char *op;
1804         char *tidPathp;
1805         char *lastComp;
1806         cm_req_t req;
1807
1808         cm_InitReq(&req);
1809
1810         infoLevel = p->parmsp[0];
1811     if (infoLevel == 6) nbytesRequired = 0;
1812     else if (infoLevel == 1) nbytesRequired = 22;
1813     else if (infoLevel == 2) nbytesRequired = 26;
1814         else if (infoLevel == 0x101) nbytesRequired = 40;
1815         else if (infoLevel == 0x102) nbytesRequired = 24;
1816         else if (infoLevel == 0x103) nbytesRequired = 4;
1817         else if (infoLevel == 0x108) nbytesRequired = 30;
1818     else {
1819                 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
1820                   p->opcode, infoLevel);
1821                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
1822         return 0;
1823     }
1824         osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
1825              osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
1826
1827     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
1828
1829         if (infoLevel > 0x100)
1830                 outp->totalParms = 2;
1831         else
1832                 outp->totalParms = 0;
1833         outp->totalData = nbytesRequired;
1834         
1835     /* now, if we're at infoLevel 6, we're only being asked to check
1836      * the syntax, so we just OK things now.  In particular, we're *not*
1837      * being asked to verify anything about the state of any parent dirs.
1838      */
1839         if (infoLevel == 6) {
1840                 smb_SendTran2Packet(vcp, outp, opx);
1841         smb_FreeTran2Packet(outp);
1842                 return 0;
1843     }
1844         
1845     userp = smb_GetTran2User(vcp, p);
1846     if (!userp) {
1847         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
1848         smb_FreeTran2Packet(outp);
1849         return CM_ERROR_BADSMB;
1850     }
1851
1852         tidPathp = smb_GetTIDPath(vcp, p->tid);
1853
1854         /*
1855          * XXX Strange hack XXX
1856          *
1857          * As of Patch 7 (13 January 98), we are having the following problem:
1858          * In NT Explorer 4.0, whenever we click on a directory, AFS gets
1859          * requests to look up "desktop.ini" in all the subdirectories.
1860          * This can cause zillions of timeouts looking up non-existent cells
1861          * and volumes, especially in the top-level directory.
1862          *
1863          * We have not found any way to avoid this or work around it except
1864          * to explicitly ignore the requests for mount points that haven't
1865          * yet been evaluated and for directories that haven't yet been
1866          * fetched.
1867          */
1868         if (infoLevel == 0x101) {
1869                 spacep = cm_GetSpace();
1870                 smb_StripLastComponent(spacep->data, &lastComp,
1871                                         (char *)(&p->parmsp[3]));
1872                 /* Make sure that lastComp is not NULL */
1873                 if (lastComp) {
1874                     if (strcmp(lastComp, "\\desktop.ini") == 0) {
1875                 code = cm_NameI(cm_rootSCachep, spacep->data,
1876                                 CM_FLAG_CASEFOLD
1877                                 | CM_FLAG_DIRSEARCH
1878                                 | CM_FLAG_FOLLOW,
1879                                 userp, tidPathp, &req, &dscp);
1880                 if (code == 0) {
1881                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
1882                          && !dscp->mountRootFidp)
1883                         code = CM_ERROR_NOSUCHFILE;
1884                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
1885                         cm_buf_t *bp = buf_Find(dscp, &hzero);
1886                         if (bp)
1887                             buf_Release(bp);
1888                         else
1889                             code = CM_ERROR_NOSUCHFILE;
1890                     }
1891                     cm_ReleaseSCache(dscp);
1892                     if (code) {
1893                         cm_FreeSpace(spacep);
1894                         cm_ReleaseUser(userp);
1895                         smb_SendTran2Error(vcp, p, opx, code);
1896                         smb_FreeTran2Packet(outp);
1897                         return 0;
1898                     }
1899                 }
1900             }
1901         }
1902                 cm_FreeSpace(spacep);
1903         }
1904
1905         /* now do namei and stat, and copy out the info */
1906     code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
1907                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
1908
1909         if (code) {
1910                 cm_ReleaseUser(userp);
1911         smb_SendTran2Error(vcp, p, opx, code);
1912         smb_FreeTran2Packet(outp);
1913         return 0;
1914     }
1915
1916     lock_ObtainMutex(&scp->mx);
1917         code = cm_SyncOp(scp, NULL, userp, &req, 0,
1918                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1919         if (code) goto done;
1920         
1921     /* now we have the status in the cache entry, and everything is locked.
1922          * Marshall the output data.
1923      */
1924         op = outp->datap;
1925         /* for info level 108, figure out short name */
1926         if (infoLevel == 0x108) {
1927                 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
1928                                 tidPathp, scp->fid.vnode, shortName,
1929                                 (size_t *) &len);
1930                 if (code) {
1931                         goto done;
1932                 }
1933
1934                 op = outp->datap;
1935                 *((u_long *)op) = len * 2; op += 4;
1936                 mbstowcs((unsigned short *)op, shortName, len);
1937                 op += (len * 2);
1938
1939                 goto done;
1940         }
1941         if (infoLevel == 1 || infoLevel == 2) {
1942                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
1943         *((u_long *)op) = dosTime; op += 4;     /* creation time */
1944         *((u_long *)op) = dosTime; op += 4;     /* access time */
1945         *((u_long *)op) = dosTime; op += 4;     /* write time */
1946         *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
1947         *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
1948                 attributes = smb_Attributes(scp);
1949                 *((u_short *)op) = attributes; op += 2; /* attributes */
1950         }
1951         else if (infoLevel == 0x101) {
1952                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
1953                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
1954                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
1955                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
1956                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
1957                 extAttributes = smb_ExtAttributes(scp);
1958                 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
1959                 *((u_long *)op) = 0; op += 4;   /* don't know what this is */
1960         }
1961         else if (infoLevel == 0x102) {
1962                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
1963                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
1964                 *((u_long *)op) = scp->linkCount; op += 4;
1965                 *op++ = 0;
1966                 *op++ = 0;
1967                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
1968                 *op++ = 0;
1969         }
1970         else if (infoLevel == 0x103) {
1971                 memset(op, 0, 4); op += 4;      /* EA size */
1972         }
1973
1974         /* now, if we are being asked about extended attrs, return a 0 size */
1975         if (infoLevel == 2) {
1976                 *((u_long *)op) = 0; op += 4;
1977         }
1978         
1979
1980         /* send and free the packets */
1981   done:
1982         lock_ReleaseMutex(&scp->mx);
1983     cm_ReleaseSCache(scp);
1984     cm_ReleaseUser(userp);
1985         if (code == 0) 
1986         smb_SendTran2Packet(vcp, outp, opx);
1987     else 
1988         smb_SendTran2Error(vcp, p, opx, code);
1989     smb_FreeTran2Packet(outp);
1990
1991     return 0;
1992 }
1993
1994 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
1995 {
1996     return CM_ERROR_BADOP;
1997 }
1998
1999 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2000 {
2001         smb_tran2Packet_t *outp;
2002         FILETIME ft;
2003         unsigned long attributes;
2004         unsigned short infoLevel;
2005         int nbytesRequired;
2006         unsigned short fid;
2007         cm_user_t *userp;
2008     smb_fid_t *fidp;
2009         cm_scache_t *scp;
2010         char *op;
2011         long code = 0;
2012         cm_req_t req;
2013
2014         cm_InitReq(&req);
2015
2016     fid = p->parmsp[0];
2017     fidp = smb_FindFID(vcp, fid, 0);
2018
2019         if (fidp == NULL) {
2020                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2021                 return 0;
2022         }
2023
2024         infoLevel = p->parmsp[1];
2025         if (infoLevel == 0x101) nbytesRequired = 40;
2026         else if (infoLevel == 0x102) nbytesRequired = 24;
2027         else if (infoLevel == 0x103) nbytesRequired = 4;
2028         else if (infoLevel == 0x104) nbytesRequired = 6;
2029         else {
2030                 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2031                  p->opcode, infoLevel);
2032                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2033         smb_ReleaseFID(fidp);
2034                 return 0;
2035         }
2036         osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2037
2038         outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2039
2040         if (infoLevel > 0x100)
2041                 outp->totalParms = 2;
2042         else
2043                 outp->totalParms = 0;
2044         outp->totalData = nbytesRequired;
2045
2046         userp = smb_GetTran2User(vcp, p);
2047     if (!userp) {
2048         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2049         code = CM_ERROR_BADSMB;
2050         goto done;
2051     }
2052
2053         scp = fidp->scp;
2054         lock_ObtainMutex(&scp->mx);
2055         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2056                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2057         if (code) goto done;
2058
2059         /* now we have the status in the cache entry, and everything is locked.
2060          * Marshall the output data.
2061          */
2062         op = outp->datap;
2063         if (infoLevel == 0x101) {
2064                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2065                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
2066                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
2067                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
2068                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
2069                 attributes = smb_ExtAttributes(scp);
2070                 *((u_long *)op) = attributes; op += 4;
2071                 *((u_long *)op) = 0; op += 4;
2072         }
2073         else if (infoLevel == 0x102) {
2074                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
2075                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
2076                 *((u_long *)op) = scp->linkCount; op += 4;
2077                 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2078                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2079                 *op++ = 0;
2080                 *op++ = 0;
2081         }
2082         else if (infoLevel == 0x103) {
2083                 *((u_long *)op) = 0; op += 4;
2084         }
2085         else if (infoLevel == 0x104) {
2086                 unsigned long len;
2087                 char *name;
2088
2089                 if (fidp->NTopen_wholepathp)
2090                         name = fidp->NTopen_wholepathp;
2091                 else
2092                         name = "\\";    /* probably can't happen */
2093                 len = strlen(name);
2094                 outp->totalData = (len*2) + 4;  /* this is actually what we want to return */
2095                 *((u_long *)op) = len * 2; op += 4;
2096                 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2097         }
2098
2099         /* send and free the packets */
2100   done:
2101         lock_ReleaseMutex(&scp->mx);
2102         cm_ReleaseUser(userp);
2103         smb_ReleaseFID(fidp);
2104         if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
2105         else smb_SendTran2Error(vcp, p, opx, code);
2106         smb_FreeTran2Packet(outp);
2107
2108         return 0;
2109 }
2110
2111 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2112 {
2113         long code = 0;
2114         unsigned short fid;
2115         smb_fid_t *fidp;
2116         unsigned short infoLevel;
2117         smb_tran2Packet_t *outp;
2118         cm_user_t *userp;
2119         cm_scache_t *scp;
2120         cm_req_t req;
2121
2122         cm_InitReq(&req);
2123
2124     fid = p->parmsp[0];
2125         fidp = smb_FindFID(vcp, fid, 0);
2126
2127         if (fidp == NULL) {
2128                 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2129                 return 0;
2130         }
2131
2132         infoLevel = p->parmsp[1];
2133         if (infoLevel > 0x104 || infoLevel < 0x101) {
2134                 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2135                          p->opcode, infoLevel);
2136                 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2137         smb_ReleaseFID(fidp);
2138                 return 0;
2139         }
2140
2141         if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2142                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2143         smb_ReleaseFID(fidp);
2144                 return 0;
2145         }
2146         if ((infoLevel == 0x103 || infoLevel == 0x104)
2147             && !(fidp->flags & SMB_FID_OPENWRITE)) {
2148                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2149         smb_ReleaseFID(fidp);
2150                 return 0;
2151         }
2152
2153         osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2154
2155         outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2156
2157         outp->totalParms = 2;
2158         outp->totalData = 0;
2159
2160         userp = smb_GetTran2User(vcp, p);
2161     if (!userp) {
2162         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2163         code = CM_ERROR_BADSMB;
2164         goto done;
2165     }
2166
2167         scp = fidp->scp;
2168
2169         if (infoLevel == 0x101) {
2170                 FILETIME lastMod;
2171                 unsigned int attribute;
2172                 cm_attr_t attr;
2173
2174                 /* lock the vnode with a callback; we need the current status
2175                  * to determine what the new status is, in some cases.
2176                  */
2177                 lock_ObtainMutex(&scp->mx);
2178                 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2179                          CM_SCACHESYNC_GETSTATUS
2180                          | CM_SCACHESYNC_NEEDCALLBACK);
2181                 if (code) {
2182                         lock_ReleaseMutex(&scp->mx);
2183                         goto done;
2184                 }
2185
2186                 /* prepare for setattr call */
2187                 attr.mask = 0;
2188                 
2189                 lastMod = *((FILETIME *)(p->datap + 16));
2190                 /* when called as result of move a b, lastMod is (-1, -1). 
2191          * If the check for -1 is not present, timestamp
2192                  * of the resulting file will be 1969 (-1)
2193                  */
2194                 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
2195             lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2196                         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2197                         smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2198                                                         &lastMod);
2199                         fidp->flags |= SMB_FID_MTIMESETDONE;
2200                 }
2201                 
2202                 attribute = *((u_long *)(p->datap + 32));
2203                 if (attribute != 0) {
2204                         if ((scp->unixModeBits & 0222)
2205                             && (attribute & 1) != 0) {
2206                                 /* make a writable file read-only */
2207                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2208                                 attr.unixModeBits = scp->unixModeBits & ~0222;
2209                         }
2210                         else if ((scp->unixModeBits & 0222) == 0
2211                                  && (attribute & 1) == 0) {
2212                                 /* make a read-only file writable */
2213                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2214                                 attr.unixModeBits = scp->unixModeBits | 0222;
2215                         }
2216                 }
2217                 lock_ReleaseMutex(&scp->mx);
2218
2219                 /* call setattr */
2220                 if (attr.mask)
2221                         code = cm_SetAttr(scp, &attr, userp, &req);
2222                 else
2223                         code = 0;
2224         }
2225         else if (infoLevel == 0x103 || infoLevel == 0x104) {
2226                 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2227                 cm_attr_t attr;
2228
2229                 attr.mask = CM_ATTRMASK_LENGTH;
2230                 attr.length.LowPart = size.LowPart;
2231                 attr.length.HighPart = size.HighPart;
2232                 code = cm_SetAttr(scp, &attr, userp, &req);
2233         }
2234         else if (infoLevel == 0x102) {
2235                 if (*((char *)(p->datap))) {
2236                         code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2237                                                 &req);
2238                         if (code == 0)
2239                                 fidp->flags |= SMB_FID_DELONCLOSE;
2240                 }
2241                 else {
2242                         code = 0;
2243                         fidp->flags &= ~SMB_FID_DELONCLOSE;
2244                 }
2245         }
2246   done:
2247         cm_ReleaseUser(userp);
2248         smb_ReleaseFID(fidp);
2249         if (code == 0) smb_SendTran2Packet(vcp, outp, op);
2250         else smb_SendTran2Error(vcp, p, op, code);
2251         smb_FreeTran2Packet(outp);
2252
2253         return 0;
2254 }
2255
2256 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2257 {
2258     return CM_ERROR_BADOP;
2259 }
2260
2261 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2262 {
2263     return CM_ERROR_BADOP;
2264 }
2265
2266 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2267 {
2268     return CM_ERROR_BADOP;
2269 }
2270
2271 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2272 {
2273     return CM_ERROR_BADOP;
2274 }
2275
2276 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2277 {
2278     return CM_ERROR_BADOP;
2279 }
2280
2281 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
2282         smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
2283         cm_req_t *reqp)
2284 {
2285         long code = 0;
2286     cm_scache_t *scp;
2287     cm_scache_t *targetScp;                     /* target if scp is a symlink */
2288     char *dptr;
2289     long dosTime;
2290         FILETIME ft;
2291     int shortTemp;
2292     unsigned short attr;
2293         unsigned long lattr;
2294     smb_dirListPatch_t *patchp;
2295     smb_dirListPatch_t *npatchp;
2296         
2297     for(patchp = *dirPatchespp; patchp; patchp =
2298          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2299                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2300         if (code) continue;
2301         lock_ObtainMutex(&scp->mx);
2302         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2303                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2304                 if (code) { 
2305                         lock_ReleaseMutex(&scp->mx);
2306                         cm_ReleaseSCache(scp);
2307                         continue;
2308         }
2309                 
2310         /* now watch for a symlink */
2311         if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
2312                         lock_ReleaseMutex(&scp->mx);
2313             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
2314             if (code == 0) {
2315                                 /* we have a more accurate file to use (the
2316                                  * target of the symbolic link).  Otherwise,
2317                                  * we'll just use the symlink anyway.
2318                  */
2319                                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2320                          scp, targetScp);
2321                                 cm_ReleaseSCache(scp);
2322                 scp = targetScp;
2323             }
2324             lock_ObtainMutex(&scp->mx);
2325         }
2326
2327                 dptr = patchp->dptr;
2328
2329                 if (infoLevel >= 0x101) {
2330                         /* get filetime */
2331                         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2332
2333                         /* copy to Creation Time */
2334                         *((FILETIME *)dptr) = ft;
2335                         dptr += 8;
2336
2337                         /* copy to Last Access Time */
2338                         *((FILETIME *)dptr) = ft;
2339                         dptr += 8;
2340
2341                         /* copy to Last Write Time */
2342                         *((FILETIME *)dptr) = ft;
2343                         dptr += 8;
2344
2345                         /* copy to Change Time */
2346                         *((FILETIME *)dptr) = ft;
2347                         dptr += 8;
2348
2349                         /* Use length for both file length and alloc length */
2350                         *((LARGE_INTEGER *)dptr) = scp->length;
2351                         dptr += 8;
2352                         *((LARGE_INTEGER *)dptr) = scp->length;
2353                         dptr += 8;
2354
2355                         /* Copy attributes */
2356                         lattr = smb_ExtAttributes(scp);
2357             /* merge in hidden (dot file) attribute */
2358                         if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2359                                 lattr |= SMB_ATTR_HIDDEN;
2360                         *((u_long *)dptr) = lattr;
2361                         dptr += 4;
2362                 }
2363                 else {
2364                         /* get dos time */
2365                         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2366
2367                         /* and copy out date */
2368                         shortTemp = (dosTime>>16) & 0xffff;
2369                         *((u_short *)dptr) = shortTemp;
2370                         dptr += 2;
2371
2372                         /* copy out creation time */
2373                         shortTemp = dosTime & 0xffff;
2374                         *((u_short *)dptr) = shortTemp;
2375                         dptr += 2;
2376
2377                         /* and copy out date */
2378                         shortTemp = (dosTime>>16) & 0xffff;
2379                         *((u_short *)dptr) = shortTemp;
2380                         dptr += 2;
2381                         
2382                         /* copy out access time */
2383                         shortTemp = dosTime & 0xffff;
2384                         *((u_short *)dptr) = shortTemp;
2385                         dptr += 2;
2386
2387                         /* and copy out date */
2388                         shortTemp = (dosTime>>16) & 0xffff;
2389                         *((u_short *)dptr) = shortTemp;
2390                         dptr += 2;
2391                         
2392                         /* copy out mod time */
2393                         shortTemp = dosTime & 0xffff;
2394                         *((u_short *)dptr) = shortTemp;
2395                         dptr += 2;
2396
2397                         /* copy out file length and alloc length,
2398                          * using the same for both
2399                          */
2400                         *((u_long *)dptr) = scp->length.LowPart;
2401                         dptr += 4;
2402                         *((u_long *)dptr) = scp->length.LowPart;
2403                         dptr += 4;
2404
2405                         /* finally copy out attributes as short */
2406                         attr = smb_Attributes(scp);
2407             /* merge in hidden (dot file) attribute */
2408             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2409                 attr |= SMB_ATTR_HIDDEN;
2410                         *dptr++ = attr & 0xff;
2411                         *dptr++ = (attr >> 8) & 0xff;
2412                 }
2413
2414         lock_ReleaseMutex(&scp->mx);
2415         cm_ReleaseSCache(scp);
2416         }
2417         
2418     /* now free the patches */
2419     for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
2420                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
2421         free(patchp);
2422         }
2423         
2424     /* and mark the list as empty */
2425     *dirPatchespp = NULL;
2426
2427     return code;
2428 }
2429
2430 #ifndef USE_OLD_MATCHING
2431 // char table for case insensitive comparison
2432 char mapCaseTable[256];
2433
2434 VOID initUpperCaseTable(VOID) 
2435 {
2436     int i;
2437     for (i = 0; i < 256; ++i) 
2438        mapCaseTable[i] = toupper(i);
2439     // make '"' match '.' 
2440     mapCaseTable[(int)'"'] = toupper('.');
2441     // make '<' match '*' 
2442     mapCaseTable[(int)'<'] = toupper('*');
2443     // make '>' match '?' 
2444     mapCaseTable[(int)'>'] = toupper('?');    
2445 }
2446
2447 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
2448 // name 'name'.
2449 // Note : this procedure works recursively calling itself.
2450 // Parameters
2451 // PSZ pattern    : string containing metacharacters.
2452 // PSZ name       : file name to be compared with 'pattern'.
2453 // Return value
2454 // BOOL : TRUE/FALSE (match/mistmatch)
2455
2456 BOOL szWildCardMatchFileName(PSZ pattern, PSZ name) {
2457    PSZ pename;         // points to the last 'name' character
2458    PSZ p;
2459    pename = name + strlen(name) - 1;
2460    while (*name) {
2461       switch (*pattern) {
2462          case '?':
2463          case '>':
2464             if (*(++pattern) != '<' || *(++pattern) != '*') {
2465                if (*name == '.') 
2466                    return FALSE;
2467                ++name;
2468                break;
2469             } /* endif */
2470          case '<':
2471          case '*':
2472             while ((*pattern == '<') || (*pattern == '*') || (*pattern == '?') || (*pattern == '>')) 
2473                 ++pattern;
2474             if (!*pattern) 
2475                 return TRUE;
2476             for (p = pename; p >= name; --p) {
2477                if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
2478                    szWildCardMatchFileName(pattern + 1, p + 1))
2479                   return TRUE;
2480             } /* endfor */
2481             return FALSE;
2482          default:
2483             if (mapCaseTable[*name] != mapCaseTable[*pattern]) 
2484                 return FALSE;
2485             ++pattern, ++name;
2486             break;
2487       } /* endswitch */
2488    } /* endwhile */ 
2489    return !*pattern;
2490 }
2491
2492 /* do a case-folding search of the star name mask with the name in namep.
2493  * Return 1 if we match, otherwise 0.
2494  */
2495 int smb_V3MatchMask(char *namep, char *maskp, int flags) 
2496 {
2497         /* make sure we only match 8.3 names, if requested */
2498         if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
2499         return 0;
2500         
2501         return szWildCardMatchFileName(maskp, namep) ? 1:0;
2502 }
2503
2504 #else /* USE_OLD_MATCHING */
2505 /* do a case-folding search of the star name mask with the name in namep.
2506  * Return 1 if we match, otherwise 0.
2507  */
2508 int smb_V3MatchMask(char *namep, char *maskp, int flags)
2509 {
2510         unsigned char tcp1, tcp2;       /* Pattern characters */
2511     unsigned char tcn1;         /* Name characters */
2512         int sawDot = 0, sawStar = 0, req8dot3 = 0;
2513         char *starNamep, *starMaskp;
2514         static char nullCharp[] = {0};
2515     int casefold = flags & CM_FLAG_CASEFOLD;
2516
2517         /* make sure we only match 8.3 names, if requested */
2518     req8dot3 = (flags & CM_FLAG_8DOT3);
2519         if (req8dot3 && !cm_Is8Dot3(namep)) 
2520         return 0;
2521
2522         /* loop */
2523         while (1) {
2524                 /* Next pattern character */
2525                 tcp1 = *maskp++;
2526
2527                 /* Next name character */
2528                 tcn1 = *namep;
2529
2530                 if (tcp1 == 0) {
2531                         /* 0 - end of pattern */
2532                         if (tcn1 == 0)
2533                                 return 1;
2534                         else
2535                                 return 0;
2536                 }
2537                 else if (tcp1 == '.' || tcp1 == '"') {
2538                         if (sawDot) {
2539                                 if (tcn1 == '.') {
2540                                         namep++;
2541                                         continue;
2542                                 } else
2543                                         return 0;
2544                         }
2545                         else {
2546                                 /*
2547                                  * first dot in pattern;
2548                                  * must match dot or end of name
2549                                  */
2550                                 sawDot = 1;
2551                                 if (tcn1 == 0)
2552                                         continue;
2553                                 else if (tcn1 == '.') {
2554                                         sawStar = 0;
2555                                         namep++;
2556                                         continue;
2557                                 }
2558                                 else
2559                                         return 0;
2560                         }
2561                 }
2562                 else if (tcp1 == '?') {
2563                         if (tcn1 == 0 || tcn1 == '.')
2564                                 return 0;
2565                         namep++;
2566                         continue;
2567                 }
2568                 else if (tcp1 == '>') {
2569                         if (tcn1 != 0 && tcn1 != '.')
2570                                 namep++;
2571                         continue;
2572                 }
2573                 else if (tcp1 == '*' || tcp1 == '<') {
2574                         tcp2 = *maskp++;
2575                         if (tcp2 == 0)
2576                                 return 1;
2577                         else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
2578                                 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
2579                                         tcn1 = *++namep;
2580                                 if (tcn1 == 0) {
2581                                         if (sawDot)
2582                                                 return 0;
2583                                         else
2584                                                 continue;
2585                                 }
2586                                 else {
2587                                         namep++;
2588                                         continue;
2589                                 }
2590                         }
2591                         else {
2592                                 /*
2593                                  * pattern character after '*' is not null or
2594                                  * period.  If it is '?' or '>', we are not
2595                                  * going to understand it.  If it is '*' or
2596                                  * '<', we are going to skip over it.  None of
2597                                  * these are likely, I hope.
2598                                  */
2599                                 /* skip over '*' and '<' */
2600                                 while (tcp2 == '*' || tcp2 == '<')
2601                                         tcp2 = *maskp++;
2602
2603                                 /* skip over characters that don't match tcp2 */
2604                                 while (req8dot3 && tcn1 != '.' && tcn1 != 0 && 
2605                        ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
2606                          (!casefold && tcn1 != tcp2)))
2607                                         tcn1 = *++namep;
2608
2609                                 /* No match */
2610                                 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
2611                                         return 0;
2612
2613                                 /* Remember where we are */
2614                                 sawStar = 1;
2615                                 starMaskp = maskp;
2616                                 starNamep = namep;
2617
2618                                 namep++;
2619                                 continue;
2620                         }
2621                 }
2622                 else {
2623                         /* tcp1 is not a wildcard */
2624             if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
2625                 (!casefold && tcn1 == tcp1)) {
2626                                 /* they match */
2627                                 namep++;
2628                                 continue;
2629                         }
2630                         /* if trying to match a star pattern, go back */
2631                         if (sawStar) {
2632                                 maskp = starMaskp - 2;
2633                                 namep = starNamep + 1;
2634                                 sawStar = 0;
2635                                 continue;
2636                         }
2637                         /* that's all */
2638                         return 0;
2639                 }
2640         }
2641 }
2642 #endif /* USE_OLD_MATCHING */
2643
2644 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2645 {
2646         int attribute;
2647     long nextCookie;
2648     char *tp;
2649     long code = 0;
2650     char *pathp;
2651     cm_dirEntry_t *dep;
2652     int maxCount;
2653     smb_dirListPatch_t *dirListPatchesp;
2654     smb_dirListPatch_t *curPatchp;
2655     cm_buf_t *bufferp;
2656     long temp;
2657     long orbytes;                       /* # of bytes in this output record */
2658     long ohbytes;                       /* # of bytes, except file name */
2659     long onbytes;                       /* # of bytes in name, incl. term. null */
2660     osi_hyper_t dirLength;
2661     osi_hyper_t bufferOffset;
2662     osi_hyper_t curOffset;
2663     osi_hyper_t thyper;
2664     smb_dirSearch_t *dsp;
2665     cm_scache_t *scp;
2666     long entryInDir;
2667     long entryInBuffer;
2668         cm_pageHeader_t *pageHeaderp;
2669     cm_user_t *userp = NULL;
2670     int slotInPage;
2671     int returnedNames;
2672     long nextEntryCookie;
2673     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
2674     char *op;                   /* output data ptr */
2675         char *origOp;                   /* original value of op */
2676     cm_space_t *spacep;         /* for pathname buffer */
2677     long maxReturnData;         /* max # of return data */
2678     long maxReturnParms;                /* max # of return parms */
2679     long bytesInBuffer;         /* # data bytes in the output buffer */
2680     int starPattern;
2681     char *maskp;                        /* mask part of path */
2682     int infoLevel;
2683     int searchFlags;
2684     int eos;
2685     smb_tran2Packet_t *outp;    /* response packet */
2686         char *tidPathp;
2687         int align;
2688         char shortName[13];             /* 8.3 name if needed */
2689         int NeedShortName;
2690     int foundInexact;
2691         char *shortNameEnd;
2692     int fileType;
2693     cm_fid_t fid;
2694
2695     cm_req_t req;
2696
2697         cm_InitReq(&req);
2698
2699         eos = 0;
2700         if (p->opcode == 1) {
2701                 /* find first; obtain basic parameters from request */
2702         attribute = p->parmsp[0];
2703         maxCount = p->parmsp[1];
2704         infoLevel = p->parmsp[3];
2705         searchFlags = p->parmsp[2];
2706         dsp = smb_NewDirSearch(1);
2707         dsp->attribute = attribute;
2708         pathp = ((char *) p->parmsp) + 12;      /* points to path */
2709         nextCookie = 0;
2710         maskp = strrchr(pathp, '\\');
2711         if (maskp == NULL) maskp = pathp;
2712                 else maskp++;   /* skip over backslash */
2713         strcpy(dsp->mask, maskp);       /* and save mask */
2714                 /* track if this is likely to match a lot of entries */
2715         starPattern = smb_V3IsStarMask(maskp);
2716         }
2717     else {
2718                 osi_assert(p->opcode == 2);
2719         /* find next; obtain basic parameters from request or open dir file */
2720         dsp = smb_FindDirSearch(p->parmsp[0]);
2721         if (!dsp) return CM_ERROR_BADFD;
2722         attribute = dsp->attribute;
2723         maxCount = p->parmsp[1];
2724         infoLevel = p->parmsp[2];
2725         searchFlags = p->parmsp[5];
2726         pathp = NULL;
2727         nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
2728         maskp = dsp->mask;
2729                 starPattern = 1;        /* assume, since required a Find Next */
2730     }
2731
2732         osi_Log4(smb_logp,
2733               "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
2734               attribute, infoLevel, maxCount, searchFlags);
2735
2736         osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
2737               p->opcode, nextCookie);
2738
2739         if (infoLevel >= 0x101)
2740                 searchFlags &= ~4;      /* no resume keys */
2741
2742     dirListPatchesp = NULL;
2743
2744         maxReturnData = p->maxReturnData;
2745     if (p->opcode == 1) /* find first */
2746         maxReturnParms = 10;    /* bytes */
2747         else    
2748         maxReturnParms = 8;     /* bytes */
2749
2750 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
2751     if (maxReturnData > 6000) 
2752         maxReturnData = 6000;
2753 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
2754
2755         outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
2756                                       maxReturnData);
2757
2758     osi_Log1(smb_logp, "T2 receive search dir %s",
2759              osi_LogSaveString(smb_logp, pathp));
2760         
2761     /* bail out if request looks bad */
2762     if (p->opcode == 1 && !pathp) {
2763         smb_ReleaseDirSearch(dsp);
2764         smb_FreeTran2Packet(outp);
2765         return CM_ERROR_BADSMB;
2766     }
2767         
2768         osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
2769              nextCookie, dsp->cookie);
2770
2771         userp = smb_GetTran2User(vcp, p);
2772     if (!userp) {
2773         osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
2774         smb_ReleaseDirSearch(dsp);
2775         smb_FreeTran2Packet(outp);
2776         return CM_ERROR_BADSMB;
2777     }
2778
2779         /* try to get the vnode for the path name next */
2780         lock_ObtainMutex(&dsp->mx);
2781         if (dsp->scp) {
2782                 scp = dsp->scp;
2783         cm_HoldSCache(scp);
2784         code = 0;
2785     }
2786     else {
2787                 spacep = cm_GetSpace();
2788         smb_StripLastComponent(spacep->data, NULL, pathp);
2789         lock_ReleaseMutex(&dsp->mx);
2790
2791                 tidPathp = smb_GetTIDPath(vcp, p->tid);
2792         code = cm_NameI(cm_rootSCachep, spacep->data,
2793                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2794                         userp, tidPathp, &req, &scp);
2795         cm_FreeSpace(spacep);
2796
2797         lock_ObtainMutex(&dsp->mx);
2798                 if (code == 0) {
2799             if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2800                         dsp->scp = scp;
2801                         /* we need one hold for the entry we just stored into,
2802              * and one for our own processing.  When we're done
2803                          * with this function, we'll drop the one for our own
2804                          * processing.  We held it once from the namei call,
2805                          * and so we do another hold now.
2806              */
2807             cm_HoldSCache(scp);
2808                         lock_ObtainMutex(&scp->mx);
2809                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2810                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2811                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2812                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
2813                         }
2814                         lock_ReleaseMutex(&scp->mx);
2815         }
2816     }
2817         lock_ReleaseMutex(&dsp->mx);
2818     if (code) {
2819                 cm_ReleaseUser(userp);
2820         smb_FreeTran2Packet(outp);
2821                 smb_DeleteDirSearch(dsp);
2822                 smb_ReleaseDirSearch(dsp);
2823         return code;
2824         }
2825
2826     /* get the directory size */
2827         lock_ObtainMutex(&scp->mx);
2828     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2829                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2830         if (code) {
2831                 lock_ReleaseMutex(&scp->mx);
2832         cm_ReleaseSCache(scp);
2833         cm_ReleaseUser(userp);
2834         smb_FreeTran2Packet(outp);
2835                 smb_DeleteDirSearch(dsp);
2836                 smb_ReleaseDirSearch(dsp);
2837         return code;
2838     }
2839
2840   startsearch:
2841     dirLength = scp->length;
2842     bufferp = NULL;
2843     bufferOffset.LowPart = bufferOffset.HighPart = 0;
2844     curOffset.HighPart = 0;
2845     curOffset.LowPart = nextCookie;
2846         origOp = outp->datap;
2847
2848     foundInexact = 0;
2849     code = 0;
2850     returnedNames = 0;
2851     bytesInBuffer = 0;
2852     while (1) {
2853                 op = origOp;
2854                 if (searchFlags & 4)
2855                         /* skip over resume key */
2856                         op += 4;
2857
2858                 /* make sure that curOffset.LowPart doesn't point to the first
2859          * 32 bytes in the 2nd through last dir page, and that it doesn't
2860          * point at the first 13 32-byte chunks in the first dir page,
2861          * since those are dir and page headers, and don't contain useful
2862          * information.
2863          */
2864                 temp = curOffset.LowPart & (2048-1);
2865         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2866                         /* we're in the first page */
2867             if (temp < 13*32) temp = 13*32;
2868                 }
2869                 else {
2870                         /* we're in a later dir page */
2871             if (temp < 32) temp = 32;
2872         }
2873                 
2874         /* make sure the low order 5 bits are zero */
2875         temp &= ~(32-1);
2876                 
2877         /* now put temp bits back ito curOffset.LowPart */
2878         curOffset.LowPart &= ~(2048-1);
2879         curOffset.LowPart |= temp;
2880
2881         /* check if we've passed the dir's EOF */
2882         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
2883             eos = 1;
2884             break;
2885         }
2886
2887         /* check if we've returned all the names that will fit in the
2888          * response packet; we check return count as well as the number
2889          * of bytes requested.  We check the # of bytes after we find
2890          * the dir entry, since we'll need to check its size.
2891          */
2892         if (returnedNames >= maxCount) {
2893             break;
2894         }
2895
2896         /* see if we can use the bufferp we have now; compute in which
2897          * page the current offset would be, and check whether that's
2898          * the offset of the buffer we have.  If not, get the buffer.
2899          */
2900         thyper.HighPart = curOffset.HighPart;
2901         thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2902         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2903                         /* wrong buffer */
2904             if (bufferp) {
2905                 buf_Release(bufferp);
2906                 bufferp = NULL;
2907                         }       
2908                         lock_ReleaseMutex(&scp->mx);
2909                         lock_ObtainRead(&scp->bufCreateLock);
2910             code = buf_Get(scp, &thyper, &bufferp);
2911                         lock_ReleaseRead(&scp->bufCreateLock);
2912
2913                         /* now, if we're doing a star match, do bulk fetching
2914                          * of all of the status info for files in the dir.
2915              */
2916             if (starPattern) {
2917                                 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
2918                                           infoLevel, userp,
2919                                           &req);
2920                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2921                     && LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
2922                                         /* Don't bulk stat if risking timeout */
2923                                         int now = GetCurrentTime();
2924                                         if (now - req.startTime > 5000) {
2925                                                 scp->bulkStatProgress = thyper;
2926                                                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2927                                                 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2928                                         } else
2929                         cm_TryBulkStat(scp, &thyper, userp, &req);
2930                                 }
2931                         }
2932
2933             lock_ObtainMutex(&scp->mx);
2934             if (code) break;
2935             bufferOffset = thyper;
2936
2937             /* now get the data in the cache */
2938             while (1) {
2939                                 code = cm_SyncOp(scp, bufferp, userp, &req,
2940                                  PRSFS_LOOKUP,
2941                                  CM_SCACHESYNC_NEEDCALLBACK
2942                                  | CM_SCACHESYNC_READ);
2943                                 if (code) break;
2944                                 
2945                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2946
2947                 /* otherwise, load the buffer and try again */
2948                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2949                                     &req);
2950                 if (code) break;
2951             }
2952             if (code) {
2953                                 buf_Release(bufferp);
2954                 bufferp = NULL;
2955                 break;
2956                         }
2957         }       /* if (wrong buffer) ... */
2958                 
2959         /* now we have the buffer containing the entry we're interested
2960          * in; copy it out if it represents a non-deleted entry.
2961          */
2962                 entryInDir = curOffset.LowPart & (2048-1);
2963         entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2964
2965                 /* page header will help tell us which entries are free.  Page
2966                  * header can change more often than once per buffer, since
2967                  * AFS 3 dir page size may be less than (but not more than)
2968                  * a buffer package buffer.
2969          */
2970                 /* only look intra-buffer */
2971                 temp = curOffset.LowPart & (buf_bufferSize - 1);
2972         temp &= ~(2048 - 1);    /* turn off intra-page bits */
2973                 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2974
2975                 /* now determine which entry we're looking at in the page.
2976                  * If it is free (there's a free bitmap at the start of the
2977                  * dir), we should skip these 32 bytes.
2978          */
2979         slotInPage = (entryInDir & 0x7e0) >> 5;
2980         if (!(pageHeaderp->freeBitmap[slotInPage>>3]
2981                & (1 << (slotInPage & 0x7)))) {
2982                         /* this entry is free */
2983             numDirChunks = 1;   /* only skip this guy */
2984             goto nextEntry;
2985         }
2986
2987                 tp = bufferp->datap + entryInBuffer;
2988         dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
2989
2990         /* while we're here, compute the next entry's location, too,
2991                  * since we'll need it when writing out the cookie into the dir
2992                  * listing stream.
2993          *
2994          * XXXX Probably should do more sanity checking.
2995          */
2996                 numDirChunks = cm_NameEntries(dep->name, &onbytes);
2997                 
2998         /* compute offset of cookie representing next entry */
2999         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3000
3001                 /* Need 8.3 name? */
3002                 NeedShortName = 0;
3003                 if (infoLevel == 0x104
3004                     && dep->fid.vnode != 0
3005                     && !cm_Is8Dot3(dep->name)) {
3006                         cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3007                         NeedShortName = 1;
3008                 }
3009
3010         /* When matching, we are using doing a case fold if we have a wildcard mask.
3011          * If we get a non-wildcard match, it's a lookup for a specific file. 
3012          */
3013         if (dep->fid.vnode != 0 && 
3014             (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0))
3015               || (NeedShortName
3016                    && smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3017
3018             /* Eliminate entries that don't match requested attributes */
3019             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
3020                  smb_IsDotFile(dep->name))
3021                 goto nextEntry; /* no hidden files */
3022                     
3023             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
3024             {
3025                 /* We have already done the cm_TryBulkStat above */
3026                 fid.cell = scp->fid.cell;
3027                 fid.volume = scp->fid.volume;
3028                 fid.vnode = ntohl(dep->fid.vnode);
3029                 fid.unique = ntohl(dep->fid.unique);
3030                 fileType = cm_FindFileType(&fid);
3031                 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3032                  "has filetype %d", dep->name,
3033                  fileType);*/
3034                 if (fileType == CM_SCACHETYPE_DIRECTORY)
3035                     goto nextEntry;
3036             }
3037
3038                         /* finally check if this name will fit */
3039
3040                         /* standard dir entry stuff */
3041                         if (infoLevel < 0x101)
3042                                 ohbytes = 23;   /* pre-NT */
3043                         else if (infoLevel == 0x103)
3044                                 ohbytes = 12;   /* NT names only */
3045                         else
3046                                 ohbytes = 64;   /* NT */
3047
3048                         if (infoLevel == 0x104)
3049                                 ohbytes += 26;  /* Short name & length */
3050
3051             if (searchFlags & 4) {
3052                 ohbytes += 4;   /* if resume key required */
3053                         }   
3054
3055             if (infoLevel != 1
3056                  && infoLevel != 0x101
3057                  && infoLevel != 0x103)
3058                                 ohbytes += 4;   /* EASIZE */
3059
3060                         /* add header to name & term. null */
3061                         orbytes = onbytes + ohbytes + 1;
3062
3063                         /* now, we round up the record to a 4 byte alignment,
3064                          * and we make sure that we have enough room here for
3065                          * even the aligned version (so we don't have to worry
3066                          * about an * overflow when we pad things out below).
3067                          * That's the reason for the alignment arithmetic below.
3068              */
3069                         if (infoLevel >= 0x101)
3070                                 align = (4 - (orbytes & 3)) & 3;
3071                         else
3072                                 align = 0;
3073                         if (orbytes + bytesInBuffer + align > maxReturnData)
3074                 break;
3075
3076                         /* this is one of the entries to use: it is not deleted
3077                          * and it matches the star pattern we're looking for.
3078                          * Put out the name, preceded by its length.
3079              */
3080                         /* First zero everything else */
3081                         memset(origOp, 0, ohbytes);
3082
3083                         if (infoLevel <= 0x101)
3084                 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
3085                         else if (infoLevel == 0x103)
3086                                 *((u_long *)(op + 8)) = onbytes;
3087                         else
3088                                 *((u_long *)(op + 60)) = onbytes;
3089             strcpy(origOp+ohbytes, dep->name);
3090
3091                         /* Short name if requested and needed */
3092             if (infoLevel == 0x104) {
3093                                 if (NeedShortName) {
3094                                         strcpy(op + 70, shortName);
3095                                         *(op + 68) = shortNameEnd - shortName;
3096                                 }
3097                         }
3098
3099             /* now, adjust the # of entries copied */
3100             returnedNames++;
3101
3102                         /* NextEntryOffset and FileIndex */
3103                         if (infoLevel >= 101) {
3104                                 int entryOffset = orbytes + align;
3105                                 *((u_long *)op) = entryOffset;
3106                                 *((u_long *)(op+4)) = nextEntryCookie;
3107                         }
3108
3109             /* now we emit the attribute.  This is tricky, since
3110              * we need to really stat the file to find out what
3111                          * type of entry we've got.  Right now, we're copying
3112                          * out data from * a buffer, while holding the scp
3113                          * locked, so it isn't really convenient to stat
3114                          * something now.  We'll put in a place holder
3115              * now, and make a second pass before returning this
3116                          * to get the real attributes.  So, we just skip the
3117                          * data for now, and adjust it later.  We allocate a
3118                          * patch record to make it easy to find this point
3119                          * later.  The replay will happen at a time when it is
3120                          * safe to unlock the directory.
3121              */
3122                         if (infoLevel != 0x103) {
3123                                 curPatchp = malloc(sizeof(*curPatchp));
3124                 osi_QAdd((osi_queue_t **) &dirListPatchesp,
3125                           &curPatchp->q);
3126                                 curPatchp->dptr = op;
3127                                 if (infoLevel >= 0x101)
3128                                         curPatchp->dptr += 8;
3129
3130                 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
3131                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3132                 }
3133                 else
3134                     curPatchp->flags = 0;
3135
3136                                 curPatchp->fid.cell = scp->fid.cell;
3137                                 curPatchp->fid.volume = scp->fid.volume;
3138                                 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3139                                 curPatchp->fid.unique = ntohl(dep->fid.unique);
3140
3141                 /* temp */
3142                 curPatchp->dep = dep;
3143                         }   
3144
3145                         if (searchFlags & 4)
3146                                 /* put out resume key */
3147                                 *((u_long *)origOp) = nextEntryCookie;
3148
3149                         /* Adjust byte ptr and count */
3150                         origOp += orbytes;      /* skip entire record */
3151             bytesInBuffer += orbytes;
3152
3153                         /* and pad the record out */
3154             while (--align >= 0) {
3155                                 *origOp++ = 0;
3156                 bytesInBuffer++;
3157             }
3158
3159                 }       /* if we're including this name */
3160         else if (!NeedShortName &&
3161                  !starPattern &&
3162                  !foundInexact &&
3163                                                         dep->fid.vnode != 0 &&
3164                  smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
3165             /* We were looking for exact matches, but here's an inexact one*/
3166             foundInexact = 1;
3167         }
3168                 
3169       nextEntry:
3170         /* and adjust curOffset to be where the new cookie is */
3171                 thyper.HighPart = 0;
3172         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3173         curOffset = LargeIntegerAdd(thyper, curOffset);
3174     }           /* while copying data for dir listing */
3175
3176     /* If we didn't get a star pattern, we did an exact match during the first pass. 
3177      * If there were no exact matches found, we fail over to inexact matches by
3178      * marking the query as a star pattern (matches all case permutations), and
3179      * re-running the query. 
3180      */
3181     if (returnedNames == 0 && !starPattern && foundInexact) {
3182         osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
3183         starPattern = 1;
3184         goto startsearch;
3185     }
3186
3187         /* release the mutex */
3188         lock_ReleaseMutex(&scp->mx);
3189     if (bufferp) buf_Release(bufferp);
3190
3191         /* apply and free last set of patches; if not doing a star match, this
3192          * will be empty, but better safe (and freeing everything) than sorry.
3193      */
3194     smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
3195                               &req);
3196         
3197     /* now put out the final parameters */
3198         if (returnedNames == 0) eos = 1;
3199     if (p->opcode == 1) {
3200                 /* find first */
3201         outp->parmsp[0] = (unsigned short) dsp->cookie;
3202         outp->parmsp[1] = returnedNames;
3203         outp->parmsp[2] = eos;
3204         outp->parmsp[3] = 0;            /* nothing wrong with EAS */
3205         outp->parmsp[4] = 0;    
3206         /* don't need last name to continue
3207          * search, cookie is enough.  Normally,
3208          * this is the offset of the file name
3209          * of the last entry returned.
3210          */
3211         outp->totalParms = 10;  /* in bytes */
3212     }
3213     else {
3214         /* find next */
3215         outp->parmsp[0] = returnedNames;
3216         outp->parmsp[1] = eos;
3217         outp->parmsp[2] = 0;    /* EAS error */
3218         outp->parmsp[3] = 0;    /* last name, as above */
3219         outp->totalParms = 8;   /* in bytes */
3220     }   
3221
3222         /* return # of bytes in the buffer */
3223     outp->totalData = bytesInBuffer;
3224
3225         osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
3226               returnedNames, code);
3227
3228         /* Return error code if unsuccessful on first request */
3229         if (code == 0 && p->opcode == 1 && returnedNames == 0)
3230                 code = CM_ERROR_NOSUCHFILE;
3231
3232         /* if we're supposed to close the search after this request, or if
3233      * we're supposed to close the search if we're done, and we're done,
3234      * or if something went wrong, close the search.
3235      */
3236     /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
3237         if ((searchFlags & 1) || (returnedNames == 0) || 
3238          ((searchFlags & 2) && eos) || code != 0)
3239             smb_DeleteDirSearch(dsp);
3240         if (code)
3241         smb_SendTran2Error(vcp, p, opx, code);
3242         else {
3243         smb_SendTran2Packet(vcp, outp, opx);
3244         }
3245         smb_FreeTran2Packet(outp);
3246     smb_ReleaseDirSearch(dsp);
3247     cm_ReleaseSCache(scp);
3248     cm_ReleaseUser(userp);
3249     return 0;
3250 }
3251
3252 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3253 {
3254     int dirHandle;
3255     smb_dirSearch_t *dsp;
3256
3257     dirHandle = smb_GetSMBParm(inp, 0);
3258         
3259     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
3260
3261     dsp = smb_FindDirSearch(dirHandle);
3262         
3263     if (!dsp)
3264                 return CM_ERROR_BADFD;
3265         
3266     /* otherwise, we have an FD to destroy */
3267     smb_DeleteDirSearch(dsp);
3268     smb_ReleaseDirSearch(dsp);
3269         
3270         /* and return results */
3271         smb_SetSMBDataLength(outp, 0);
3272
3273     return 0;
3274 }
3275
3276 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3277 {
3278         smb_SetSMBDataLength(outp, 0);
3279     return 0;
3280 }
3281
3282 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3283 {
3284         char *pathp;
3285     long code = 0;
3286         cm_space_t *spacep;
3287     int excl;
3288     cm_user_t *userp;
3289     cm_scache_t *dscp;          /* dir we're dealing with */
3290     cm_scache_t *scp;           /* file we're creating */
3291     cm_attr_t setAttr;
3292     int initialModeBits;
3293     smb_fid_t *fidp;
3294     int attributes;
3295     char *lastNamep;
3296     long dosTime;
3297     int openFun;
3298     int trunc;
3299     int openMode;
3300     int extraInfo;
3301     int openAction;
3302     int parmSlot;                       /* which parm we're dealing with */
3303         char *tidPathp;
3304         cm_req_t req;
3305
3306         cm_InitReq(&req);
3307
3308     scp = NULL;
3309         
3310         extraInfo = (smb_GetSMBParm(inp, 2) & 1);       /* return extra info */
3311         openFun = smb_GetSMBParm(inp, 8);       /* open function */
3312     excl = ((openFun & 3) == 0);
3313     trunc = ((openFun & 3) == 2);               /* truncate it */
3314         openMode = (smb_GetSMBParm(inp, 3) & 0x7);
3315     openAction = 0;                     /* tracks what we did */
3316
3317     attributes = smb_GetSMBParm(inp, 5);
3318     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
3319
3320         /* compute initial mode bits based on read-only flag in attributes */
3321     initialModeBits = 0666;
3322     if (attributes & 1) initialModeBits &= ~0222;
3323         
3324     pathp = smb_GetSMBData(inp, NULL);
3325
3326         spacep = inp->spacep;
3327     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3328
3329         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3330                 /* special case magic file name for receiving IOCTL requests
3331          * (since IOCTL calls themselves aren't getting through).
3332          */
3333 #ifdef NOTSERVICE
3334         osi_Log0(smb_logp, "IOCTL Open");
3335 #endif
3336
3337         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3338         smb_SetupIoctlFid(fidp, spacep);
3339
3340                 /* set inp->fid so that later read calls in same msg can find fid */
3341         inp->fid = fidp->fid;
3342         
3343         /* copy out remainder of the parms */
3344                 parmSlot = 2;
3345                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3346                 if (extraInfo) {
3347             smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
3348             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* mod time */
3349             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
3350             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* len */
3351             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
3352             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
3353             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
3354             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
3355                 }   
3356                 /* and the final "always present" stuff */
3357         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
3358                 /* next write out the "unique" ID */
3359                 smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
3360                 smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
3361         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
3362         smb_SetSMBDataLength(outp, 0);
3363
3364                 /* and clean up fid reference */
3365         smb_ReleaseFID(fidp);
3366         return 0;
3367     }
3368
3369 #ifdef DEBUG_VERBOSE
3370     {
3371         char *hexp, *asciip;
3372         asciip = (lastNamep ? lastNamep : pathp );
3373         hexp = osi_HexifyString(asciip);
3374         DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
3375         free(hexp);
3376     }
3377 #endif
3378     userp = smb_GetUser(vcp, inp);
3379
3380         dscp = NULL;
3381         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3382         code = cm_NameI(cm_rootSCachep, pathp,
3383                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3384                     userp, tidPathp, &req, &scp);
3385         if (code != 0) {
3386                 code = cm_NameI(cm_rootSCachep, spacep->data,
3387                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3388                         userp, tidPathp, &req, &dscp);
3389
3390         if (code) {
3391             cm_ReleaseUser(userp);
3392             return code;
3393         }
3394         
3395         /* otherwise, scp points to the parent directory.  Do a lookup,
3396          * and truncate the file if we find it, otherwise we create the
3397          * file.
3398          */
3399         if (!lastNamep) lastNamep = pathp;
3400         else lastNamep++;
3401         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
3402                           &req, &scp);
3403         if (code && code != CM_ERROR_NOSUCHFILE) {
3404                         cm_ReleaseSCache(dscp);
3405             cm_ReleaseUser(userp);
3406             return code;
3407         }
3408         }
3409         
3410     /* if we get here, if code is 0, the file exists and is represented by
3411      * scp.  Otherwise, we have to create it.  The dir may be represented
3412      * by dscp, or we may have found the file directly.  If code is non-zero,
3413      * scp is NULL.
3414      */
3415         if (code == 0) {
3416         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
3417         if (code) {
3418             if (dscp) cm_ReleaseSCache(dscp);
3419             cm_ReleaseSCache(scp);
3420             cm_ReleaseUser(userp);
3421             return code;
3422         }
3423
3424                 if (excl) {
3425                         /* oops, file shouldn't be there */
3426             if (dscp) cm_ReleaseSCache(dscp);
3427             cm_ReleaseSCache(scp);
3428             cm_ReleaseUser(userp);
3429             return CM_ERROR_EXISTS;
3430         }
3431
3432                 if (trunc) {
3433                         setAttr.mask = CM_ATTRMASK_LENGTH;
3434             setAttr.length.LowPart = 0;
3435             setAttr.length.HighPart = 0;
3436                         code = cm_SetAttr(scp, &setAttr, userp, &req);
3437             openAction = 3;     /* truncated existing file */
3438                 }
3439         else openAction = 1;    /* found existing file */
3440     }
3441         else if (!(openFun & 0x10)) {
3442                 /* don't create if not found */
3443         if (dscp) cm_ReleaseSCache(dscp);
3444         cm_ReleaseUser(userp);
3445         return CM_ERROR_NOSUCHFILE;
3446     }
3447     else {
3448                 osi_assert(dscp != NULL);
3449                 osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
3450                  osi_LogSaveString(smb_logp, lastNamep));
3451                 openAction = 2; /* created file */
3452                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
3453                 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
3454         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
3455                          &req);
3456                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3457                         smb_NotifyChange(FILE_ACTION_ADDED,
3458                              FILE_NOTIFY_CHANGE_FILE_NAME,
3459                              dscp, lastNamep, NULL, TRUE);
3460         if (!excl && code == CM_ERROR_EXISTS) {
3461                         /* not an exclusive create, and someone else tried
3462                          * creating it already, then we open it anyway.  We
3463                          * don't bother retrying after this, since if this next
3464                          * fails, that means that the file was deleted after we
3465                          * started this call.
3466              */
3467             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
3468                              userp, &req, &scp);
3469             if (code == 0) {
3470                 if (trunc) {
3471                                         setAttr.mask = CM_ATTRMASK_LENGTH;
3472                     setAttr.length.LowPart = 0;
3473                     setAttr.length.HighPart = 0;
3474                     code = cm_SetAttr(scp, &setAttr, userp, &req);
3475                 }   
3476                         }       /* lookup succeeded */
3477         }
3478     }
3479         
3480         /* we don't need this any longer */
3481         if (dscp) cm_ReleaseSCache(dscp);
3482
3483     if (code) {
3484                 /* something went wrong creating or truncating the file */
3485         if (scp) cm_ReleaseSCache(scp);
3486         cm_ReleaseUser(userp);
3487         return code;
3488     }
3489         
3490         /* make sure we're about to open a file */
3491         if (scp->fileType != CM_SCACHETYPE_FILE) {
3492                 cm_ReleaseSCache(scp);
3493                 cm_ReleaseUser(userp);
3494                 return CM_ERROR_ISDIR;
3495         }
3496
3497     /* now all we have to do is open the file itself */
3498     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3499     osi_assert(fidp);
3500         
3501         /* save a pointer to the vnode */
3502     fidp->scp = scp;
3503         
3504         /* compute open mode */
3505     if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
3506     if (openMode == 1 || openMode == 2)
3507         fidp->flags |= SMB_FID_OPENWRITE;
3508
3509         smb_ReleaseFID(fidp);
3510         
3511         cm_Open(scp, 0, userp);
3512
3513         /* set inp->fid so that later read calls in same msg can find fid */
3514     inp->fid = fidp->fid;
3515         
3516     /* copy out remainder of the parms */
3517         parmSlot = 2;
3518         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3519         lock_ObtainMutex(&scp->mx);
3520         if (extraInfo) {
3521         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
3522                 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
3523         smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
3524         smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
3525         smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
3526         smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
3527         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
3528         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
3529         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
3530         }
3531         /* and the final "always present" stuff */
3532     smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
3533         /* next write out the "unique" ID */
3534         smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
3535         smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
3536     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
3537         lock_ReleaseMutex(&scp->mx);
3538     smb_SetSMBDataLength(outp, 0);
3539
3540         osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
3541
3542     cm_ReleaseUser(userp);
3543     /* leave scp held since we put it in fidp->scp */
3544     return 0;
3545 }   
3546
3547 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3548 {
3549         cm_req_t req;
3550         cm_user_t *userp;
3551         unsigned short fid;
3552         smb_fid_t *fidp;
3553         cm_scache_t *scp;
3554         unsigned char LockType;
3555         unsigned short NumberOfUnlocks, NumberOfLocks;
3556         unsigned long Timeout;
3557         char *op;
3558         LARGE_INTEGER LOffset, LLength;
3559         smb_waitingLock_t *waitingLock;
3560         void *lockp;
3561         long code = 0;
3562         int i;
3563
3564         cm_InitReq(&req);
3565
3566         fid = smb_GetSMBParm(inp, 2);
3567         fid = smb_ChainFID(fid, inp);
3568
3569         fidp = smb_FindFID(vcp, fid, 0);
3570         if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
3571                 return CM_ERROR_BADFD;
3572         }
3573         /* set inp->fid so that later read calls in same msg can find fid */
3574     inp->fid = fid;
3575
3576         userp = smb_GetUser(vcp, inp);
3577
3578         scp = fidp->scp;
3579
3580         lock_ObtainMutex(&scp->mx);
3581         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3582                          CM_SCACHESYNC_NEEDCALLBACK
3583                          | CM_SCACHESYNC_GETSTATUS
3584                          | CM_SCACHESYNC_LOCK);
3585         if (code) goto doneSync;
3586
3587         LockType = smb_GetSMBParm(inp, 3) & 0xff;
3588         Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
3589         NumberOfUnlocks = smb_GetSMBParm(inp, 6);
3590         NumberOfLocks = smb_GetSMBParm(inp, 7);
3591
3592         op = smb_GetSMBData(inp, NULL);
3593
3594         for (i=0; i<NumberOfUnlocks; i++) {
3595                 if (LockType & 0x10) {
3596                         /* Large Files */
3597                         LOffset.HighPart = *((LONG *)(op + 4));
3598                         LOffset.LowPart = *((DWORD *)(op + 8));
3599                         LLength.HighPart = *((LONG *)(op + 12));
3600                         LLength.LowPart = *((DWORD *)(op + 16));
3601                         op += 20;
3602                 }
3603                 else {
3604                         /* Not Large Files */
3605                         LOffset.HighPart = 0;
3606                         LOffset.LowPart = *((DWORD *)(op + 2));
3607                         LLength.HighPart = 0;
3608                         LLength.LowPart = *((DWORD *)(op + 6));
3609                         op += 10;
3610                 }
3611                 if (LargeIntegerNotEqualToZero(LOffset))
3612                         continue;
3613                 /* Do not check length -- length check done in cm_Unlock */
3614
3615                 code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
3616                 if (code) goto done;
3617         }
3618
3619         for (i=0; i<NumberOfLocks; i++) {
3620                 if (LockType & 0x10) {
3621                         /* Large Files */
3622                         LOffset.HighPart = *((LONG *)(op + 4));
3623                         LOffset.LowPart = *((DWORD *)(op + 8));
3624                         LLength.HighPart = *((LONG *)(op + 12));
3625                         LLength.LowPart = *((DWORD *)(op + 16));
3626                         op += 20;
3627                 }
3628                 else {
3629                         /* Not Large Files */
3630                         LOffset.HighPart = 0;
3631                         LOffset.LowPart = *((DWORD *)(op + 2));
3632                         LLength.HighPart = 0;
3633                         LLength.LowPart = *((DWORD *)(op + 6));
3634                         op += 10;
3635                 }
3636                 if (LargeIntegerNotEqualToZero(LOffset))
3637                         continue;
3638                 if (LargeIntegerLessThan(LOffset, scp->length))
3639                         continue;
3640
3641                 code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
3642                                 userp, &req, &lockp);
3643                 if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
3644                         /* Put on waiting list */
3645                         waitingLock = malloc(sizeof(smb_waitingLock_t));
3646                         waitingLock->vcp = vcp;
3647                         waitingLock->inp = smb_CopyPacket(inp);
3648                         waitingLock->outp = smb_CopyPacket(outp);
3649                         waitingLock->timeRemaining = Timeout;
3650                         waitingLock->lockp = lockp;
3651                         lock_ObtainWrite(&smb_globalLock);
3652                         osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
3653                                  &waitingLock->q);
3654                         osi_Wakeup((long) &smb_allWaitingLocks);
3655                         lock_ReleaseWrite(&smb_globalLock);
3656                         /* don't send reply immediately */
3657                         outp->flags |= SMB_PACKETFLAG_NOSEND;
3658                 }
3659                 if (code) break;
3660         }
3661
3662         if (code) {
3663                 /* release any locks acquired before the failure */
3664         }
3665         else
3666                 smb_SetSMBDataLength(outp, 0);
3667 done:
3668         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
3669 doneSync:
3670         lock_ReleaseMutex(&scp->mx);
3671         cm_ReleaseUser(userp);
3672         smb_ReleaseFID(fidp);
3673
3674         return code;
3675 }
3676
3677 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3678 {
3679         unsigned short fid;
3680     smb_fid_t *fidp;
3681     cm_scache_t *scp;
3682     long code = 0;
3683     long searchTime;
3684     cm_user_t *userp;
3685         cm_req_t req;
3686
3687         cm_InitReq(&req);
3688
3689     fid = smb_GetSMBParm(inp, 0);
3690     fid = smb_ChainFID(fid, inp);
3691         
3692     fidp = smb_FindFID(vcp, fid, 0);
3693     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
3694                 return CM_ERROR_BADFD;
3695     }
3696         
3697     userp = smb_GetUser(vcp, inp);
3698         
3699     scp = fidp->scp;
3700         
3701     /* otherwise, stat the file */
3702         lock_ObtainMutex(&scp->mx);
3703     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3704                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3705         if (code) goto done;
3706
3707         /* decode times.  We need a search time, but the response to this
3708      * call provides the date first, not the time, as returned in the
3709      * searchTime variable.  So we take the high-order bits first.
3710      */
3711         smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
3712     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);       /* ctime */
3713     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
3714     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);       /* atime */
3715     smb_SetSMBParm(outp, 3, searchTime & 0xffff);
3716     smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);       /* mtime */
3717     smb_SetSMBParm(outp, 5, searchTime & 0xffff);
3718
3719     /* now handle file size and allocation size */
3720     smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);              /* file size */
3721     smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
3722     smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);              /* alloc size */
3723     smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
3724
3725         /* file attribute */
3726     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
3727         
3728     /* and finalize stuff */
3729     smb_SetSMBDataLength(outp, 0);
3730     code = 0;
3731
3732   done:
3733         lock_ReleaseMutex(&scp->mx);
3734         cm_ReleaseUser(userp);
3735         smb_ReleaseFID(fidp);
3736         return code;
3737 }
3738
3739 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3740 {
3741         unsigned short fid;
3742     smb_fid_t *fidp;
3743     cm_scache_t *scp;
3744     long code = 0;
3745         long searchTime;
3746     long unixTime;
3747     cm_user_t *userp;
3748     cm_attr_t attrs;
3749         cm_req_t req;
3750
3751         cm_InitReq(&req);
3752
3753     fid = smb_GetSMBParm(inp, 0);
3754     fid = smb_ChainFID(fid, inp);
3755         
3756     fidp = smb_FindFID(vcp, fid, 0);
3757     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
3758                 return CM_ERROR_BADFD;
3759     }
3760         
3761     userp = smb_GetUser(vcp, inp);
3762         
3763     scp = fidp->scp;
3764         
3765         /* now prepare to call cm_setattr.  This message only sets various times,
3766      * and AFS only implements mtime, and we'll set the mtime if that's
3767      * requested.  The others we'll ignore.
3768      */
3769         searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
3770         
3771     if (searchTime != 0) {
3772                 smb_UnixTimeFromSearchTime(&unixTime, searchTime);
3773
3774         if ( unixTime != -1 ) {
3775             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
3776             attrs.clientModTime = unixTime;
3777             code = cm_SetAttr(scp, &attrs, userp, &req);
3778
3779             osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
3780         } else {
3781             osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
3782         }
3783     }
3784     else code = 0;
3785
3786         cm_ReleaseUser(userp);
3787         smb_ReleaseFID(fidp);
3788         return code;
3789 }
3790
3791
3792 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3793 {
3794         osi_hyper_t offset;
3795     long count, finalCount;
3796     unsigned short fd;
3797     smb_fid_t *fidp;
3798     long code = 0;
3799     cm_user_t *userp;
3800     char *op;
3801         
3802     fd = smb_GetSMBParm(inp, 2);
3803     count = smb_GetSMBParm(inp, 5);
3804     offset.HighPart = 0;        /* too bad */
3805     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
3806
3807     osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
3808              fd, offset.LowPart, count);
3809         
3810         fd = smb_ChainFID(fd, inp);
3811     fidp = smb_FindFID(vcp, fd, 0);
3812     if (!fidp) {
3813                 return CM_ERROR_BADFD;
3814     }
3815         /* set inp->fid so that later read calls in same msg can find fid */
3816     inp->fid = fd;
3817
3818     if (fidp->flags & SMB_FID_IOCTL) {
3819                 return smb_IoctlV3Read(fidp, vcp, inp, outp);
3820     }
3821         
3822         userp = smb_GetUser(vcp, inp);
3823
3824         /* 0 and 1 are reserved for request chaining, were setup by our caller,
3825      * and will be further filled in after we return.
3826      */
3827     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
3828     smb_SetSMBParm(outp, 3, 0); /* resvd */
3829     smb_SetSMBParm(outp, 4, 0); /* resvd */
3830         smb_SetSMBParm(outp, 5, count); /* # of bytes we're going to read */
3831     /* fill in #6 when we have all the parameters' space reserved */
3832     smb_SetSMBParm(outp, 7, 0); /* resv'd */
3833     smb_SetSMBParm(outp, 8, 0); /* resv'd */
3834     smb_SetSMBParm(outp, 9, 0); /* resv'd */
3835     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
3836         smb_SetSMBParm(outp, 11, 0);    /* reserved */
3837
3838         /* get op ptr after putting in the parms, since otherwise we don't
3839      * know where the data really is.
3840      */
3841     op = smb_GetSMBData(outp, NULL);
3842         
3843     /* now fill in offset from start of SMB header to first data byte (to op) */
3844     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
3845
3846         /* set the packet data length the count of the # of bytes */
3847     smb_SetSMBDataLength(outp, count);
3848
3849 #ifndef DJGPP
3850         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
3851 #else /* DJGPP */
3852         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
3853 #endif /* !DJGPP */
3854
3855         /* fix some things up */
3856         smb_SetSMBParm(outp, 5, finalCount);
3857         smb_SetSMBDataLength(outp, finalCount);
3858
3859     smb_ReleaseFID(fidp);
3860
3861     cm_ReleaseUser(userp);
3862     return code;
3863 }   
3864         
3865 /*
3866  * Values for createDisp, copied from NTDDK.H
3867  *
3868  *  FILE_SUPERSEDE      0       (???)
3869  *  FILE_OPEN           1       (open)
3870  *  FILE_CREATE         2       (exclusive)
3871  *  FILE_OPEN_IF        3       (non-exclusive)
3872  *  FILE_OVERWRITE      4       (open & truncate, but do not create)
3873  *  FILE_OVERWRITE_IF   5       (open & truncate, or create)
3874  */
3875
3876 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3877 {
3878         char *pathp, *realPathp;
3879         long code = 0;
3880         cm_space_t *spacep;
3881         cm_user_t *userp;
3882         cm_scache_t *dscp;              /* parent dir */
3883         cm_scache_t *scp;               /* file to create or open */
3884         cm_attr_t setAttr;
3885         char *lastNamep;
3886     char *treeStartp;
3887         unsigned short nameLength;
3888         unsigned int flags;
3889         unsigned int requestOpLock;
3890         unsigned int requestBatchOpLock;
3891         unsigned int mustBeDir;
3892     unsigned int treeCreate;
3893         int realDirFlag;
3894         unsigned int desiredAccess;
3895         unsigned int extAttributes;
3896         unsigned int createDisp;
3897         unsigned int createOptions;
3898         int initialModeBits;
3899         unsigned short baseFid;
3900         smb_fid_t *baseFidp;
3901         smb_fid_t *fidp;
3902         cm_scache_t *baseDirp;
3903         unsigned short openAction;
3904         int parmSlot;
3905         long fidflags;
3906         FILETIME ft;
3907         LARGE_INTEGER sz;
3908         char *tidPathp;
3909         BOOL foundscp;
3910         cm_req_t req;
3911
3912         cm_InitReq(&req);
3913
3914     treeCreate = FALSE;
3915         foundscp = FALSE;
3916         scp = NULL;
3917
3918         nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
3919         flags = smb_GetSMBOffsetParm(inp, 3, 1)
3920                   | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
3921         requestOpLock = flags & 0x02;
3922         requestBatchOpLock = flags & 0x04;
3923         mustBeDir = flags & 0x08;
3924
3925         /*
3926          * Why all of a sudden 32-bit FID?
3927          * We will reject all bits higher than 16.
3928          */
3929         if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
3930                 return CM_ERROR_INVAL;
3931         baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
3932         desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
3933                           | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
3934         extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
3935                           | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
3936         createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
3937                         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
3938         createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
3939                           | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
3940
3941         /* mustBeDir is never set; createOptions directory bit seems to be
3942      * more important
3943          */
3944         if (createOptions & 1)
3945                 realDirFlag = 1;
3946         else if (createOptions & 0x40)
3947                 realDirFlag = 0;
3948         else
3949                 realDirFlag = -1;
3950
3951         /*
3952          * compute initial mode bits based on read-only flag in
3953          * extended attributes
3954          */
3955         initialModeBits = 0666;
3956         if (extAttributes & 1) initialModeBits &= ~0222;
3957
3958         pathp = smb_GetSMBData(inp, NULL);
3959         /* Sometimes path is not null-terminated, so we make a copy. */
3960         realPathp = malloc(nameLength+1);
3961         memcpy(realPathp, pathp, nameLength);
3962         realPathp[nameLength] = 0;
3963
3964         spacep = inp->spacep;
3965         smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
3966
3967     osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
3968     osi_Log4(smb_logp,"NTCreateX da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
3969     osi_Log1(smb_logp,"NTCreateX lastNamep=[%s]",osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
3970
3971         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3972                 /* special case magic file name for receiving IOCTL requests
3973                  * (since IOCTL calls themselves aren't getting through).
3974                  */
3975                 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3976                 smb_SetupIoctlFid(fidp, spacep);
3977                 osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
3978
3979                 /* set inp->fid so that later read calls in same msg can find fid */
3980                 inp->fid = fidp->fid;
3981
3982                 /* out parms */
3983                 parmSlot = 2;
3984                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
3985                 smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
3986                 smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
3987                 /* times */
3988                 memset(&ft, 0, sizeof(ft));
3989                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3990                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3991                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3992                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
3993                 smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
3994                 sz.HighPart = 0x7fff; sz.LowPart = 0;
3995                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
3996                 smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
3997                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
3998                 smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
3999                 smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
4000                 smb_SetSMBDataLength(outp, 0);
4001
4002                 /* clean up fid reference */
4003                 smb_ReleaseFID(fidp);
4004                 free(realPathp);
4005                 return 0;
4006         }
4007
4008 #ifdef DEBUG_VERBOSE
4009     {
4010         char *hexp, *asciip;
4011         asciip = (lastNamep? lastNamep : realPathp);
4012         hexp = osi_HexifyString( asciip );
4013         DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
4014         free(hexp);
4015     }
4016 #endif
4017     userp = smb_GetUser(vcp, inp);
4018     if (!userp) {
4019         osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
4020         free(realPathp);
4021         return CM_ERROR_INVAL;
4022     }
4023
4024         if (baseFid == 0) {
4025                 baseDirp = cm_rootSCachep;
4026                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4027         }
4028         else {
4029         baseFidp = smb_FindFID(vcp, baseFid, 0);
4030         if (!baseFidp) {
4031                 osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
4032                 free(realPathp);
4033                 cm_ReleaseUser(userp);
4034                 return CM_ERROR_INVAL;
4035         }
4036                 baseDirp = baseFidp->scp;
4037                 tidPathp = NULL;
4038         }
4039
4040     osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
4041         
4042     /* compute open mode */
4043         fidflags = 0;
4044         if (desiredAccess & DELETE)
4045                 fidflags |= SMB_FID_OPENDELETE;
4046         if (desiredAccess & AFS_ACCESS_READ)
4047                 fidflags |= SMB_FID_OPENREAD;
4048         if (desiredAccess & AFS_ACCESS_WRITE)
4049                 fidflags |= SMB_FID_OPENWRITE;
4050
4051         dscp = NULL;
4052         code = 0;
4053     /* For an exclusive create, we want to do a case sensitive match for the last component. */
4054     if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
4055         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4056                         userp, tidPathp, &req, &dscp);
4057         if (code == 0) {
4058             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
4059                              userp, &req, &scp);
4060             if (code == CM_ERROR_NOSUCHFILE) {
4061                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
4062                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
4063                 if (code == 0 && realDirFlag == 1) {
4064                                         cm_ReleaseSCache(scp);
4065                     cm_ReleaseSCache(dscp);
4066                     cm_ReleaseUser(userp);
4067                     free(realPathp);
4068                     return CM_ERROR_EXISTS;
4069                 }
4070             }
4071         } else
4072             dscp = NULL;
4073     } else {
4074         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4075                         userp, tidPathp, &req, &scp);
4076     }
4077     if (code == 0) 
4078                 foundscp = TRUE;
4079
4080         if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
4081                 /* look up parent directory */
4082         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
4083          * the immediate parent.  We have to work our way up realPathp until we hit something that we
4084          * recognize.
4085          */
4086
4087         if ( !dscp ) {
4088             while (1) {
4089                 char *tp;
4090
4091                 code = cm_NameI(baseDirp, spacep->data,
4092                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4093                              userp, tidPathp, &req, &dscp);
4094
4095                 if (code && 
4096                      (tp = strrchr(spacep->data,'\\')) &&
4097                      (createDisp == 2) &&
4098                      (realDirFlag == 1)) {
4099                     *tp++ = 0;
4100                     treeCreate = TRUE;
4101                     treeStartp = realPathp + (tp - spacep->data);
4102
4103                     if (*tp && !smb_IsLegalFilename(tp)) {
4104                         if (baseFid != 0) 
4105                             smb_ReleaseFID(baseFidp);
4106                         cm_ReleaseUser(userp);
4107                         free(realPathp);
4108                         return CM_ERROR_BADNTFILENAME;
4109                     }
4110                 }
4111                 else
4112                     break;
4113             }
4114         } else
4115             code = 0;
4116
4117         if (baseFid != 0) 
4118                         smb_ReleaseFID(baseFidp);
4119
4120         if (code) {
4121             osi_Log0(smb_logp,"NTCreateX parent not found");
4122             cm_ReleaseUser(userp);
4123             free(realPathp);
4124             return code;
4125         }
4126
4127         if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
4128             /* A file exists where we want a directory. */
4129             cm_ReleaseSCache(dscp);
4130             cm_ReleaseUser(userp);
4131             free(realPathp);
4132             return CM_ERROR_EXISTS;
4133         }
4134
4135         if (!lastNamep) 
4136             lastNamep = realPathp;
4137         else 
4138             lastNamep++;
4139
4140         if (!smb_IsLegalFilename(lastNamep)) {
4141             cm_ReleaseSCache(dscp);
4142             cm_ReleaseUser(userp);
4143             free(realPathp);
4144             return CM_ERROR_BADNTFILENAME;
4145         }
4146
4147         if (!foundscp && !treeCreate) {
4148             if (createDisp == 2 || createDisp == 4)
4149                 code = cm_Lookup(dscp, lastNamep,
4150                                   CM_FLAG_FOLLOW, userp, &req, &scp);
4151             else
4152                 code = cm_Lookup(dscp, lastNamep,
4153                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4154                                  userp, &req, &scp);
4155                         if (code && code != CM_ERROR_NOSUCHFILE) {
4156                                 cm_ReleaseSCache(dscp);
4157                                 cm_ReleaseUser(userp);
4158                                 free(realPathp);
4159                                 return code;
4160                         }
4161                 }
4162         }
4163         else {
4164                 if (baseFid != 0) 
4165                         smb_ReleaseFID(baseFidp);
4166         }
4167
4168         /* if we get here, if code is 0, the file exists and is represented by
4169          * scp.  Otherwise, we have to create it.  The dir may be represented
4170          * by dscp, or we may have found the file directly.  If code is non-zero,
4171          * scp is NULL.
4172          */
4173         if (code == 0 && !treeCreate) {
4174                 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
4175                                       &req);
4176                 if (code) {
4177                         if (dscp) cm_ReleaseSCache(dscp);
4178                         cm_ReleaseSCache(scp);
4179                         cm_ReleaseUser(userp);
4180                         free(realPathp);
4181                         return code;
4182                 }
4183
4184                 if (createDisp == 2) {
4185                         /* oops, file shouldn't be there */
4186                         if (dscp) cm_ReleaseSCache(dscp);
4187                         cm_ReleaseSCache(scp);
4188                         cm_ReleaseUser(userp);
4189                         free(realPathp);
4190                         return CM_ERROR_EXISTS;
4191                 }
4192
4193                 if (createDisp == 4
4194                     || createDisp == 5) {
4195                         setAttr.mask = CM_ATTRMASK_LENGTH;
4196                         setAttr.length.LowPart = 0;
4197                         setAttr.length.HighPart = 0;
4198                         code = cm_SetAttr(scp, &setAttr, userp, &req);
4199                         openAction = 3; /* truncated existing file */
4200                 }
4201                 else openAction = 1;    /* found existing file */
4202         }
4203         else if (createDisp == 1 || createDisp == 4) {
4204                 /* don't create if not found */
4205                 if (dscp) cm_ReleaseSCache(dscp);
4206                 cm_ReleaseUser(userp);
4207                 free(realPathp);
4208                 return CM_ERROR_NOSUCHFILE;
4209         }
4210         else if (realDirFlag == 0 || realDirFlag == -1) {
4211                 osi_assert(dscp != NULL);
4212                 osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
4213                                 osi_LogSaveString(smb_logp, lastNamep));
4214                 openAction = 2;         /* created file */
4215                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4216                 setAttr.clientModTime = time(NULL);
4217                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4218                                  &req);
4219                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4220                         smb_NotifyChange(FILE_ACTION_ADDED,
4221                                          FILE_NOTIFY_CHANGE_FILE_NAME,
4222                                          dscp, lastNamep, NULL, TRUE);
4223                 if (code == CM_ERROR_EXISTS && createDisp != 2) {
4224                         /* Not an exclusive create, and someone else tried
4225                          * creating it already, then we open it anyway.  We
4226                          * don't bother retrying after this, since if this next
4227                          * fails, that means that the file was deleted after we
4228                          * started this call.
4229                          */
4230                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4231                                          userp, &req, &scp);
4232                         if (code == 0) {
4233                                 if (createDisp == 5) {
4234                                         setAttr.mask = CM_ATTRMASK_LENGTH;
4235                                         setAttr.length.LowPart = 0;
4236                                         setAttr.length.HighPart = 0;
4237                                         code = cm_SetAttr(scp, &setAttr, userp,
4238                                                           &req);
4239                                 }
4240                         }       /* lookup succeeded */
4241                 }
4242         }
4243         else {
4244         char *tp, *pp;
4245         char *cp; /* This component */
4246         int clen = 0; /* length of component */
4247         cm_scache_t *tscp;
4248         int isLast = 0;
4249                 
4250         /* create directory */
4251                 if ( !treeCreate ) treeStartp = lastNamep;
4252         osi_assert(dscp != NULL);
4253         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
4254                                 osi_LogSaveString(smb_logp, treeStartp));
4255                 openAction = 2;         /* created directory */
4256
4257                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4258                 setAttr.clientModTime = time(NULL);
4259                 
4260                 pp = treeStartp;
4261                 cp = spacep->data;
4262                 tscp = dscp;
4263
4264                 while (pp && *pp) {
4265                         tp = strchr(pp, '\\');
4266                         if (!tp) {
4267                                 strcpy(cp,pp);
4268                 clen = strlen(cp);
4269                                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
4270                         }
4271                         else {
4272                                 clen = tp - pp;
4273                                 strncpy(cp,pp,clen);
4274                                 *(cp + clen) = 0;
4275                                 tp++;
4276                         }
4277                         pp = tp;
4278
4279                         if (clen == 0) continue; /* the supplied path can't have consecutive slashes either , but */
4280
4281                         /* cp is the next component to be created. */
4282                         code = cm_MakeDir(tscp, cp, 0, &setAttr, userp, &req);
4283                         if (code == 0 && (tscp->flags & CM_SCACHEFLAG_ANYWATCH))
4284                                 smb_NotifyChange(FILE_ACTION_ADDED,
4285                                 FILE_NOTIFY_CHANGE_DIR_NAME,
4286                                 tscp, cp, NULL, TRUE);
4287                         if (code == 0 || 
4288                                 (code == CM_ERROR_EXISTS && createDisp != 2)) {
4289                                         /* Not an exclusive create, and someone else tried
4290                                         * creating it already, then we open it anyway.  We
4291                                         * don't bother retrying after this, since if this next
4292                                         * fails, that means that the file was deleted after we
4293                                         * started this call.
4294                                         */
4295                                         code = cm_Lookup(tscp, cp, CM_FLAG_CASEFOLD,
4296                                                 userp, &req, &scp);
4297                                 }
4298                         if (code) break;
4299
4300                         if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
4301                                 cm_ReleaseSCache(tscp);
4302                                 tscp = scp; /* Newly created directory will be next parent */
4303                         }
4304                 }
4305
4306                 /* 
4307                 if we get here and code == 0, then scp is the last directory created, and tscp is the
4308                 parent of scp.  dscp got released if dscp != tscp. both tscp and scp are held.
4309                 */
4310                 dscp = tscp;
4311         }
4312
4313         if (code) {
4314                 /* something went wrong creating or truncating the file */
4315                 if (scp) cm_ReleaseSCache(scp);
4316         if (dscp) cm_ReleaseSCache(dscp);
4317                 cm_ReleaseUser(userp);
4318                 free(realPathp);
4319                 return code;
4320         }
4321
4322         /* make sure we have file vs. dir right (only applies for single component case) */
4323         if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
4324                 cm_ReleaseSCache(scp);
4325         if (dscp) cm_ReleaseSCache(dscp);
4326                 cm_ReleaseUser(userp);
4327                 free(realPathp);
4328                 return CM_ERROR_ISDIR;
4329         }
4330     /* (only applies to single component case) */
4331         if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
4332                 cm_ReleaseSCache(scp);
4333         if (dscp) cm_ReleaseSCache(dscp);
4334                 cm_ReleaseUser(userp);
4335                 free(realPathp);
4336                 return CM_ERROR_NOTDIR;
4337         }
4338
4339         /* open the file itself */
4340         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4341         osi_assert(fidp);
4342         /* save a pointer to the vnode */
4343         fidp->scp = scp;
4344
4345         fidp->flags = fidflags;
4346
4347         /* save parent dir and pathname for delete or change notification */
4348         if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
4349                 fidp->flags |= SMB_FID_NTOPEN;
4350                 fidp->NTopen_dscp = dscp;
4351                 cm_HoldSCache(dscp);
4352                 fidp->NTopen_pathp = strdup(lastNamep);
4353         }
4354         fidp->NTopen_wholepathp = realPathp;
4355
4356         /* we don't need this any longer */
4357         if (dscp) cm_ReleaseSCache(dscp);
4358         cm_Open(scp, 0, userp);
4359
4360         /* set inp->fid so that later read calls in same msg can find fid */
4361         inp->fid = fidp->fid;
4362
4363         /* out parms */
4364         parmSlot = 2;
4365         lock_ObtainMutex(&scp->mx);
4366         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
4367         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4368         smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
4369         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4370         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4371         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4372         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4373         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
4374         smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
4375                                                 parmSlot += 2;
4376         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
4377         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
4378         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
4379         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
4380         smb_SetSMBParmByte(outp, parmSlot,
4381                 scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
4382         lock_ReleaseMutex(&scp->mx);
4383         smb_SetSMBDataLength(outp, 0);
4384
4385         osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
4386                  osi_LogSaveString(smb_logp, realPathp));
4387
4388         smb_ReleaseFID(fidp);
4389
4390         cm_ReleaseUser(userp);
4391
4392     /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
4393
4394         /* leave scp held since we put it in fidp->scp */
4395         return 0;
4396 }
4397
4398 /*
4399  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
4400  * Instead, ultimately, would like to use a subroutine for common code.
4401  */
4402 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4403 {
4404         char *pathp, *realPathp;
4405         long code = 0;
4406         cm_space_t *spacep;
4407         cm_user_t *userp;
4408         cm_scache_t *dscp;              /* parent dir */
4409         cm_scache_t *scp;               /* file to create or open */
4410         cm_attr_t setAttr;
4411         char *lastNamep;
4412         unsigned long nameLength;
4413         unsigned int flags;
4414         unsigned int requestOpLock;
4415         unsigned int requestBatchOpLock;
4416         unsigned int mustBeDir;
4417     unsigned int extendedRespRequired;
4418         int realDirFlag;
4419         unsigned int desiredAccess;
4420 #ifdef DEBUG_VERBOSE    
4421     unsigned int allocSize;
4422     unsigned int shareAccess;
4423 #endif
4424         unsigned int extAttributes;
4425         unsigned int createDisp;
4426 #ifdef DEBUG_VERBOSE
4427     unsigned int sdLen;
4428 #endif
4429         unsigned int createOptions;
4430         int initialModeBits;
4431         unsigned short baseFid;
4432         smb_fid_t *baseFidp;
4433         smb_fid_t *fidp;
4434         cm_scache_t *baseDirp;
4435         unsigned short openAction;
4436         int parmSlot;
4437         long fidflags;
4438         FILETIME ft;
4439         char *tidPathp;
4440         BOOL foundscp;
4441         int parmOffset, dataOffset;
4442         char *parmp;
4443         ULONG *lparmp;
4444         char *outData;
4445         cm_req_t req;
4446
4447         cm_InitReq(&req);
4448
4449         foundscp = FALSE;
4450         scp = NULL;
4451
4452         parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
4453                         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
4454         parmp = inp->data + parmOffset;
4455         lparmp = (ULONG *) parmp;
4456
4457         flags = lparmp[0];
4458         requestOpLock = flags & 0x02;
4459         requestBatchOpLock = flags & 0x04;
4460         mustBeDir = flags & 0x08;
4461     extendedRespRequired = flags & 0x10;
4462
4463         /*
4464          * Why all of a sudden 32-bit FID?
4465          * We will reject all bits higher than 16.
4466          */
4467         if (lparmp[1] & 0xFFFF0000)
4468                 return CM_ERROR_INVAL;
4469         baseFid = (unsigned short)lparmp[1];
4470         desiredAccess = lparmp[2];
4471 #ifdef DEBUG_VERBOSE
4472     allocSize = lparmp[3];
4473 #endif /* DEBUG_VERSOSE */
4474         extAttributes = lparmp[5];
4475 #ifdef DEBUG_VEROSE
4476     shareAccess = lparmp[6];
4477 #endif
4478         createDisp = lparmp[7];
4479         createOptions = lparmp[8];
4480 #ifdef DEBUG_VERBOSE
4481     sdLen = lparmp[9];
4482 #endif
4483         nameLength = lparmp[11];
4484
4485 #ifdef DEBUG_VERBOSE
4486         osi_Log4(smb_logp,"NTTransCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
4487         osi_Log2(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
4488         osi_Log1(smb_logp,"... flags[%x]",flags);
4489 #endif
4490
4491         /* mustBeDir is never set; createOptions directory bit seems to be
4492          * more important
4493          */
4494         if (createOptions & 1)
4495                 realDirFlag = 1;
4496         else if (createOptions & 0x40)
4497                 realDirFlag = 0;
4498         else
4499                 realDirFlag = -1;
4500
4501         /*
4502          * compute initial mode bits based on read-only flag in
4503          * extended attributes
4504          */
4505         initialModeBits = 0666;
4506         if (extAttributes & 1) initialModeBits &= ~0222;
4507
4508         pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
4509         /* Sometimes path is not null-terminated, so we make a copy. */
4510         realPathp = malloc(nameLength+1);
4511         memcpy(realPathp, pathp, nameLength);
4512         realPathp[nameLength] = 0;
4513
4514         spacep = cm_GetSpace();
4515         smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
4516
4517         /*
4518          * Nothing here to handle SMB_IOCTL_FILENAME.
4519          * Will add it if necessary.
4520          */
4521
4522 #ifdef DEBUG_VERBOSE
4523         {
4524                 char *hexp, *asciip;
4525                 asciip = (lastNamep? lastNamep : realPathp);
4526                 hexp = osi_HexifyString( asciip );
4527                 DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
4528                 free(hexp);
4529         }
4530 #endif
4531
4532         userp = smb_GetUser(vcp, inp);
4533     if (!userp) {
4534         osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
4535         free(realPathp);
4536         return CM_ERROR_INVAL;
4537     }
4538
4539         if (baseFid == 0) {
4540                 baseDirp = cm_rootSCachep;
4541                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4542         }
4543         else {
4544         baseFidp = smb_FindFID(vcp, baseFid, 0);
4545         if (!baseFidp) {
4546                 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
4547                 free(realPathp);
4548                 cm_ReleaseUser(userp);
4549                 return CM_ERROR_INVAL;
4550         }
4551                 baseDirp = baseFidp->scp;
4552                 tidPathp = NULL;
4553         }
4554
4555     /* compute open mode */
4556     fidflags = 0;
4557     if (desiredAccess & DELETE)
4558         fidflags |= SMB_FID_OPENDELETE;
4559     if (desiredAccess & AFS_ACCESS_READ)
4560         fidflags |= SMB_FID_OPENREAD;
4561     if (desiredAccess & AFS_ACCESS_WRITE)
4562         fidflags |= SMB_FID_OPENWRITE;
4563
4564         dscp = NULL;
4565         code = 0;
4566     if (createDisp == 2 || createDisp == 4 || createDisp == 5) {
4567         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4568                         userp, tidPathp, &req, &dscp);
4569         if (code == 0) {
4570             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
4571                              userp, &req, &scp);
4572             if (code == CM_ERROR_NOSUCHFILE) {
4573                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
4574                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
4575                 if (code == 0 && realDirFlag == 1) {
4576                                         cm_ReleaseSCache(scp);
4577                     cm_ReleaseSCache(dscp);
4578                     cm_ReleaseUser(userp);
4579                     free(realPathp);
4580                     return CM_ERROR_EXISTS;
4581                 }
4582             }
4583         } else 
4584             dscp = NULL;
4585     } else {
4586         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4587                         userp, tidPathp, &req, &scp);
4588     }
4589
4590         if (code == 0) foundscp = TRUE;
4591         if (code != 0
4592             || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
4593                 /* look up parent directory */
4594         if ( !dscp ) {
4595             code = cm_NameI(baseDirp, spacep->data,
4596                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4597                              userp, tidPathp, &req, &dscp);
4598         } else
4599             code = 0;
4600         
4601         cm_FreeSpace(spacep);
4602
4603                 if (baseFid != 0) {
4604            smb_ReleaseFID(baseFidp);
4605            baseFidp = 0;
4606         }
4607
4608                 if (code) {
4609                         cm_ReleaseUser(userp);
4610                         free(realPathp);
4611                         return code;
4612                 }
4613
4614                 if (!lastNamep) lastNamep = realPathp;
4615                 else lastNamep++;
4616
4617         if (!smb_IsLegalFilename(lastNamep))
4618             return CM_ERROR_BADNTFILENAME;
4619
4620                 if (!foundscp) {
4621             if (createDisp == 2 || createDisp == 4)
4622                 code = cm_Lookup(dscp, lastNamep,
4623                                  CM_FLAG_FOLLOW, userp, &req, &scp);
4624             else
4625                 code = cm_Lookup(dscp, lastNamep,
4626                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4627                                  userp, &req, &scp);
4628                         if (code && code != CM_ERROR_NOSUCHFILE) {
4629                                 cm_ReleaseSCache(dscp);
4630                                 cm_ReleaseUser(userp);
4631                                 free(realPathp);
4632                                 return code;
4633                         }
4634                 }
4635         }
4636         else {
4637                 if (baseFid != 0) {
4638             smb_ReleaseFID(baseFidp);
4639             baseFidp = 0;
4640         }
4641                 cm_FreeSpace(spacep);
4642         }
4643
4644         /* if we get here, if code is 0, the file exists and is represented by
4645          * scp.  Otherwise, we have to create it.  The dir may be represented
4646          * by dscp, or we may have found the file directly.  If code is non-zero,
4647          * scp is NULL.
4648          */
4649         if (code == 0) {
4650                 code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
4651                                       &req);
4652                 if (code) {
4653                         if (dscp) cm_ReleaseSCache(dscp);
4654                         cm_ReleaseSCache(scp);
4655                         cm_ReleaseUser(userp);
4656                         free(realPathp);
4657                         return code;
4658                 }
4659
4660                 if (createDisp == 2) {
4661                         /* oops, file shouldn't be there */
4662                         if (dscp) cm_ReleaseSCache(dscp);
4663                         cm_ReleaseSCache(scp);
4664                         cm_ReleaseUser(userp);
4665                         free(realPathp);
4666                         return CM_ERROR_EXISTS;
4667                 }
4668
4669                 if (createDisp == 4
4670                     || createDisp == 5) {
4671                         setAttr.mask = CM_ATTRMASK_LENGTH;
4672                         setAttr.length.LowPart = 0;
4673                         setAttr.length.HighPart = 0;
4674                         code = cm_SetAttr(scp, &setAttr, userp, &req);
4675                         openAction = 3; /* truncated existing file */
4676                 }
4677                 else openAction = 1;    /* found existing file */
4678         }
4679         else if (createDisp == 1 || createDisp == 4) {
4680                 /* don't create if not found */
4681                 if (dscp) cm_ReleaseSCache(dscp);
4682                 cm_ReleaseUser(userp);
4683                 free(realPathp);
4684                 return CM_ERROR_NOSUCHFILE;
4685         }
4686         else if (realDirFlag == 0 || realDirFlag == -1) {
4687                 osi_assert(dscp != NULL);
4688                 osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
4689                  osi_LogSaveString(smb_logp, lastNamep));
4690                 openAction = 2;         /* created file */
4691                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4692                 setAttr.clientModTime = time(NULL);
4693                 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4694                                  &req);
4695                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4696                         smb_NotifyChange(FILE_ACTION_ADDED,
4697                                          FILE_NOTIFY_CHANGE_FILE_NAME,
4698                                          dscp, lastNamep, NULL, TRUE);
4699                 if (code == CM_ERROR_EXISTS && createDisp != 2) {
4700                         /* Not an exclusive create, and someone else tried
4701                          * creating it already, then we open it anyway.  We
4702                          * don't bother retrying after this, since if this next
4703                          * fails, that means that the file was deleted after we
4704                          * started this call.
4705                          */
4706                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4707                                          userp, &req, &scp);
4708                         if (code == 0) {
4709                                 if (createDisp == 5) {
4710                                         setAttr.mask = CM_ATTRMASK_LENGTH;
4711                                         setAttr.length.LowPart = 0;
4712                                         setAttr.length.HighPart = 0;
4713                                         code = cm_SetAttr(scp, &setAttr, userp,
4714                                                           &req);
4715                                 }
4716                         }       /* lookup succeeded */
4717                 }
4718         }
4719         else {
4720                 /* create directory */
4721                 osi_assert(dscp != NULL);
4722                 osi_Log1(smb_logp,
4723                                 "smb_ReceiveNTTranCreate creating directory %s",
4724                                 osi_LogSaveString(smb_logp, lastNamep));
4725                 openAction = 2;         /* created directory */
4726                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4727                 setAttr.clientModTime = time(NULL);
4728                 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
4729                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4730                         smb_NotifyChange(FILE_ACTION_ADDED,
4731                                          FILE_NOTIFY_CHANGE_DIR_NAME,
4732                                          dscp, lastNamep, NULL, TRUE);
4733                 if (code == 0
4734                     || (code == CM_ERROR_EXISTS && createDisp != 2)) {
4735                         /* Not an exclusive create, and someone else tried
4736                          * creating it already, then we open it anyway.  We
4737                          * don't bother retrying after this, since if this next
4738                          * fails, that means that the file was deleted after we
4739                          * started this call.
4740                          */
4741                         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4742                                          userp, &req, &scp);
4743                 }
4744         }
4745
4746         if (code) {
4747                 /* something went wrong creating or truncating the file */
4748                 if (scp) cm_ReleaseSCache(scp);
4749                 cm_ReleaseUser(userp);
4750                 free(realPathp);
4751                 return code;
4752         }
4753
4754         /* make sure we have file vs. dir right */
4755         if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
4756                 cm_ReleaseSCache(scp);
4757                 cm_ReleaseUser(userp);
4758                 free(realPathp);
4759                 return CM_ERROR_ISDIR;
4760         }
4761         if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
4762                 cm_ReleaseSCache(scp);
4763                 cm_ReleaseUser(userp);
4764                 free(realPathp);
4765                 return CM_ERROR_NOTDIR;
4766         }
4767
4768         /* open the file itself */
4769         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4770         osi_assert(fidp);
4771
4772         /* save a pointer to the vnode */
4773         fidp->scp = scp;
4774
4775         fidp->flags = fidflags;
4776
4777     /* save parent dir and pathname for deletion or change notification */
4778     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
4779         fidp->flags |= SMB_FID_NTOPEN;
4780         fidp->NTopen_dscp = dscp;
4781         cm_HoldSCache(dscp);
4782         fidp->NTopen_pathp = strdup(lastNamep);
4783     }
4784         fidp->NTopen_wholepathp = realPathp;
4785
4786         /* we don't need this any longer */
4787         if (dscp) cm_ReleaseSCache(dscp);
4788
4789         cm_Open(scp, 0, userp);
4790
4791         /* set inp->fid so that later read calls in same msg can find fid */
4792         inp->fid = fidp->fid;
4793
4794     /* check whether we are required to send an extended response */
4795     if (!extendedRespRequired) {
4796         /* out parms */
4797         parmOffset = 8*4 + 39;
4798         parmOffset += 1;        /* pad to 4 */
4799         dataOffset = parmOffset + 70;
4800
4801         parmSlot = 1;
4802         outp->oddByte = 1;
4803         /* Total Parameter Count */
4804         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
4805         /* Total Data Count */
4806         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4807         /* Parameter Count */
4808         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
4809         /* Parameter Offset */
4810         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4811         /* Parameter Displacement */
4812         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4813         /* Data Count */
4814         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4815         /* Data Offset */
4816         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4817         /* Data Displacement */
4818         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4819         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
4820         smb_SetSMBDataLength(outp, 70);
4821
4822         lock_ObtainMutex(&scp->mx);
4823         outData = smb_GetSMBData(outp, NULL);
4824         outData++;                      /* round to get to parmOffset */
4825         *outData = 0; outData++;        /* oplock */
4826         *outData = 0; outData++;        /* reserved */
4827         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4828         *((ULONG *)outData) = openAction; outData += 4;
4829         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
4830         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4831         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
4832         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
4833         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
4834         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
4835         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4836         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4837         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4838         *((USHORT *)outData) = 0; outData += 2; /* filetype */
4839         *((USHORT *)outData) = 0; outData += 2; /* dev state */
4840         *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4841         outData += 2;   /* is a dir? */
4842         lock_ReleaseMutex(&scp->mx);
4843     } else {
4844         /* out parms */
4845         parmOffset = 8*4 + 39;
4846         parmOffset += 1;        /* pad to 4 */
4847         dataOffset = parmOffset + 104;
4848         
4849         parmSlot = 1;
4850         outp->oddByte = 1;
4851         /* Total Parameter Count */
4852         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4853         /* Total Data Count */
4854         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4855         /* Parameter Count */
4856         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
4857         /* Parameter Offset */
4858         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
4859         /* Parameter Displacement */
4860         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4861         /* Data Count */
4862         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4863         /* Data Offset */
4864         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
4865         /* Data Displacement */
4866         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
4867         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
4868         smb_SetSMBDataLength(outp, 105);
4869         
4870         lock_ObtainMutex(&scp->mx);
4871         outData = smb_GetSMBData(outp, NULL);
4872         outData++;                      /* round to get to parmOffset */
4873         *outData = 0; outData++;        /* oplock */
4874         *outData = 1; outData++;        /* response type */
4875         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
4876         *((ULONG *)outData) = openAction; outData += 4;
4877         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
4878         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4879         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
4880         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
4881         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
4882         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
4883         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
4884         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
4885         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
4886         *((USHORT *)outData) = 0; outData += 2; /* filetype */
4887         *((USHORT *)outData) = 0; outData += 2; /* dev state */
4888         *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
4889         outData += 1;   /* is a dir? */
4890         memset(outData,0,24); outData += 24; /* Volume ID and file ID */
4891         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
4892         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
4893         lock_ReleaseMutex(&scp->mx);
4894     }
4895
4896         osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
4897
4898         smb_ReleaseFID(fidp);
4899
4900         cm_ReleaseUser(userp);
4901
4902         /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
4903         /* leave scp held since we put it in fidp->scp */
4904         return 0;
4905 }
4906
4907 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
4908         smb_packet_t *outp)
4909 {
4910         smb_packet_t *savedPacketp;
4911         ULONG filter; USHORT fid, watchtree;
4912         smb_fid_t *fidp;
4913         cm_scache_t *scp;
4914         
4915         filter = smb_GetSMBParm(inp, 19)
4916                         | (smb_GetSMBParm(inp, 20) << 16);
4917         fid = smb_GetSMBParm(inp, 21);
4918         watchtree = smb_GetSMBParm(inp, 22) && 0xffff;  /* TODO: should this be 0xff ? */
4919
4920     fidp = smb_FindFID(vcp, fid, 0);
4921     if (!fidp) {
4922         osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
4923         return CM_ERROR_BADFD;
4924     }
4925
4926         savedPacketp = smb_CopyPacket(inp);
4927     smb_HoldVC(vcp);
4928         savedPacketp->vcp = vcp;
4929         lock_ObtainMutex(&smb_Dir_Watch_Lock);
4930         savedPacketp->nextp = smb_Directory_Watches;
4931         smb_Directory_Watches = savedPacketp;
4932         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
4933
4934     osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
4935              filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
4936
4937     scp = fidp->scp;
4938     lock_ObtainMutex(&scp->mx);
4939     if (watchtree)
4940         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
4941     else
4942         scp->flags |= CM_SCACHEFLAG_WATCHED;
4943     lock_ReleaseMutex(&scp->mx);
4944     smb_ReleaseFID(fidp);
4945
4946         outp->flags |= SMB_PACKETFLAG_NOSEND;
4947         return 0;
4948 }
4949
4950 unsigned char nullSecurityDesc[36] = {
4951         0x01,                           /* security descriptor revision */
4952         0x00,                           /* reserved, should be zero */
4953         0x00, 0x80,                     /* security descriptor control;
4954                                          * 0x8000 : self-relative format */
4955         0x14, 0x00, 0x00, 0x00,         /* offset of owner SID */
4956         0x1c, 0x00, 0x00, 0x00,         /* offset of group SID */
4957         0x00, 0x00, 0x00, 0x00,         /* offset of DACL would go here */
4958         0x00, 0x00, 0x00, 0x00,         /* offset of SACL would go here */
4959         0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
4960                                         /* "null SID" owner SID */
4961         0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
4962                                         /* "null SID" group SID */
4963 };
4964
4965 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4966 {
4967         int parmOffset, parmCount, dataOffset, dataCount;
4968         int parmSlot;
4969         int maxData;
4970         char *outData;
4971         char *parmp;
4972         USHORT *sparmp;
4973         ULONG *lparmp;
4974         USHORT fid;
4975         ULONG securityInformation;
4976
4977         parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
4978                         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
4979         parmp = inp->data + parmOffset;
4980         sparmp = (USHORT *) parmp;
4981         lparmp = (ULONG *) parmp;
4982
4983         fid = sparmp[0];
4984         securityInformation = lparmp[1];
4985
4986         maxData = smb_GetSMBOffsetParm(inp, 7, 1)
4987                         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
4988
4989         if (maxData < 36)
4990                 dataCount = 0;
4991         else
4992                 dataCount = 36;
4993
4994         /* out parms */
4995         parmOffset = 8*4 + 39;
4996         parmOffset += 1;        /* pad to 4 */
4997         parmCount = 4;
4998         dataOffset = parmOffset + parmCount;
4999
5000         parmSlot = 1;
5001         outp->oddByte = 1;
5002         /* Total Parameter Count */
5003         smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
5004         /* Total Data Count */
5005         smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
5006         /* Parameter Count */
5007         smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
5008         /* Parameter Offset */
5009         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
5010         /* Parameter Displacement */
5011         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5012         /* Data Count */
5013         smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
5014         /* Data Offset */
5015         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
5016         /* Data Displacement */
5017         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
5018         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
5019         smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
5020
5021         outData = smb_GetSMBData(outp, NULL);
5022         outData++;                      /* round to get to parmOffset */
5023         *((ULONG *)outData) = 36; outData += 4; /* length */
5024
5025         if (maxData >= 36) {
5026                 memcpy(outData, nullSecurityDesc, 36);
5027                 outData += 36;
5028                 return 0;
5029         } else
5030                 return CM_ERROR_BUFFERTOOSMALL;
5031 }
5032
5033 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5034 {
5035         unsigned short function;
5036
5037         function = smb_GetSMBParm(inp, 18);
5038
5039         osi_Log1(smb_logp, "SMB NT Transact function %d", function);
5040
5041         /* We can handle long names */
5042         if (vcp->flags & SMB_VCFLAG_USENT)
5043                 ((smb_t *)outp)->flg2 |= 0x40;  /* IS_LONG_NAME */
5044         
5045         switch (function) {
5046
5047                 case 6: return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
5048
5049                 case 4: return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
5050
5051                 case 1: return smb_ReceiveNTTranCreate(vcp, inp, outp);
5052
5053                 default: return CM_ERROR_INVAL;
5054         }
5055 }
5056
5057 /*
5058  * smb_NotifyChange -- find relevant change notification messages and
5059  *                     reply to them
5060  *
5061  * If we don't know the file name (i.e. a callback break), filename is
5062  * NULL, and we return a zero-length list.
5063  */
5064 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
5065         cm_scache_t *dscp, char *filename, char *otherFilename,
5066         BOOL isDirectParent)
5067 {
5068         smb_packet_t *watch, *lastWatch, *nextWatch;
5069         ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
5070         char *outData, *oldOutData;
5071         ULONG filter;
5072         USHORT fid, wtree;
5073         ULONG maxLen;
5074         BOOL twoEntries = FALSE;
5075         ULONG otherNameLen, oldParmCount = 0;
5076         DWORD otherAction;
5077         smb_vc_t *vcp;
5078         smb_fid_t *fidp;
5079
5080         /* Get ready for rename within directory */
5081         if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
5082                 twoEntries = TRUE;
5083                 otherAction = FILE_ACTION_RENAMED_NEW_NAME;
5084         }
5085
5086     osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
5087               osi_LogSaveString(smb_logp,filename),dscp);
5088
5089         lock_ObtainMutex(&smb_Dir_Watch_Lock);
5090         watch = smb_Directory_Watches;
5091         while (watch) {
5092                 filter = smb_GetSMBParm(watch, 19)
5093                                 | (smb_GetSMBParm(watch, 20) << 16);
5094                 fid = smb_GetSMBParm(watch, 21);
5095                 wtree = smb_GetSMBParm(watch, 22) & 0xffff;  /* TODO: should this be 0xff ? */
5096                 maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
5097                                 | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
5098                 vcp = watch->vcp;
5099
5100                 /*
5101                  * Strange hack - bug in NT Client and NT Server that we
5102                  * must emulate?
5103                  */
5104                 if (filter == 3 && wtree)
5105                         filter = 0x17;
5106
5107                 fidp = smb_FindFID(vcp, fid, 0);
5108         if (!fidp) {
5109             osi_Log1(smb_logp," no fidp for fid[%d]",fid);
5110                 lastWatch = watch;
5111                 watch = watch->nextp;
5112                 continue;
5113         }
5114                 if (fidp->scp != dscp
5115                     || (filter & notifyFilter) == 0
5116                     || (!isDirectParent && !wtree)) {
5117             osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
5118             smb_ReleaseFID(fidp);
5119                         lastWatch = watch;
5120                         watch = watch->nextp;
5121                         continue;
5122                 }
5123                 smb_ReleaseFID(fidp);
5124
5125                 osi_Log4(smb_logp,
5126                          "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
5127                          fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
5128
5129                 nextWatch = watch->nextp;
5130                 if (watch == smb_Directory_Watches)
5131                         smb_Directory_Watches = nextWatch;
5132                 else
5133                         lastWatch->nextp = nextWatch;
5134
5135                 /* Turn off WATCHED flag in dscp */
5136                 lock_ObtainMutex(&dscp->mx);
5137                 if (wtree)
5138                         dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
5139                 else
5140                         dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
5141                 lock_ReleaseMutex(&dscp->mx);
5142
5143                 /* Convert to response packet */
5144                 ((smb_t *) watch)->reb = 0x80;
5145                 ((smb_t *) watch)->wct = 0;
5146
5147                 /* out parms */
5148                 if (filename == NULL)
5149                         parmCount = 0;
5150                 else {
5151                         nameLen = strlen(filename);
5152                         parmCount = 3*4 + nameLen*2;
5153                         parmCount = (parmCount + 3) & ~3;       /* pad to 4 */
5154                         if (twoEntries) {
5155                                 otherNameLen = strlen(otherFilename);
5156                                 oldParmCount = parmCount;
5157                                 parmCount += 3*4 + otherNameLen*2;
5158                                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
5159                         }
5160                         if (maxLen < parmCount)
5161                                 parmCount = 0;  /* not enough room */
5162                 }
5163                 parmOffset = 8*4 + 39;
5164                 parmOffset += 1;                        /* pad to 4 */
5165                 dataOffset = parmOffset + parmCount;
5166
5167                 parmSlot = 1;
5168                 watch->oddByte = 1;
5169                 /* Total Parameter Count */
5170                 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
5171                 /* Total Data Count */
5172                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5173                 /* Parameter Count */
5174                 smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
5175                 /* Parameter Offset */
5176                 smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
5177                 /* Parameter Displacement */
5178                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5179                 /* Data Count */
5180                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5181                 /* Data Offset */
5182                 smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
5183                 /* Data Displacement */
5184                 smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
5185                 smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
5186                 smb_SetSMBDataLength(watch, parmCount + 1);
5187
5188                 if (parmCount != 0) {
5189                         outData = smb_GetSMBData(watch, NULL);
5190                         outData++;      /* round to get to parmOffset */
5191                         oldOutData = outData;
5192                         *((DWORD *)outData) = oldParmCount; outData += 4;
5193                                         /* Next Entry Offset */
5194                         *((DWORD *)outData) = action; outData += 4;
5195                                         /* Action */
5196                         *((DWORD *)outData) = nameLen*2; outData += 4;
5197                                         /* File Name Length */
5198                         mbstowcs((WCHAR *)outData, filename, nameLen);
5199                                         /* File Name */
5200                         if (twoEntries) {
5201                                 outData = oldOutData + oldParmCount;
5202                                 *((DWORD *)outData) = 0; outData += 4;
5203                                         /* Next Entry Offset */
5204                                 *((DWORD *)outData) = otherAction; outData += 4;
5205                                         /* Action */
5206                                 *((DWORD *)outData) = otherNameLen*2;
5207                                 outData += 4;   /* File Name Length */
5208                                 mbstowcs((WCHAR *)outData, otherFilename,
5209                                          otherNameLen); /* File Name */
5210                         }
5211                 }
5212
5213                 /*
5214                  * If filename is null, we don't know the cause of the
5215                  * change notification.  We return zero data (see above),
5216                  * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
5217                  * (= 0x010C).  We set the error code here by hand, without
5218                  * modifying wct and bcc.
5219                  */
5220                 if (filename == NULL) {
5221                         ((smb_t *) watch)->rcls = 0x0C;
5222                         ((smb_t *) watch)->reh = 0x01;
5223                         ((smb_t *) watch)->errLow = 0;
5224                         ((smb_t *) watch)->errHigh = 0;
5225                         /* Set NT Status codes flag */
5226                         ((smb_t *) watch)->flg2 |= 0x4000;
5227                 }
5228
5229                 smb_SendPacket(vcp, watch);
5230         smb_ReleaseVC(vcp);
5231                 smb_FreePacket(watch);
5232                 watch = nextWatch;
5233         }
5234         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5235 }
5236
5237 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5238 {
5239         unsigned char *replyWctp;
5240         smb_packet_t *watch, *lastWatch;
5241         USHORT fid, watchtree;
5242         smb_fid_t *fidp;
5243         cm_scache_t *scp;
5244
5245         osi_Log0(smb_logp, "SMB3 receive NT cancel");
5246
5247         lock_ObtainMutex(&smb_Dir_Watch_Lock);
5248         watch = smb_Directory_Watches;
5249         while (watch) {
5250                 if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
5251                     && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
5252                     && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
5253                     && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
5254                         if (watch == smb_Directory_Watches)
5255                                 smb_Directory_Watches = watch->nextp;
5256                         else
5257                                 lastWatch->nextp = watch->nextp;
5258                         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5259
5260                         /* Turn off WATCHED flag in scp */
5261                         fid = smb_GetSMBParm(watch, 21);
5262                         watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
5263
5264             if (vcp != watch->vcp)
5265                 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x", 
5266                          vcp, watch->vcp);
5267
5268                         fidp = smb_FindFID(vcp, fid, 0);
5269             if (fidp) {
5270                 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s", 
5271                          fid, watchtree,
5272                          osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
5273
5274                 scp = fidp->scp;
5275                 lock_ObtainMutex(&scp->mx);
5276                 if (watchtree)
5277                     scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
5278                 else
5279                     scp->flags &= ~CM_SCACHEFLAG_WATCHED;
5280                 lock_ReleaseMutex(&scp->mx);
5281                 smb_ReleaseFID(fidp);
5282             } else {
5283                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
5284             }
5285
5286                         /* assume STATUS32; return 0xC0000120 (CANCELED) */
5287                         replyWctp = watch->wctp;
5288                         *replyWctp++ = 0;
5289                         *replyWctp++ = 0;
5290                         *replyWctp++ = 0;
5291                         ((smb_t *)watch)->rcls = 0x20;
5292                         ((smb_t *)watch)->reh = 0x1;
5293                         ((smb_t *)watch)->errLow = 0;
5294                         ((smb_t *)watch)->errHigh = 0xC0;
5295                         ((smb_t *)watch)->flg2 |= 0x4000;
5296                         smb_SendPacket(vcp, watch);
5297             if (watch->vcp)
5298                 smb_ReleaseVC(watch->vcp);
5299                         smb_FreePacket(watch);
5300                         return 0;
5301                 }
5302                 lastWatch = watch;
5303                 watch = watch->nextp;
5304         }
5305         lock_ReleaseMutex(&smb_Dir_Watch_Lock);
5306
5307         return 0;
5308 }
5309
5310 void smb3_Init()
5311 {
5312         lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
5313 }
5314
5315 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
5316 {
5317     /*int newUid;*/
5318     smb_username_t *unp;
5319
5320     unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
5321     if (!unp->userp) {
5322         lock_ObtainMutex(&unp->mx);
5323         unp->userp = cm_NewUser();
5324         lock_ReleaseMutex(&unp->mx);
5325                 osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
5326         osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
5327     }  else     {
5328         osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
5329         osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);
5330         }
5331     return unp->userp;
5332 }
5333