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