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