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