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