f03270c3d4bbb3f89bb640e7b3e65d5e80de441c
[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 #include <osi.h>
25
26 #include "afsd.h"
27
28 #include "smb.h"
29
30 extern osi_hyper_t hzero;
31
32 smb_packet_t *smb_Directory_Watches = NULL;
33 osi_mutex_t smb_Dir_Watch_Lock;
34
35 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
36
37 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
38
39 /* protected by the smb_globalLock */
40 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
41
42 /* retrieve a held reference to a user structure corresponding to an incoming
43  * request */
44 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
45 {
46     smb_user_t *uidp;
47     cm_user_t *up = NULL;
48         
49     uidp = smb_FindUID(vcp, inp->uid, 0);
50     if (!uidp) return NULL;
51         
52     lock_ObtainMutex(&uidp->mx);
53     if (uidp->unp) {
54         up = uidp->unp->userp;
55         cm_HoldUser(up);
56     }
57     lock_ReleaseMutex(&uidp->mx);
58
59     smb_ReleaseUID(uidp);
60
61     return up;
62 }
63
64 /*
65  * Return extended attributes.
66  * Right now, we aren't using any of the "new" bits, so this looks exactly
67  * like smb_Attributes() (see smb.c).
68  */
69 unsigned long smb_ExtAttributes(cm_scache_t *scp)
70 {
71     unsigned long attrs;
72
73     if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
74         scp->fileType == CM_SCACHETYPE_MOUNTPOINT) 
75     {
76         attrs = SMB_ATTR_DIRECTORY;
77 #ifdef SPECIAL_FOLDERS
78         attrs |= SMB_ATTR_SYSTEM;               /* FILE_ATTRIBUTE_SYSTEM */
79 #endif /* SPECIAL_FOLDERS */
80     } else
81         attrs = 0;
82     /*
83      * We used to mark a file RO if it was in an RO volume, but that
84      * turns out to be impolitic in NT.  See defect 10007.
85      */
86 #ifdef notdef
87     if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
88 #endif
89         if ((scp->unixModeBits & 0222) == 0)
90             attrs |= SMB_ATTR_READONLY;         /* Read-only */
91
92     if (attrs == 0)
93         attrs = SMB_ATTR_NORMAL;                /* FILE_ATTRIBUTE_NORMAL */
94
95     return attrs;
96 }
97
98 int smb_V3IsStarMask(char *maskp)
99 {
100     char tc;
101
102     while (tc = *maskp++)
103         if (tc == '?' || tc == '*') 
104             return 1;
105     return 0;
106 }
107
108 unsigned char *smb_ParseString(unsigned char *inp, char **chainpp)
109 {
110     if (chainpp) {
111         /* skip over null-terminated string */
112         *chainpp = inp + strlen(inp) + 1;
113     }
114     return inp;
115 }   
116
117 /*DEBUG do not checkin*/
118 void OutputDebugF(char * format, ...) {
119     va_list args;
120     int len;
121     char * buffer;
122
123     va_start( args, format );
124     len = _vscprintf( format, args ) // _vscprintf doesn't count
125                                + 3; // terminating '\0' + '\n'
126     buffer = malloc( len * sizeof(char) );
127     vsprintf( buffer, format, args );
128     osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buffer));
129     strcat(buffer, "\n");
130     OutputDebugString(buffer);
131     free( buffer );
132 }
133
134 void OutputDebugHexDump(unsigned char * buffer, int len) {
135     int i,j,k;
136     char buf[256];
137     static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
138
139     OutputDebugF("Hexdump length [%d]",len);
140
141     for (i=0;i<len;i++) {
142         if(!(i%16)) {
143             if(i) {
144                 osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
145                 strcat(buf,"\n");
146                 OutputDebugString(buf);
147             }
148             sprintf(buf,"%5x",i);
149             memset(buf+5,' ',80);
150             buf[85] = 0;
151         }
152
153         j = (i%16);
154         j = j*3 + 7 + ((j>7)?1:0);
155         k = buffer[i];
156
157         buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
158
159         j = (i%16);
160         j = j + 56 + ((j>7)?1:0);
161
162         buf[j] = (k>32 && k<127)?k:'.';
163     }    
164     if(i) {
165         osi_Log0(smb_logp, osi_LogSaveString(smb_logp, buf));
166         strcat(buf,"\n");
167         OutputDebugString(buf);
168     }   
169 }
170 /**/
171
172 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
173 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
174     SECURITY_STATUS status, istatus;
175     CredHandle creds = {0,0};
176     TimeStamp expiry;
177     SecBufferDesc secOut;
178     SecBuffer secTok;
179     CtxtHandle ctx;
180     ULONG flags;
181
182     *secBlob = NULL;
183     *secBlobLength = 0;
184
185     OutputDebugF("Negotiating Extended Security");
186
187     status = AcquireCredentialsHandle( NULL,
188                                        SMB_EXT_SEC_PACKAGE_NAME,
189                                        SECPKG_CRED_INBOUND,
190                                        NULL,
191                                        NULL,
192                                        NULL,
193                                        NULL,
194                                        &creds,
195                                        &expiry);
196
197     if (status != SEC_E_OK) {       
198         /* Really bad. We return an empty security blob */
199         OutputDebugF("AcquireCredentialsHandle failed with %lX", status);
200         goto nes_0;
201     }
202
203     secOut.cBuffers = 1;
204     secOut.pBuffers = &secTok;
205     secOut.ulVersion = SECBUFFER_VERSION;
206
207     secTok.BufferType = SECBUFFER_TOKEN;
208     secTok.cbBuffer = 0;
209     secTok.pvBuffer = NULL;
210
211     ctx.dwLower = ctx.dwUpper = 0;
212
213     status = AcceptSecurityContext( &creds,
214                                     NULL,
215                                     NULL,
216                                     ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
217                                     SECURITY_NETWORK_DREP,
218                                     &ctx,
219                                     &secOut,
220                                     &flags,
221                                     &expiry
222                                     );
223
224     if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
225         OutputDebugF("Completing token...");
226         istatus = CompleteAuthToken(&ctx, &secOut);
227         if ( istatus != SEC_E_OK )
228             OutputDebugF("Token completion failed: %x", istatus);
229     }
230
231     if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
232         if (secTok.pvBuffer) {
233             *secBlobLength = secTok.cbBuffer;
234             *secBlob = malloc( secTok.cbBuffer );
235             memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
236         }
237     } else {
238         if ( status != SEC_E_OK )
239             OutputDebugF("AcceptSecurityContext status != CONTINUE  %lX", status);
240     }
241
242     /* Discard partial security context */
243     DeleteSecurityContext(&ctx);
244
245     if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
246
247     /* Discard credentials handle.  We'll reacquire one when we get the session setup X */
248     FreeCredentialsHandle(&creds);
249
250   nes_0:
251     return;
252 }
253
254 struct smb_ext_context {
255     CredHandle creds;
256     CtxtHandle ctx;
257     int partialTokenLen;
258     void * partialToken;
259 };      
260
261 long smb_AuthenticateUserExt(smb_vc_t * vcp, char * usern, char * secBlobIn, int secBlobInLength, char ** secBlobOut, int * secBlobOutLength) {
262     SECURITY_STATUS status, istatus;
263     CredHandle creds;
264     TimeStamp expiry;
265     long code = 0;
266     SecBufferDesc secBufIn;
267     SecBuffer secTokIn;
268     SecBufferDesc secBufOut;
269     SecBuffer secTokOut;
270     CtxtHandle ctx;
271     struct smb_ext_context * secCtx = NULL;
272     struct smb_ext_context * newSecCtx = NULL;
273     void * assembledBlob = NULL;
274     int assembledBlobLength = 0;
275     ULONG flags;
276
277     OutputDebugF("In smb_AuthenticateUserExt");
278
279     *secBlobOut = NULL;
280     *secBlobOutLength = 0;
281
282     if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
283         secCtx = vcp->secCtx;
284         lock_ObtainMutex(&vcp->mx);
285         vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
286         vcp->secCtx = NULL;
287         lock_ReleaseMutex(&vcp->mx);
288     }
289
290     if (secBlobIn) {
291         OutputDebugF("Received incoming token:");
292         OutputDebugHexDump(secBlobIn,secBlobInLength);
293     }
294     
295     if (secCtx) {
296         OutputDebugF("Continuing with existing context.");              
297         creds = secCtx->creds;
298         ctx = secCtx->ctx;
299
300         if (secCtx->partialToken) {
301             assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
302             assembledBlob = malloc(assembledBlobLength);
303             memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
304             memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
305         }
306     } else {
307         status = AcquireCredentialsHandle( 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( &creds,
349                                     ((secCtx)?&ctx:NULL),
350                                     &secBufIn,
351                                     ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
352                                     SECURITY_NETWORK_DREP,
353                                     &ctx,
354                                     &secBufOut,
355                                     &flags,
356                                     &expiry
357                                     );
358
359     if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
360         OutputDebugF("Completing token...");
361         istatus = CompleteAuthToken(&ctx, &secBufOut);
362         if ( istatus != SEC_E_OK )
363             OutputDebugF("Token completion failed: %lX", istatus);
364     }
365
366     if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
367         OutputDebugF("Continue needed");
368
369         newSecCtx = malloc(sizeof(*newSecCtx));
370
371         newSecCtx->creds = creds;
372         newSecCtx->ctx = ctx;
373         newSecCtx->partialToken = NULL;
374         newSecCtx->partialTokenLen = 0;
375
376         lock_ObtainMutex( &vcp->mx );
377         vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
378         vcp->secCtx = newSecCtx;
379         lock_ReleaseMutex( &vcp->mx );
380
381         code = CM_ERROR_GSSCONTINUE;
382     }
383
384     if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK || 
385           status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) && 
386          secTokOut.pvBuffer) {
387         OutputDebugF("Need to send token back to client");
388
389         *secBlobOutLength = secTokOut.cbBuffer;
390         *secBlobOut = malloc(secTokOut.cbBuffer);
391         memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
392
393         OutputDebugF("Outgoing token:");
394         OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
395     } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
396         OutputDebugF("Incomplete message");
397
398         newSecCtx = malloc(sizeof(*newSecCtx));
399
400         newSecCtx->creds = creds;
401         newSecCtx->ctx = ctx;
402         newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
403         memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
404         newSecCtx->partialTokenLen = secTokOut.cbBuffer;
405
406         lock_ObtainMutex( &vcp->mx );
407         vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
408         vcp->secCtx = newSecCtx;
409         lock_ReleaseMutex( &vcp->mx );
410
411         code = CM_ERROR_GSSCONTINUE;
412     }
413
414     if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
415         /* woo hoo! */
416         SecPkgContext_Names names;
417
418         OutputDebugF("Authentication completed");
419         OutputDebugF("Returned flags : [%lX]", flags);
420
421         if (!QueryContextAttributes(&ctx, SECPKG_ATTR_NAMES, &names)) {
422             OutputDebugF("Received name [%s]", names.sUserName);
423             strcpy(usern, names.sUserName);
424             strlwr(usern); /* in tandem with smb_GetNormalizedUsername */
425             FreeContextBuffer(names.sUserName);
426         } else {
427             /* Force the user to retry if the context is invalid */
428             OutputDebugF("QueryContextAttributes Names failed [%x]", GetLastError());
429             code = CM_ERROR_BADPASSWORD; 
430         }
431     } else if (!code) {
432         switch ( status ) {
433         case SEC_E_INVALID_TOKEN:
434             OutputDebugF("Returning bad password :: INVALID_TOKEN");
435             break;
436         case SEC_E_INVALID_HANDLE:
437             OutputDebugF("Returning bad password :: INVALID_HANDLE");
438             break;
439         case SEC_E_LOGON_DENIED:
440             OutputDebugF("Returning bad password :: LOGON_DENIED");
441             break;
442         case SEC_E_UNKNOWN_CREDENTIALS:
443             OutputDebugF("Returning bad password :: UNKNOWN_CREDENTIALS");
444             break;
445         case SEC_E_NO_CREDENTIALS:
446             OutputDebugF("Returning bad password :: NO_CREDENTIALS");
447             break;
448         case SEC_E_CONTEXT_EXPIRED:
449             OutputDebugF("Returning bad password :: CONTEXT_EXPIRED");
450             break;
451         case SEC_E_INCOMPLETE_CREDENTIALS:
452             OutputDebugF("Returning bad password :: INCOMPLETE_CREDENTIALS");
453             break;
454         case SEC_E_WRONG_PRINCIPAL:
455             OutputDebugF("Returning bad password :: WRONG_PRINCIPAL");
456             break;
457         case SEC_E_TIME_SKEW:
458             OutputDebugF("Returning bad password :: TIME_SKEW");
459             break;
460         default:
461             OutputDebugF("Returning bad password :: Status == %lX", status);
462         }
463         code = CM_ERROR_BADPASSWORD;
464     }
465
466     if (secCtx) {
467         if (secCtx->partialToken) free(secCtx->partialToken);
468         free(secCtx);
469     }
470
471     if (assembledBlob) {
472         free(assembledBlob);
473     }
474
475     if (secTokOut.pvBuffer)
476         FreeContextBuffer(secTokOut.pvBuffer);
477
478     if (code != CM_ERROR_GSSCONTINUE) {
479         DeleteSecurityContext(&ctx);
480         FreeCredentialsHandle(&creds);
481     }
482
483   aue_0:
484     return code;
485 }
486
487 #define P_LEN 256
488 #define P_RESP_LEN 128
489
490 /* LsaLogonUser expects input parameters to be in a contiguous block of memory. 
491    So put stuff in a struct. */
492 struct Lm20AuthBlob {
493     MSV1_0_LM20_LOGON lmlogon;
494     BYTE ciResponse[P_RESP_LEN];    /* Unicode representation */
495     BYTE csResponse[P_RESP_LEN];    /* ANSI representation */
496     WCHAR accountNameW[P_LEN];
497     WCHAR primaryDomainW[P_LEN];
498     WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
499     TOKEN_GROUPS tgroups;
500     TOKEN_SOURCE tsource;
501 };
502
503 long smb_AuthenticateUserLM(smb_vc_t *vcp, char * accountName, char * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength) 
504 {
505     NTSTATUS nts, ntsEx;
506     struct Lm20AuthBlob lmAuth;
507     PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
508     QUOTA_LIMITS quotaLimits;
509     DWORD size;
510     ULONG lmprofilepSize;
511     LUID lmSession;
512     HANDLE lmToken;
513
514     OutputDebugF("In smb_AuthenticateUser for user [%s] domain [%s]", accountName, primaryDomain);
515     OutputDebugF("ciPwdLength is %d and csPwdLength is %d", ciPwdLength, csPwdLength);
516
517     if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
518         OutputDebugF("ciPwdLength or csPwdLength is too long");
519         return CM_ERROR_BADPASSWORD;
520     }
521
522     memset(&lmAuth,0,sizeof(lmAuth));
523
524     lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
525         
526     lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
527     mbstowcs(lmAuth.primaryDomainW, primaryDomain, P_LEN);
528     lmAuth.lmlogon.LogonDomainName.Length = wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR);
529     lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
530
531     lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
532     mbstowcs(lmAuth.accountNameW, accountName, P_LEN);
533     lmAuth.lmlogon.UserName.Length = wcslen(lmAuth.accountNameW) * sizeof(WCHAR);
534     lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
535
536     lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
537     lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
538     size = MAX_COMPUTERNAME_LENGTH + 1;
539     GetComputerNameW(lmAuth.workstationW, &size);
540     lmAuth.lmlogon.Workstation.Length = wcslen(lmAuth.workstationW) * sizeof(WCHAR);
541
542     memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
543
544     lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
545     lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
546     lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
547     memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
548
549     lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
550     lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
551     lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
552     memcpy(lmAuth.csResponse, csPwd, csPwdLength);
553
554     lmAuth.lmlogon.ParameterControl = 0;
555
556     lmAuth.tgroups.GroupCount = 0;
557     lmAuth.tgroups.Groups[0].Sid = NULL;
558     lmAuth.tgroups.Groups[0].Attributes = 0;
559
560     lmAuth.tsource.SourceIdentifier.HighPart = 0;
561     lmAuth.tsource.SourceIdentifier.LowPart = (DWORD) vcp;
562     strcpy(lmAuth.tsource.SourceName,"OpenAFS"); /* 8 char limit */
563
564     nts = LsaLogonUser( smb_lsaHandle,
565                         &smb_lsaLogonOrigin,
566                         Network, /*3*/
567                         smb_lsaSecPackage,
568                         &lmAuth,
569                         sizeof(lmAuth),
570                         &lmAuth.tgroups,
571                         &lmAuth.tsource,
572                         &lmprofilep,
573                         &lmprofilepSize,
574                         &lmSession,
575                         &lmToken,
576                         &quotaLimits,
577                         &ntsEx);
578
579     OutputDebugF("Return from LsaLogonUser is 0x%lX", nts);
580     OutputDebugF("Extended status is 0x%lX", ntsEx);
581
582     if (nts == ERROR_SUCCESS) {
583         /* free the token */
584         LsaFreeReturnBuffer(lmprofilep);
585         CloseHandle(lmToken);
586         return 0;
587     } else {
588         /* No AFS for you */
589         if (nts == 0xC000015BL)
590             return CM_ERROR_BADLOGONTYPE;
591         else /* our catchall is a bad password though we could be more specific */
592             return CM_ERROR_BADPASSWORD;
593     }       
594 }
595
596 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
597 long smb_GetNormalizedUsername(char * usern, const char * accountName, const char * domainName) 
598 {
599     char * atsign;
600     const char * domain;
601
602     /* check if we have sane input */
603     if ((strlen(accountName) + strlen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
604         return 1;
605
606     /* we could get : [accountName][domainName]
607        [user][domain]
608        [user@domain][]
609        [user][]/[user][?]
610        [][]/[][?] */
611
612     atsign = strchr(accountName, '@');
613
614     if (atsign) /* [user@domain][] -> [user@domain][domain] */
615         domain = atsign + 1;
616     else
617         domain = domainName;
618
619     /* if for some reason the client doesn't know what domain to use,
620        it will either return an empty string or a '?' */
621     if (!domain[0] || domain[0] == '?')
622         /* Empty domains and empty usernames are usually sent from tokenless contexts.
623            This way such logins will get an empty username (easy to check).  I don't know 
624            when a non-empty username would be supplied with an anonymous domain, but *shrug* */
625         strcpy(usern,accountName);
626     else {
627         /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
628         strcpy(usern,domain);
629         strcat(usern,"\\");
630         if (atsign)
631             strncat(usern,accountName,atsign - accountName);
632         else
633             strcat(usern,accountName);
634     }       
635
636     strlwr(usern);
637
638     return 0;
639 }
640
641 /* When using SMB auth, all SMB sessions have to pass through here first to
642  * authenticate the user. 
643  * Caveat: If not use the SMB auth the protocol does not require sending a
644  * session setup packet, which means that we can't rely on a UID in subsequent
645  * packets.  Though in practice we get one anyway.
646  */
647 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
648 {
649     char *tp;
650     smb_user_t *uidp;
651     unsigned short newUid;
652     unsigned long caps = 0;
653     cm_user_t *userp;
654     smb_username_t *unp;
655     char *s1 = " ";
656     long code = 0; 
657     char usern[SMB_MAX_USERNAME_LENGTH];
658     char *secBlobOut = NULL;
659     int  secBlobOutLength = 0;
660
661     /* Check for bad conns */
662     if (vcp->flags & SMB_VCFLAG_REMOTECONN)
663         return CM_ERROR_REMOTECONN;
664
665     if (vcp->flags & SMB_VCFLAG_USENT) {
666         if (smb_authType == SMB_AUTH_EXTENDED) {
667             /* extended authentication */
668             char *secBlobIn;
669             int secBlobInLength;
670         
671             if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
672                 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
673             }
674
675             secBlobInLength = smb_GetSMBParm(inp, 7);
676             secBlobIn = smb_GetSMBData(inp, NULL);
677
678             code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
679
680             if (code == CM_ERROR_GSSCONTINUE) {
681                 smb_SetSMBParm(outp, 2, 0);
682                 smb_SetSMBParm(outp, 3, secBlobOutLength);
683                 smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
684                 tp = smb_GetSMBData(outp, NULL);
685                 if (secBlobOutLength) {
686                     memcpy(tp, secBlobOut, secBlobOutLength);
687                     free(secBlobOut);
688                     tp += secBlobOutLength;
689                 }       
690                 memcpy(tp,smb_ServerOS,smb_ServerOSLength);
691                 tp += smb_ServerOSLength;
692                 memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
693                 tp += smb_ServerLanManagerLength;
694                 memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
695                 tp += smb_ServerDomainNameLength;
696             }
697
698             /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
699         } else {
700             unsigned ciPwdLength, csPwdLength;
701             char *ciPwd, *csPwd;
702             char *accountName;
703             char *primaryDomain;
704             int  datalen;
705
706             /* TODO: parse for extended auth as well */
707             ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
708             csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
709
710             tp = smb_GetSMBData(inp, &datalen);
711
712             OutputDebugF("Session packet data size [%d]",datalen);
713
714             ciPwd = tp;
715             tp += ciPwdLength;
716             csPwd = tp;
717             tp += csPwdLength;
718
719             accountName = smb_ParseString(tp, &tp);
720             primaryDomain = smb_ParseString(tp, NULL);
721
722             if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
723                 /* shouldn't happen */
724                 code = CM_ERROR_BADSMB;
725                 goto after_read_packet;
726             }
727
728             /* capabilities are only valid for first session packet */
729             if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
730                 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
731             }
732
733             if (smb_authType == SMB_AUTH_NTLM) {
734                 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
735             }
736         }
737     }  else { /* V3 */
738         unsigned ciPwdLength;
739         char *ciPwd;
740         char *accountName;
741         char *primaryDomain;
742
743         ciPwdLength = smb_GetSMBParm(inp, 7);
744         tp = smb_GetSMBData(inp, NULL);
745         ciPwd = tp;
746         tp += ciPwdLength;
747
748         accountName = smb_ParseString(tp, &tp);
749         primaryDomain = smb_ParseString(tp, NULL);
750
751         if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
752             /* shouldn't happen */
753             code = CM_ERROR_BADSMB;
754             goto after_read_packet;
755         }
756
757         /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
758          * to NTLM.
759          */
760         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
761             code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
762         }
763     }
764
765   after_read_packet:
766     /* note down that we received a session setup X and set the capabilities flag */
767     if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
768         lock_ObtainMutex(&vcp->mx);
769         vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
770         /* for the moment we can only deal with NTSTATUS */
771         if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
772             vcp->flags |= SMB_VCFLAG_STATUS32;
773         }       
774         lock_ReleaseMutex(&vcp->mx);
775     }
776
777     /* code would be non-zero if there was an authentication failure.
778        Ideally we would like to invalidate the uid for this session or break
779        early to avoid accidently stealing someone else's tokens. */
780
781     if (code) {
782         return code;
783     }
784
785     OutputDebugF("Received username=[%s]", usern);
786
787     /* On Windows 2000, this function appears to be called more often than
788        it is expected to be called. This resulted in multiple smb_user_t
789        records existing all for the same user session which results in all
790        of the users tokens disappearing.
791
792        To avoid this problem, we look for an existing smb_user_t record
793        based on the users name, and use that one if we find it.
794     */
795
796     uidp = smb_FindUserByNameThisSession(vcp, usern);
797     if (uidp) {   /* already there, so don't create a new one */
798         unp = uidp->unp;
799         userp = unp->userp;
800         newUid = (unsigned short)uidp->userID;  /* For some reason these are different types!*/
801         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));
802         osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",vcp->lana,vcp->lsn,newUid);
803         smb_ReleaseUID(uidp);
804     }
805     else {
806       /* do a global search for the username/machine name pair */
807         unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
808
809         /* Create a new UID and cm_user_t structure */
810         userp = unp->userp;
811         if (!userp)
812             userp = cm_NewUser();
813         lock_ObtainMutex(&vcp->mx);
814         if (!vcp->uidCounter)
815             vcp->uidCounter++; /* handle unlikely wraparounds */
816         newUid = (strlen(usern)==0)?0:vcp->uidCounter++;
817         lock_ReleaseMutex(&vcp->mx);
818
819         /* Create a new smb_user_t structure and connect them up */
820         lock_ObtainMutex(&unp->mx);
821         unp->userp = userp;
822         lock_ReleaseMutex(&unp->mx);
823
824         uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
825         lock_ObtainMutex(&uidp->mx);
826         uidp->unp = unp;
827         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));
828         osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%x],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
829         lock_ReleaseMutex(&uidp->mx);
830         smb_ReleaseUID(uidp);
831     }
832
833     /* Return UID to the client */
834     ((smb_t *)outp)->uid = newUid;
835     /* Also to the next chained message */
836     ((smb_t *)inp)->uid = newUid;
837
838     osi_Log3(smb_logp, "SMB3 session setup name %s creating ID %d%s",
839              osi_LogSaveString(smb_logp, usern), newUid, osi_LogSaveString(smb_logp, s1));
840
841     smb_SetSMBParm(outp, 2, 0);
842
843     if (vcp->flags & SMB_VCFLAG_USENT) {
844         if (smb_authType == SMB_AUTH_EXTENDED) {
845             smb_SetSMBParm(outp, 3, secBlobOutLength);
846             smb_SetSMBDataLength(outp, secBlobOutLength + smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
847             tp = smb_GetSMBData(outp, NULL);
848             if (secBlobOutLength) {
849                 memcpy(tp, secBlobOut, secBlobOutLength);
850                 free(secBlobOut);
851                 tp += secBlobOutLength;
852             }   
853             memcpy(tp,smb_ServerOS,smb_ServerOSLength);
854             tp += smb_ServerOSLength;
855             memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
856             tp += smb_ServerLanManagerLength;
857             memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
858             tp += smb_ServerDomainNameLength;
859         } else {
860             smb_SetSMBDataLength(outp, 0);
861         }
862     } else {
863         if (smb_authType == SMB_AUTH_EXTENDED) {
864             smb_SetSMBDataLength(outp, smb_ServerOSLength + smb_ServerLanManagerLength + smb_ServerDomainNameLength);
865             tp = smb_GetSMBData(outp, NULL);
866             memcpy(tp,smb_ServerOS,smb_ServerOSLength);
867             tp += smb_ServerOSLength;
868             memcpy(tp,smb_ServerLanManager,smb_ServerLanManagerLength);
869             tp += smb_ServerLanManagerLength;
870             memcpy(tp,smb_ServerDomainName,smb_ServerDomainNameLength);
871             tp += smb_ServerDomainNameLength;
872         } else {
873             smb_SetSMBDataLength(outp, 0);
874         }
875     }
876
877     return 0;
878 }
879
880 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
881 {
882     smb_user_t *uidp;
883
884     /* don't get tokens from this VC */
885     vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
886
887     inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
888
889     /* find the tree and free it */
890     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
891     /* TODO: smb_ReleaseUID() ? */
892     if (uidp) {
893         char *s1 = NULL, *s2 = NULL;
894
895         if (s2 == NULL) s2 = " ";
896         if (s1 == NULL) {s1 = s2; s2 = " ";}
897
898         osi_Log4(smb_logp, "SMB3 user logoffX uid %d name %s%s%s", uidp->userID,
899                   osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name: " "), s1, s2);
900
901         lock_ObtainMutex(&uidp->mx);
902         uidp->flags |= SMB_USERFLAG_DELETE;
903         /*
904          * it doesn't get deleted right away
905          * because the vcp points to it
906          */
907         lock_ReleaseMutex(&uidp->mx);
908     }
909     else    
910         osi_Log0(smb_logp, "SMB3 user logoffX");
911
912     smb_SetSMBDataLength(outp, 0);
913     return 0;
914 }
915
916 #define SMB_SUPPORT_SEARCH_BITS        0x0001
917
918 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
919 {
920     smb_tid_t *tidp;
921     smb_user_t *uidp;
922     unsigned short newTid;
923     char shareName[256];
924     char *sharePath;
925     int shareFound;
926     char *tp;
927     char *pathp;
928     char *passwordp;
929     char *servicep;
930     cm_user_t *userp;
931     int ipc = 0;
932         
933     osi_Log0(smb_logp, "SMB3 receive tree connect");
934
935     /* parse input parameters */
936     tp = smb_GetSMBData(inp, NULL);
937     passwordp = smb_ParseString(tp, &tp);
938     pathp = smb_ParseString(tp, &tp);
939     servicep = smb_ParseString(tp, &tp);
940
941     tp = strrchr(pathp, '\\');
942     if (!tp) {
943         return CM_ERROR_BADSMB;
944     }
945     strcpy(shareName, tp+1);
946
947     osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
948              osi_LogSaveString(smb_logp, pathp),
949              osi_LogSaveString(smb_logp, shareName));
950
951     if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
952 #ifndef NO_IPC
953         osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
954         ipc = 1;
955 #else
956         return CM_ERROR_NOIPC;
957 #endif
958     }
959
960     userp = smb_GetUser(vcp, inp);
961
962     lock_ObtainMutex(&vcp->mx);
963     newTid = vcp->tidCounter++;
964     lock_ReleaseMutex(&vcp->mx);
965         
966     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
967
968     if(!ipc) {
969         uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
970         shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
971         if (uidp)
972             smb_ReleaseUID(uidp);
973         if (!shareFound) {
974             smb_ReleaseTID(tidp);
975             return CM_ERROR_BADSHARENAME;
976         }
977
978         if (vcp->flags & SMB_VCFLAG_USENT)
979         {
980             int policy = smb_FindShareCSCPolicy(shareName);
981             smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
982         }
983     } else {
984         smb_SetSMBParm(outp, 2, 0);
985         sharePath = NULL;
986     }
987
988     lock_ObtainMutex(&tidp->mx);
989     tidp->userp = userp;
990     tidp->pathname = sharePath;
991     if(ipc) tidp->flags |= SMB_TIDFLAG_IPC;
992     lock_ReleaseMutex(&tidp->mx);
993     smb_ReleaseTID(tidp);
994
995     ((smb_t *)outp)->tid = newTid;
996     ((smb_t *)inp)->tid = newTid;
997     tp = smb_GetSMBData(outp, NULL);
998     if (!ipc) {
999         *tp++ = 'A';
1000         *tp++ = ':';
1001         *tp++ = 0;
1002         smb_SetSMBDataLength(outp, 3);
1003     } else {
1004         strcpy(tp, "IPC");
1005         smb_SetSMBDataLength(outp, 4);
1006     }
1007
1008     osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1009     return 0;
1010 }
1011
1012 /* must be called with global tran lock held */
1013 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1014 {
1015     smb_tran2Packet_t *tp;
1016     smb_t *smbp;
1017         
1018     smbp = (smb_t *) inp->data;
1019     for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1020         if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1021             return tp;
1022     }
1023     return NULL;
1024 }
1025
1026 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1027         int totalParms, int totalData)
1028 {
1029     smb_tran2Packet_t *tp;
1030     smb_t *smbp;
1031         
1032     smbp = (smb_t *) inp->data;
1033     tp = malloc(sizeof(*tp));
1034     memset(tp, 0, sizeof(*tp));
1035     tp->vcp = vcp;
1036     smb_HoldVC(vcp);
1037     tp->curData = tp->curParms = 0;
1038     tp->totalData = totalData;
1039     tp->totalParms = totalParms;
1040     tp->tid = smbp->tid;
1041     tp->mid = smbp->mid;
1042     tp->uid = smbp->uid;
1043     tp->pid = smbp->pid;
1044     tp->res[0] = smbp->res[0];
1045     osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1046     if (totalParms != 0)
1047         tp->parmsp = malloc(totalParms);
1048     if (totalData != 0)
1049         tp->datap = malloc(totalData);
1050     if (smbp->com == 0x25 || smbp->com == 0x26)
1051         tp->com = 0x25;
1052     else {
1053         tp->opcode = smb_GetSMBParm(inp, 14);
1054         tp->com = 0x32;
1055     }
1056     tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1057     return tp;
1058 }
1059
1060 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1061                                                smb_tran2Packet_t *inp, smb_packet_t *outp,
1062                                                int totalParms, int totalData)  
1063 {
1064     smb_tran2Packet_t *tp;
1065     unsigned short parmOffset;
1066     unsigned short dataOffset;
1067     unsigned short dataAlign;
1068         
1069     tp = malloc(sizeof(*tp));
1070     memset(tp, 0, sizeof(*tp));
1071     tp->vcp = NULL;
1072     tp->curData = tp->curParms = 0;
1073     tp->totalData = totalData;
1074     tp->totalParms = totalParms;
1075     tp->oldTotalParms = totalParms;
1076     tp->tid = inp->tid;
1077     tp->mid = inp->mid;
1078     tp->uid = inp->uid;
1079     tp->pid = inp->pid;
1080     tp->res[0] = inp->res[0];
1081     tp->opcode = inp->opcode;
1082     tp->com = inp->com;
1083
1084     /*
1085      * We calculate where the parameters and data will start.
1086      * This calculation must parallel the calculation in
1087      * smb_SendTran2Packet.
1088      */
1089
1090     parmOffset = 10*2 + 35;
1091     parmOffset++;                       /* round to even */
1092     tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1093
1094     dataOffset = parmOffset + totalParms;
1095     dataAlign = dataOffset & 2; /* quad-align */
1096     dataOffset += dataAlign;
1097     tp->datap = outp->data + dataOffset;
1098
1099     return tp;
1100 }       
1101
1102 /* free a tran2 packet; must be called with smb_globalLock held */
1103 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1104 {
1105     if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1106     if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1107         if (t2p->parmsp)
1108             free(t2p->parmsp);
1109         if (t2p->datap)
1110             free(t2p->datap);
1111     }       
1112     free(t2p);
1113 }
1114
1115 /* called with a VC, an input packet to respond to, and an error code.
1116  * sends an error response.
1117  */
1118 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1119         smb_packet_t *tp, long code)
1120 {
1121     smb_t *smbp;
1122     unsigned short errCode;
1123     unsigned char errClass;
1124     unsigned long NTStatus;
1125
1126     if (vcp->flags & SMB_VCFLAG_STATUS32)
1127         smb_MapNTError(code, &NTStatus);
1128     else
1129         smb_MapCoreError(code, vcp, &errCode, &errClass);
1130
1131     smb_FormatResponsePacket(vcp, NULL, tp);
1132     smbp = (smb_t *) tp;
1133
1134     /* We can handle long names */
1135     if (vcp->flags & SMB_VCFLAG_USENT)
1136         smbp->flg2 |= 0x40;     /* IS_LONG_NAME */
1137         
1138     /* now copy important fields from the tran 2 packet */
1139     smbp->com = t2p->com;
1140     smbp->tid = t2p->tid;
1141     smbp->mid = t2p->mid;
1142     smbp->pid = t2p->pid;
1143     smbp->uid = t2p->uid;
1144     smbp->res[0] = t2p->res[0];
1145     if (vcp->flags & SMB_VCFLAG_STATUS32) {
1146         smbp->rcls = (unsigned char) (NTStatus & 0xff);
1147         smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1148         smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1149         smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1150         smbp->flg2 |= 0x4000;
1151     }
1152     else {
1153         smbp->rcls = errClass;
1154         smbp->errLow = (unsigned char) (errCode & 0xff);
1155         smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1156     }
1157         
1158     /* send packet */
1159     smb_SendPacket(vcp, tp);
1160 }        
1161
1162 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1163 {
1164     smb_t *smbp;
1165     unsigned short parmOffset;
1166     unsigned short dataOffset;
1167     unsigned short totalLength;
1168     unsigned short dataAlign;
1169     char *datap;
1170
1171     smb_FormatResponsePacket(vcp, NULL, tp);
1172     smbp = (smb_t *) tp;
1173
1174     /* We can handle long names */
1175     if (vcp->flags & SMB_VCFLAG_USENT)
1176         smbp->flg2 |= 0x40;     /* IS_LONG_NAME */
1177
1178     /* now copy important fields from the tran 2 packet */
1179     smbp->com = t2p->com;
1180     smbp->tid = t2p->tid;
1181     smbp->mid = t2p->mid;
1182     smbp->pid = t2p->pid;
1183     smbp->uid = t2p->uid;
1184     smbp->res[0] = t2p->res[0];
1185
1186     totalLength = 1 + t2p->totalData + t2p->totalParms;
1187
1188     /* now add the core parameters (tran2 info) to the packet */
1189     smb_SetSMBParm(tp, 0, t2p->totalParms);     /* parm bytes */
1190     smb_SetSMBParm(tp, 1, t2p->totalData);      /* data bytes */
1191     smb_SetSMBParm(tp, 2, 0);           /* reserved */
1192     smb_SetSMBParm(tp, 3, t2p->totalParms);     /* parm bytes in this packet */
1193     parmOffset = 10*2 + 35;                     /* parm offset in packet */
1194     parmOffset++;                               /* round to even */
1195     smb_SetSMBParm(tp, 4, parmOffset);  /* 11 parm words plus *
1196     * hdr, bcc and wct */
1197     smb_SetSMBParm(tp, 5, 0);           /* parm displacement */
1198     smb_SetSMBParm(tp, 6, t2p->totalData);      /* data in this packet */
1199     dataOffset = parmOffset + t2p->oldTotalParms;
1200     dataAlign = dataOffset & 2;         /* quad-align */
1201     dataOffset += dataAlign;
1202     smb_SetSMBParm(tp, 7, dataOffset);  /* offset of data */
1203     smb_SetSMBParm(tp, 8, 0);           /* data displacement */
1204     smb_SetSMBParm(tp, 9, 0);           /* low: setup word count *
1205     * high: resvd */
1206
1207     datap = smb_GetSMBData(tp, NULL);
1208     *datap++ = 0;                               /* we rounded to even */
1209
1210     totalLength += dataAlign;
1211     smb_SetSMBDataLength(tp, totalLength);
1212         
1213     /* next, send the datagram */
1214     smb_SendPacket(vcp, tp);
1215 }   
1216
1217 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1218 {
1219     smb_tran2Packet_t *asp;
1220     int totalParms;
1221     int totalData;
1222     int parmDisp;
1223     int dataDisp;
1224     int parmOffset;
1225     int dataOffset;
1226     int parmCount;
1227     int dataCount;
1228     int firstPacket;
1229     int rapOp;
1230     long code = 0;
1231
1232     /* We sometimes see 0 word count.  What to do? */
1233     if (*inp->wctp == 0) {
1234 #ifndef DJGPP
1235         HANDLE h;
1236         char *ptbuf[1];
1237
1238         osi_Log0(smb_logp, "TRANSACTION word count = 0"); 
1239
1240         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1241         ptbuf[0] = "Transaction2 word count = 0";
1242         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1243                     1, inp->ncb_length, ptbuf, inp);
1244         DeregisterEventSource(h);
1245 #else /* DJGPP */
1246         osi_Log0(smb_logp, "TRANSACTION word count = 0"); 
1247 #endif /* !DJGPP */
1248
1249         smb_SetSMBDataLength(outp, 0);
1250         smb_SendPacket(vcp, outp);
1251         return 0;
1252     }
1253
1254     totalParms = smb_GetSMBParm(inp, 0);
1255     totalData = smb_GetSMBParm(inp, 1);
1256         
1257     firstPacket = (inp->inCom == 0x25);
1258         
1259     /* find the packet we're reassembling */
1260     lock_ObtainWrite(&smb_globalLock);
1261     asp = smb_FindTran2Packet(vcp, inp);
1262     if (!asp) {
1263         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1264     }
1265     lock_ReleaseWrite(&smb_globalLock);
1266         
1267     /* now merge in this latest packet; start by looking up offsets */
1268     if (firstPacket) {
1269         parmDisp = dataDisp = 0;
1270         parmOffset = smb_GetSMBParm(inp, 10);
1271         dataOffset = smb_GetSMBParm(inp, 12);
1272         parmCount = smb_GetSMBParm(inp, 9);
1273         dataCount = smb_GetSMBParm(inp, 11);
1274         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1275         asp->maxReturnData = smb_GetSMBParm(inp, 3);
1276
1277         osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1278                   totalData, dataCount, asp->maxReturnData);
1279     }
1280     else {
1281         parmDisp = smb_GetSMBParm(inp, 4);
1282         parmOffset = smb_GetSMBParm(inp, 3);
1283         dataDisp = smb_GetSMBParm(inp, 7);
1284         dataOffset = smb_GetSMBParm(inp, 6);
1285         parmCount = smb_GetSMBParm(inp, 2);
1286         dataCount = smb_GetSMBParm(inp, 5);
1287
1288         osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1289                  parmCount, dataCount);
1290     }   
1291
1292     /* now copy the parms and data */
1293     if ( asp->totalParms > 0 && parmCount != 0 )
1294     {
1295         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1296     }
1297     if ( asp->totalData > 0 && dataCount != 0 ) {
1298         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1299     }
1300
1301     /* account for new bytes */
1302     asp->curData += dataCount;
1303     asp->curParms += parmCount;
1304
1305     /* finally, if we're done, remove the packet from the queue and dispatch it */
1306     if (asp->totalParms > 0 &&
1307         asp->curParms > 0 &&
1308         asp->totalData <= asp->curData &&
1309         asp->totalParms <= asp->curParms) {
1310         /* we've received it all */
1311         lock_ObtainWrite(&smb_globalLock);
1312         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1313         lock_ReleaseWrite(&smb_globalLock);
1314
1315         /* now dispatch it */
1316         rapOp = asp->parmsp[0];
1317
1318         if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1319             osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1320             osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1321             code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1322         }
1323         else {
1324             osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1325             osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1326             code = CM_ERROR_BADOP;
1327         }
1328
1329         /* if an error is returned, we're supposed to send an error packet,
1330          * otherwise the dispatched function already did the data sending.
1331          * We give dispatched proc the responsibility since it knows how much
1332          * space to allocate.
1333          */
1334         if (code != 0) {
1335             smb_SendTran2Error(vcp, asp, outp, code);
1336         }
1337
1338         /* free the input tran 2 packet */
1339         lock_ObtainWrite(&smb_globalLock);
1340         smb_FreeTran2Packet(asp);
1341         lock_ReleaseWrite(&smb_globalLock);
1342     }
1343     else if (firstPacket) {
1344         /* the first packet in a multi-packet request, we need to send an
1345          * ack to get more data.
1346          */
1347         smb_SetSMBDataLength(outp, 0);
1348         smb_SendPacket(vcp, outp);
1349     }
1350
1351     return 0;
1352 }
1353
1354 /* ANSI versions.  The unicode versions support arbitrary length
1355    share names, but we don't support unicode yet. */
1356
1357 typedef struct smb_rap_share_info_0 {
1358     char        shi0_netname[13];
1359 } smb_rap_share_info_0_t;
1360
1361 typedef struct smb_rap_share_info_1 {
1362     char                        shi1_netname[13];
1363     char                        shi1_pad;
1364     WORD                        shi1_type;
1365     DWORD                       shi1_remark; /* char *shi1_remark; data offset */
1366 } smb_rap_share_info_1_t;
1367
1368 typedef struct smb_rap_share_info_2 {
1369     char                                shi2_netname[13];
1370     char                                shi2_pad;
1371     unsigned short              shi2_type;
1372     DWORD                               shi2_remark; /* char *shi2_remark; data offset */
1373     unsigned short              shi2_permissions;
1374     unsigned short              shi2_max_uses;
1375     unsigned short              shi2_current_uses;
1376     DWORD                               shi2_path;  /* char *shi2_path; data offset */
1377     unsigned short              shi2_passwd[9];
1378     unsigned short              shi2_pad2;
1379 } smb_rap_share_info_2_t;
1380
1381 #define SMB_RAP_MAX_SHARES 512
1382
1383 typedef struct smb_rap_share_list {
1384     int cShare;
1385     int maxShares;
1386     smb_rap_share_info_0_t * shares;
1387 } smb_rap_share_list_t;
1388
1389 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1390     smb_rap_share_list_t * sp;
1391     char * name;
1392
1393     name = dep->name;
1394
1395     if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1396         return 0; /* skip over '.' and '..' */
1397
1398     sp = (smb_rap_share_list_t *) vrockp;
1399
1400     strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1401     sp->shares[sp->cShare].shi0_netname[12] = 0;
1402
1403     sp->cShare++;
1404
1405     if (sp->cShare >= sp->maxShares)
1406         return CM_ERROR_STOPNOW;
1407     else
1408         return 0;
1409 }       
1410
1411 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1412 {
1413     smb_tran2Packet_t *outp;
1414     unsigned short * tp;
1415     int len;
1416     int infoLevel;
1417     int bufsize;
1418     int outParmsTotal;  /* total parameter bytes */
1419     int outDataTotal;   /* total data bytes */
1420     int code = 0;
1421     DWORD rv;
1422     DWORD allSubmount;
1423     USHORT nShares;
1424     DWORD nRegShares;
1425     DWORD nSharesRet;
1426     HKEY hkParam;
1427     HKEY hkSubmount = NULL;
1428     smb_rap_share_info_1_t * shares;
1429     USHORT cshare = 0;
1430     char * cstrp;
1431     char thisShare[256];
1432     int i,j;
1433     int nonrootShares;
1434     smb_rap_share_list_t rootShares;
1435     cm_req_t req;
1436     cm_user_t * userp;
1437     osi_hyper_t thyper;
1438
1439     tp = p->parmsp + 1; /* skip over function number (always 0) */
1440     (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1441     (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1442     infoLevel = tp[0];
1443     bufsize = tp[1];
1444
1445     if (infoLevel != 1) {
1446         return CM_ERROR_INVAL;
1447     }
1448
1449     /* first figure out how many shares there are */
1450     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1451                       KEY_QUERY_VALUE, &hkParam);
1452     if (rv == ERROR_SUCCESS) {
1453         len = sizeof(allSubmount);
1454         rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1455                              (BYTE *) &allSubmount, &len);
1456         if (rv != ERROR_SUCCESS || allSubmount != 0) {
1457             allSubmount = 1;
1458         }
1459         RegCloseKey (hkParam);
1460     }
1461
1462     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1463                       0, KEY_QUERY_VALUE, &hkSubmount);
1464     if (rv == ERROR_SUCCESS) {
1465         rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1466                              NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1467         if (rv != ERROR_SUCCESS)
1468             nRegShares = 0;
1469     } else {
1470         hkSubmount = NULL;
1471     }
1472
1473     /* fetch the root shares */
1474     rootShares.maxShares = SMB_RAP_MAX_SHARES;
1475     rootShares.cShare = 0;
1476     rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1477
1478     cm_InitReq(&req);
1479
1480     userp = smb_GetTran2User(vcp,p);
1481
1482     thyper.HighPart = 0;
1483     thyper.LowPart = 0;
1484
1485     cm_HoldSCache(cm_rootSCachep);
1486     cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1487     cm_ReleaseSCache(cm_rootSCachep);
1488
1489     cm_ReleaseUser(userp);
1490
1491     nShares = rootShares.cShare + nRegShares + allSubmount;
1492
1493 #define REMARK_LEN 1
1494     outParmsTotal = 8; /* 4 dwords */
1495     outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1496     if(outDataTotal > bufsize) {
1497         nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1498         outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1499     }
1500     else {
1501         nSharesRet = nShares;
1502     }
1503     
1504     outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1505
1506     /* now for the submounts */
1507     shares = (smb_rap_share_info_1_t *) outp->datap;
1508     cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1509
1510     memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1511
1512     if (allSubmount) {
1513         strcpy( shares[cshare].shi1_netname, "all" );
1514         shares[cshare].shi1_remark = cstrp - outp->datap;
1515         /* type and pad are zero already */
1516         cshare++;
1517         cstrp+=REMARK_LEN;
1518     }
1519
1520     if (hkSubmount) {
1521         for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1522             len = sizeof(thisShare);
1523             rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1524             if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1525                 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1526                 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1527                 shares[cshare].shi1_remark = cstrp - outp->datap;
1528                 cshare++;
1529                 cstrp+=REMARK_LEN;
1530             }
1531             else
1532                 nShares--; /* uncount key */
1533         }
1534
1535         RegCloseKey(hkSubmount);
1536     }
1537
1538     nonrootShares = cshare;
1539
1540     for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1541         /* in case there are collisions with submounts, submounts have higher priority */               
1542         for (j=0; j < nonrootShares; j++)
1543             if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1544                 break;
1545                 
1546         if (j < nonrootShares) {
1547             nShares--; /* uncount */
1548             continue;
1549         }
1550
1551         strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1552         shares[cshare].shi1_remark = cstrp - outp->datap;
1553         cshare++;
1554         cstrp+=REMARK_LEN;
1555     }
1556
1557     outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1558     outp->parmsp[1] = 0;
1559     outp->parmsp[2] = cshare;
1560     outp->parmsp[3] = nShares;
1561
1562     outp->totalData = cstrp - outp->datap;
1563     outp->totalParms = outParmsTotal;
1564
1565     smb_SendTran2Packet(vcp, outp, op);
1566     smb_FreeTran2Packet(outp);
1567
1568     free(rootShares.shares);
1569
1570     return code;
1571 }
1572
1573 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1574 {
1575     smb_tran2Packet_t *outp;
1576     unsigned short * tp;
1577     char * shareName;
1578     BOOL shareFound = FALSE;
1579     unsigned short infoLevel;
1580     unsigned short bufsize;
1581     int totalData;
1582     int totalParam;
1583     DWORD len;
1584     HKEY hkParam;
1585     HKEY hkSubmount;
1586     DWORD allSubmount;
1587     LONG rv;
1588     long code = 0;
1589
1590     tp = p->parmsp + 1; /* skip over function number (always 1) */
1591     (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1592     (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1593     shareName = smb_ParseString( (char *) tp, (char **) &tp);
1594     infoLevel = *tp++;
1595     bufsize = *tp++;
1596     
1597     totalParam = 6;
1598
1599     if (infoLevel == 0)
1600         totalData = sizeof(smb_rap_share_info_0_t);
1601     else if(infoLevel == 1)
1602         totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1603     else if(infoLevel == 2)
1604         totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1605     else
1606         return CM_ERROR_INVAL;
1607
1608     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1609
1610     if(!stricmp(shareName,"all")) {
1611         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1612                           KEY_QUERY_VALUE, &hkParam);
1613         if (rv == ERROR_SUCCESS) {
1614             len = sizeof(allSubmount);
1615             rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1616                                   (BYTE *) &allSubmount, &len);
1617             if (rv != ERROR_SUCCESS || allSubmount != 0) {
1618                 allSubmount = 1;
1619             }
1620             RegCloseKey (hkParam);
1621         }
1622
1623         if (allSubmount)
1624             shareFound = TRUE;
1625
1626     } else {
1627         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1628                           KEY_QUERY_VALUE, &hkSubmount);
1629         if (rv == ERROR_SUCCESS) {
1630             rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1631             if (rv == ERROR_SUCCESS) {
1632                 shareFound = TRUE;
1633             }
1634             RegCloseKey(hkSubmount);
1635         }
1636     }
1637
1638     if (!shareFound) {
1639         smb_FreeTran2Packet(outp);
1640         return CM_ERROR_BADSHARENAME;
1641     }
1642
1643     memset(outp->datap, 0, totalData);
1644
1645     outp->parmsp[0] = 0;
1646     outp->parmsp[1] = 0;
1647     outp->parmsp[2] = totalData;
1648
1649     if (infoLevel == 0) {
1650         smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1651         strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1652         info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1653     } else if(infoLevel == 1) {
1654         smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1655         strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1656         info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1657         info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1658         /* type and pad are already zero */
1659     } else { /* infoLevel==2 */
1660         smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1661         strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1662         info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1663         info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1664         info->shi2_permissions = ACCESS_ALL;
1665         info->shi2_max_uses = (unsigned short) -1;
1666         info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1667     }
1668
1669     outp->totalData = totalData;
1670     outp->totalParms = totalParam;
1671
1672     smb_SendTran2Packet(vcp, outp, op);
1673     smb_FreeTran2Packet(outp);
1674
1675     return code;
1676 }
1677
1678 typedef struct smb_rap_wksta_info_10 {
1679     DWORD       wki10_computername;     /*char *wki10_computername;*/
1680     DWORD       wki10_username; /* char *wki10_username; */
1681     DWORD       wki10_langroup; /* char *wki10_langroup;*/
1682     unsigned char       wki10_ver_major;
1683     unsigned char       wki10_ver_minor;
1684     DWORD       wki10_logon_domain;     /*char *wki10_logon_domain;*/
1685     DWORD       wki10_oth_domains; /* char *wki10_oth_domains;*/
1686 } smb_rap_wksta_info_10_t;
1687
1688
1689 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1690 {
1691     smb_tran2Packet_t *outp;
1692     long code = 0;
1693     int infoLevel;
1694     int bufsize;
1695     unsigned short * tp;
1696     int totalData;
1697     int totalParams;
1698     smb_rap_wksta_info_10_t * info;
1699     char * cstrp;
1700     smb_user_t *uidp;
1701
1702     tp = p->parmsp + 1; /* Skip over function number */
1703     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1704     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1705     infoLevel = *tp++;
1706     bufsize = *tp++;
1707
1708     if (infoLevel != 10) {
1709         return CM_ERROR_INVAL;
1710     }
1711
1712     totalParams = 6;
1713         
1714     /* infolevel 10 */
1715     totalData = sizeof(*info) +         /* info */
1716         MAX_COMPUTERNAME_LENGTH +       /* wki10_computername */
1717         SMB_MAX_USERNAME_LENGTH +       /* wki10_username */
1718         MAX_COMPUTERNAME_LENGTH +       /* wki10_langroup */
1719         MAX_COMPUTERNAME_LENGTH +       /* wki10_logon_domain */
1720         1;                              /* wki10_oth_domains (null)*/
1721
1722     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1723
1724     memset(outp->parmsp,0,totalParams);
1725     memset(outp->datap,0,totalData);
1726
1727     info = (smb_rap_wksta_info_10_t *) outp->datap;
1728     cstrp = (char *) (info + 1);
1729
1730     info->wki10_computername = (DWORD) (cstrp - outp->datap);
1731     strcpy(cstrp, smb_localNamep);
1732     cstrp += strlen(cstrp) + 1;
1733
1734     info->wki10_username = (DWORD) (cstrp - outp->datap);
1735     uidp = smb_FindUID(vcp, p->uid, 0);
1736     if (uidp) {
1737         lock_ObtainMutex(&uidp->mx);
1738         if(uidp->unp && uidp->unp->name)
1739             strcpy(cstrp, uidp->unp->name);
1740         lock_ReleaseMutex(&uidp->mx);
1741         smb_ReleaseUID(uidp);
1742     }
1743     cstrp += strlen(cstrp) + 1;
1744
1745     info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1746     strcpy(cstrp, "WORKGROUP");
1747     cstrp += strlen(cstrp) + 1;
1748
1749     /* TODO: Not sure what values these should take, but these work */
1750     info->wki10_ver_major = 5;
1751     info->wki10_ver_minor = 1;
1752
1753     info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1754     strcpy(cstrp, smb_ServerDomainName);
1755     cstrp += strlen(cstrp) + 1;
1756
1757     info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1758     cstrp ++; /* no other domains */
1759
1760     outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1761     outp->parmsp[2] = outp->totalData;
1762     outp->totalParms = totalParams;
1763
1764     smb_SendTran2Packet(vcp,outp,op);
1765     smb_FreeTran2Packet(outp);
1766
1767     return code;
1768 }
1769
1770 typedef struct smb_rap_server_info_0 {
1771     char    sv0_name[16];
1772 } smb_rap_server_info_0_t;
1773
1774 typedef struct smb_rap_server_info_1 {
1775     char            sv1_name[16];
1776     char            sv1_version_major;
1777     char            sv1_version_minor;
1778     unsigned long   sv1_type;
1779     DWORD           *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1780 } smb_rap_server_info_1_t;
1781
1782 char smb_ServerComment[] = "OpenAFS Client";
1783 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1784
1785 #define SMB_SV_TYPE_SERVER              0x00000002L
1786 #define SMB_SV_TYPE_NT              0x00001000L
1787 #define SMB_SV_TYPE_SERVER_NT       0x00008000L
1788
1789 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1790 {
1791     smb_tran2Packet_t *outp;
1792     long code = 0;
1793     int infoLevel;
1794     int bufsize;
1795     unsigned short * tp;
1796     int totalData;
1797     int totalParams;
1798     smb_rap_server_info_0_t * info0;
1799     smb_rap_server_info_1_t * info1;
1800     char * cstrp;
1801
1802     tp = p->parmsp + 1; /* Skip over function number */
1803     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1804     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1805     infoLevel = *tp++;
1806     bufsize = *tp++;
1807
1808     if (infoLevel != 0 && infoLevel != 1) {
1809         return CM_ERROR_INVAL;
1810     }
1811
1812     totalParams = 6;
1813
1814     totalData = 
1815         (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1816         : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1817
1818     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1819
1820     memset(outp->parmsp,0,totalParams);
1821     memset(outp->datap,0,totalData);
1822
1823     if (infoLevel == 0) {
1824         info0 = (smb_rap_server_info_0_t *) outp->datap;
1825         cstrp = (char *) (info0 + 1);
1826         strcpy(info0->sv0_name, "AFS");
1827     } else { /* infoLevel == 1 */
1828         info1 = (smb_rap_server_info_1_t *) outp->datap;
1829         cstrp = (char *) (info1 + 1);
1830         strcpy(info1->sv1_name, "AFS");
1831
1832         info1->sv1_type = 
1833             SMB_SV_TYPE_SERVER |
1834             SMB_SV_TYPE_NT |
1835             SMB_SV_TYPE_SERVER_NT;
1836
1837         info1->sv1_version_major = 5;
1838         info1->sv1_version_minor = 1;
1839         info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1840
1841         strcpy(cstrp, smb_ServerComment);
1842
1843         cstrp += smb_ServerCommentLen;
1844     }
1845
1846     totalData = cstrp - outp->datap;
1847     outp->totalData = min(bufsize,totalData); /* actual data size */
1848     outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1849     outp->parmsp[2] = totalData;
1850     outp->totalParms = totalParams;
1851
1852     smb_SendTran2Packet(vcp,outp,op);
1853     smb_FreeTran2Packet(outp);
1854
1855     return code;
1856 }
1857
1858 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1859 {
1860     smb_tran2Packet_t *asp;
1861     int totalParms;
1862     int totalData;
1863     int parmDisp;
1864     int dataDisp;
1865     int parmOffset;
1866     int dataOffset;
1867     int parmCount;
1868     int dataCount;
1869     int firstPacket;
1870     long code = 0;
1871
1872     /* We sometimes see 0 word count.  What to do? */
1873     if (*inp->wctp == 0) {
1874 #ifndef DJGPP
1875         HANDLE h;
1876         char *ptbuf[1];
1877
1878         osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
1879
1880         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1881         ptbuf[0] = "Transaction2 word count = 0";
1882         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1883                     1, inp->ncb_length, ptbuf, inp);
1884         DeregisterEventSource(h);
1885 #else /* DJGPP */
1886         osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
1887 #endif /* !DJGPP */
1888
1889         smb_SetSMBDataLength(outp, 0);
1890         smb_SendPacket(vcp, outp);
1891         return 0;
1892     }
1893
1894     totalParms = smb_GetSMBParm(inp, 0);
1895     totalData = smb_GetSMBParm(inp, 1);
1896         
1897     firstPacket = (inp->inCom == 0x32);
1898         
1899     /* find the packet we're reassembling */
1900     lock_ObtainWrite(&smb_globalLock);
1901     asp = smb_FindTran2Packet(vcp, inp);
1902     if (!asp) {
1903         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1904     }
1905     lock_ReleaseWrite(&smb_globalLock);
1906         
1907     /* now merge in this latest packet; start by looking up offsets */
1908     if (firstPacket) {
1909         parmDisp = dataDisp = 0;
1910         parmOffset = smb_GetSMBParm(inp, 10);
1911         dataOffset = smb_GetSMBParm(inp, 12);
1912         parmCount = smb_GetSMBParm(inp, 9);
1913         dataCount = smb_GetSMBParm(inp, 11);
1914         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1915         asp->maxReturnData = smb_GetSMBParm(inp, 3);
1916
1917         osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1918                  totalData, dataCount, asp->maxReturnData);
1919     }
1920     else {
1921         parmDisp = smb_GetSMBParm(inp, 4);
1922         parmOffset = smb_GetSMBParm(inp, 3);
1923         dataDisp = smb_GetSMBParm(inp, 7);
1924         dataOffset = smb_GetSMBParm(inp, 6);
1925         parmCount = smb_GetSMBParm(inp, 2);
1926         dataCount = smb_GetSMBParm(inp, 5);
1927
1928         osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1929                  parmCount, dataCount);
1930     }   
1931
1932     /* now copy the parms and data */
1933     if ( asp->totalParms > 0 && parmCount != 0 )
1934     {
1935         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1936     }
1937     if ( asp->totalData > 0 && dataCount != 0 ) {
1938         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1939     }
1940
1941     /* account for new bytes */
1942     asp->curData += dataCount;
1943     asp->curParms += parmCount;
1944
1945     /* finally, if we're done, remove the packet from the queue and dispatch it */
1946     if (asp->totalParms > 0 &&
1947         asp->curParms > 0 &&
1948         asp->totalData <= asp->curData &&
1949         asp->totalParms <= asp->curParms) {
1950         /* we've received it all */
1951         lock_ObtainWrite(&smb_globalLock);
1952         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1953         lock_ReleaseWrite(&smb_globalLock);
1954
1955         /* now dispatch it */
1956         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1957             osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1958             osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1959             code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1960         }
1961         else {
1962             osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1963             osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1964             code = CM_ERROR_BADOP;
1965         }
1966
1967         /* if an error is returned, we're supposed to send an error packet,
1968          * otherwise the dispatched function already did the data sending.
1969          * We give dispatched proc the responsibility since it knows how much
1970          * space to allocate.
1971          */
1972         if (code != 0) {
1973             smb_SendTran2Error(vcp, asp, outp, code);
1974         }
1975
1976         /* free the input tran 2 packet */
1977         lock_ObtainWrite(&smb_globalLock);
1978         smb_FreeTran2Packet(asp);
1979         lock_ReleaseWrite(&smb_globalLock);
1980     }
1981     else if (firstPacket) {
1982         /* the first packet in a multi-packet request, we need to send an
1983          * ack to get more data.
1984          */
1985         smb_SetSMBDataLength(outp, 0);
1986         smb_SendPacket(vcp, outp);
1987     }
1988
1989     return 0;
1990 }
1991
1992 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1993 {
1994     char *pathp;
1995     smb_tran2Packet_t *outp;
1996     long code = 0;
1997     cm_space_t *spacep;
1998     int excl;
1999     cm_user_t *userp;
2000     cm_scache_t *dscp;          /* dir we're dealing with */
2001     cm_scache_t *scp;           /* file we're creating */
2002     cm_attr_t setAttr;
2003     int initialModeBits;
2004     smb_fid_t *fidp;
2005     int attributes;
2006     char *lastNamep;
2007     time_t dosTime;
2008     int openFun;
2009     int trunc;
2010     int openMode;
2011     int extraInfo;
2012     int openAction;
2013     int parmSlot;                       /* which parm we're dealing with */
2014     long returnEALength;
2015     char *tidPathp;
2016     cm_req_t req;
2017
2018     cm_InitReq(&req);
2019
2020     scp = NULL;
2021         
2022     extraInfo = (p->parmsp[0] & 1);     /* return extra info */
2023     returnEALength = (p->parmsp[0] & 8);        /* return extended attr length */
2024
2025     openFun = p->parmsp[6];             /* open function */
2026     excl = ((openFun & 3) == 0);
2027     trunc = ((openFun & 3) == 2);       /* truncate it */
2028     openMode = (p->parmsp[1] & 0x7);
2029     openAction = 0;                     /* tracks what we did */
2030
2031     attributes = p->parmsp[3];
2032     dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2033         
2034     /* compute initial mode bits based on read-only flag in attributes */
2035     initialModeBits = 0666;
2036     if (attributes & 1) initialModeBits &= ~0222;
2037         
2038     pathp = (char *) (&p->parmsp[14]);
2039         
2040     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2041
2042     spacep = cm_GetSpace();
2043     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2044
2045     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2046         /* special case magic file name for receiving IOCTL requests
2047          * (since IOCTL calls themselves aren't getting through).
2048          */
2049         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2050         smb_SetupIoctlFid(fidp, spacep);
2051
2052         /* copy out remainder of the parms */
2053         parmSlot = 0;
2054         outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2055         if (extraInfo) {
2056             outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
2057             outp->parmsp[parmSlot] = 0; parmSlot++;     /* mod time */
2058             outp->parmsp[parmSlot] = 0; parmSlot++;
2059             outp->parmsp[parmSlot] = 0; parmSlot++;     /* len */
2060             outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
2061             outp->parmsp[parmSlot] = openMode; parmSlot++;
2062             outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2063             outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2064         }   
2065         /* and the final "always present" stuff */
2066         outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
2067         /* next write out the "unique" ID */
2068         outp->parmsp[parmSlot] = 0x1234; parmSlot++;
2069         outp->parmsp[parmSlot] = 0x5678; parmSlot++;
2070         outp->parmsp[parmSlot] = 0; parmSlot++;
2071         if (returnEALength) {
2072             outp->parmsp[parmSlot] = 0; parmSlot++;
2073             outp->parmsp[parmSlot] = 0; parmSlot++;
2074         }       
2075                 
2076         outp->totalData = 0;
2077         outp->totalParms = parmSlot * 2;
2078                 
2079         smb_SendTran2Packet(vcp, outp, op);
2080                 
2081         smb_FreeTran2Packet(outp);
2082
2083         /* and clean up fid reference */
2084         smb_ReleaseFID(fidp);
2085         return 0;
2086     }
2087
2088 #ifdef DEBUG_VERBOSE
2089     {
2090         char *hexp, *asciip;
2091         asciip = (lastNamep ? lastNamep : pathp);
2092         hexp = osi_HexifyString( asciip );
2093         DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2094         free(hexp);
2095     }       
2096 #endif
2097
2098     userp = smb_GetTran2User(vcp, p);
2099     /* In the off chance that userp is NULL, we log and abandon */
2100     if (!userp) {
2101         osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2102         smb_FreeTran2Packet(outp);
2103         return CM_ERROR_BADSMB;
2104     }
2105
2106     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2107     if (code == CM_ERROR_TIDIPC) {
2108         /* Attempt to use TID allocated for IPC.  The client is
2109            probably trying to locate DCE RPC end points, which
2110            we don't support. */
2111         osi_Log0(smb_logp, "Tran2Open received IPC TID");
2112         cm_ReleaseUser(userp);
2113         smb_FreeTran2Packet(outp);
2114         return CM_ERROR_NOSUCHPATH;
2115     }
2116
2117     dscp = NULL;
2118     code = cm_NameI(cm_rootSCachep, pathp,
2119                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2120                      userp, tidPathp, &req, &scp);
2121     if (code != 0) {
2122         code = cm_NameI(cm_rootSCachep, spacep->data,
2123                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2124                          userp, tidPathp, &req, &dscp);
2125         cm_FreeSpace(spacep);
2126
2127         if (code) {
2128             cm_ReleaseUser(userp);
2129             smb_FreeTran2Packet(outp);
2130             return code;
2131         }
2132         
2133         /* otherwise, scp points to the parent directory.  Do a lookup,
2134          * and truncate the file if we find it, otherwise we create the
2135          * file.
2136          */
2137         if (!lastNamep) 
2138             lastNamep = pathp;
2139         else 
2140             lastNamep++;
2141         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2142                          &req, &scp);
2143         if (code && code != CM_ERROR_NOSUCHFILE) {
2144             cm_ReleaseSCache(dscp);
2145             cm_ReleaseUser(userp);
2146             smb_FreeTran2Packet(outp);
2147             return code;
2148         }
2149     }
2150     else {
2151         cm_FreeSpace(spacep);
2152     }
2153         
2154     /* if we get here, if code is 0, the file exists and is represented by
2155      * scp.  Otherwise, we have to create it.
2156      */
2157     if (code == 0) {
2158         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2159         if (code) {
2160             if (dscp) cm_ReleaseSCache(dscp);
2161             cm_ReleaseSCache(scp);
2162             cm_ReleaseUser(userp);
2163             smb_FreeTran2Packet(outp);
2164             return code;
2165         }
2166
2167         if (excl) {
2168             /* oops, file shouldn't be there */
2169             if (dscp) cm_ReleaseSCache(dscp);
2170             cm_ReleaseSCache(scp);
2171             cm_ReleaseUser(userp);
2172             smb_FreeTran2Packet(outp);
2173             return CM_ERROR_EXISTS;
2174         }
2175
2176         if (trunc) {
2177             setAttr.mask = CM_ATTRMASK_LENGTH;
2178             setAttr.length.LowPart = 0;
2179             setAttr.length.HighPart = 0;
2180             code = cm_SetAttr(scp, &setAttr, userp, &req);
2181             openAction = 3;     /* truncated existing file */
2182         }   
2183         else 
2184             openAction = 1;     /* found existing file */
2185     }
2186     else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2187         /* don't create if not found */
2188         if (dscp) cm_ReleaseSCache(dscp);
2189         osi_assert(scp == NULL);
2190         cm_ReleaseUser(userp);
2191         smb_FreeTran2Packet(outp);
2192         return CM_ERROR_NOSUCHFILE;
2193     }
2194     else {
2195         osi_assert(dscp != NULL && scp == NULL);
2196         openAction = 2; /* created file */
2197         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2198         smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2199         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2200                           &req);
2201         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2202             smb_NotifyChange(FILE_ACTION_ADDED,
2203                              FILE_NOTIFY_CHANGE_FILE_NAME,  
2204                              dscp, lastNamep, NULL, TRUE);
2205         if (!excl && code == CM_ERROR_EXISTS) {
2206             /* not an exclusive create, and someone else tried
2207              * creating it already, then we open it anyway.  We
2208              * don't bother retrying after this, since if this next
2209              * fails, that means that the file was deleted after we
2210              * started this call.
2211              */
2212             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2213                               userp, &req, &scp);
2214             if (code == 0) {
2215                 if (trunc) {
2216                     setAttr.mask = CM_ATTRMASK_LENGTH;
2217                     setAttr.length.LowPart = 0;
2218                     setAttr.length.HighPart = 0;
2219                     code = cm_SetAttr(scp, &setAttr, userp,
2220                                        &req);
2221                 }   
2222             }   /* lookup succeeded */
2223         }
2224     }
2225         
2226     /* we don't need this any longer */
2227     if (dscp) cm_ReleaseSCache(dscp);
2228
2229     if (code) {
2230         /* something went wrong creating or truncating the file */
2231         if (scp) cm_ReleaseSCache(scp);
2232         cm_ReleaseUser(userp);
2233         smb_FreeTran2Packet(outp);
2234         return code;
2235     }
2236         
2237     /* make sure we're about to open a file */
2238     if (scp->fileType != CM_SCACHETYPE_FILE) {
2239         code = 0;
2240         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2241             cm_scache_t * targetScp = 0;
2242             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2243             if (code == 0) {
2244                 /* we have a more accurate file to use (the
2245                 * target of the symbolic link).  Otherwise,
2246                 * we'll just use the symlink anyway.
2247                 */
2248                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2249                           scp, targetScp);
2250                 cm_ReleaseSCache(scp);
2251                 scp = targetScp;
2252             }
2253         }
2254         if (scp->fileType != CM_SCACHETYPE_FILE) {
2255             cm_ReleaseSCache(scp);
2256             cm_ReleaseUser(userp);
2257             smb_FreeTran2Packet(outp);
2258             return CM_ERROR_ISDIR;
2259         }
2260     }
2261
2262     /* now all we have to do is open the file itself */
2263     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2264     osi_assert(fidp);
2265         
2266     /* save a pointer to the vnode */
2267     fidp->scp = scp;
2268         
2269     /* compute open mode */
2270     if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2271     if (openMode == 1 || openMode == 2)
2272         fidp->flags |= SMB_FID_OPENWRITE;
2273
2274     smb_ReleaseFID(fidp);
2275         
2276     cm_Open(scp, 0, userp);
2277
2278     /* copy out remainder of the parms */
2279     parmSlot = 0;
2280     outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2281     lock_ObtainMutex(&scp->mx);
2282     if (extraInfo) {
2283         outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2284         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2285         outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2286         outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2287         outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2288         parmSlot++;
2289         outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2290         parmSlot++;
2291         outp->parmsp[parmSlot] = openMode; parmSlot++;
2292         outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2293         outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2294     }   
2295     /* and the final "always present" stuff */
2296     outp->parmsp[parmSlot] = openAction; parmSlot++;
2297     /* next write out the "unique" ID */
2298     outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2299     outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2300     outp->parmsp[parmSlot] = 0; parmSlot++;
2301     if (returnEALength) {
2302         outp->parmsp[parmSlot] = 0; parmSlot++;
2303         outp->parmsp[parmSlot] = 0; parmSlot++;
2304     }   
2305     lock_ReleaseMutex(&scp->mx);
2306     outp->totalData = 0;                /* total # of data bytes */
2307     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
2308
2309     smb_SendTran2Packet(vcp, outp, op);
2310
2311     smb_FreeTran2Packet(outp);
2312
2313     cm_ReleaseUser(userp);
2314     /* leave scp held since we put it in fidp->scp */
2315     return 0;
2316 }   
2317
2318 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2319 {
2320     osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2321     return CM_ERROR_BADOP;
2322 }
2323
2324 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2325 {
2326     osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2327     return CM_ERROR_BADOP;
2328 }
2329
2330 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2331 {
2332     smb_tran2Packet_t *outp;
2333     smb_tran2QFSInfo_t qi;
2334     int responseSize;
2335     osi_hyper_t temp;
2336     static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2337         
2338     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2339
2340     switch (p->parmsp[0]) {
2341     case 1: responseSize = sizeof(qi.u.allocInfo); break;
2342     case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2343     case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2344     case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2345     case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2346     case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2347     default: return CM_ERROR_INVAL;
2348     }
2349
2350     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2351     switch (p->parmsp[0]) {
2352     case 1:
2353         /* alloc info */
2354         qi.u.allocInfo.FSID = 0;
2355         qi.u.allocInfo.sectorsPerAllocUnit = 1;
2356         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2357         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2358         qi.u.allocInfo.bytesPerSector = 1024;
2359         break;
2360
2361     case 2:
2362         /* volume info */
2363         qi.u.volumeInfo.vsn = 1234;
2364         qi.u.volumeInfo.vnCount = 4;
2365         /* we're supposed to pad it out with zeroes to the end */
2366         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2367         memcpy(qi.u.volumeInfo.label, "AFS", 4);
2368         break;
2369
2370     case 0x102:
2371         /* FS volume info */
2372         memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2373         qi.u.FSvolumeInfo.vsn = 1234;
2374         qi.u.FSvolumeInfo.vnCount = 8;
2375         memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2376         break;
2377
2378     case 0x103:
2379         /* FS size info */
2380         temp.HighPart = 0;
2381         temp.LowPart = 0x7fffffff;
2382         qi.u.FSsizeInfo.totalAllocUnits = temp;
2383         temp.LowPart = 0x3fffffff;
2384         qi.u.FSsizeInfo.availAllocUnits = temp;
2385         qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2386         qi.u.FSsizeInfo.bytesPerSector = 1024;
2387         break;
2388
2389     case 0x104:
2390         /* FS device info */
2391         qi.u.FSdeviceInfo.devType = 0;  /* don't have a number */
2392         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2393         break;
2394
2395         case 0x105:
2396         /* FS attribute info */
2397         /* attributes, defined in WINNT.H:
2398          *      FILE_CASE_SENSITIVE_SEARCH      0x1
2399          *      FILE_CASE_PRESERVED_NAMES       0x2
2400          *      <no name defined>               0x4000
2401          *         If bit 0x4000 is not set, Windows 95 thinks
2402          *         we can't handle long (non-8.3) names,
2403          *         despite our protestations to the contrary.
2404          */
2405         qi.u.FSattributeInfo.attributes = 0x4003;
2406         qi.u.FSattributeInfo.maxCompLength = 255;
2407         qi.u.FSattributeInfo.FSnameLength = 6;
2408         memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2409         break;
2410     }   
2411         
2412     /* copy out return data, and set corresponding sizes */
2413     outp->totalParms = 0;
2414     outp->totalData = responseSize;
2415     memcpy(outp->datap, &qi, responseSize);
2416
2417     /* send and free the packets */
2418     smb_SendTran2Packet(vcp, outp, op);
2419     smb_FreeTran2Packet(outp);
2420
2421     return 0;
2422 }
2423
2424 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2425 {
2426     osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2427     return CM_ERROR_BADOP;
2428 }
2429
2430 struct smb_ShortNameRock {
2431     char *maskp;
2432     unsigned int vnode;
2433     char *shortName;
2434     size_t shortNameLen;
2435 };      
2436
2437 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2438                          osi_hyper_t *offp)
2439 {       
2440     struct smb_ShortNameRock *rockp;
2441     char *shortNameEnd;
2442
2443     rockp = vrockp;
2444     /* compare both names and vnodes, though probably just comparing vnodes
2445      * would be safe enough.
2446      */
2447     if (cm_stricmp(dep->name, rockp->maskp) != 0)
2448         return 0;
2449     if (ntohl(dep->fid.vnode) != rockp->vnode)
2450         return 0;
2451     /* This is the entry */
2452     cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2453     rockp->shortNameLen = shortNameEnd - rockp->shortName;
2454     return CM_ERROR_STOPNOW;
2455 }       
2456
2457 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2458         char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2459 {
2460     struct smb_ShortNameRock rock;
2461     char *lastNamep;
2462     cm_space_t *spacep;
2463     cm_scache_t *dscp;
2464     int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2465     long code = 0;
2466     osi_hyper_t thyper;
2467
2468     spacep = cm_GetSpace();
2469     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2470
2471     code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2472                      reqp, &dscp);
2473     cm_FreeSpace(spacep);
2474     if (code) return code;
2475
2476     if (!lastNamep) lastNamep = pathp;
2477     else lastNamep++;
2478     thyper.LowPart = 0;
2479     thyper.HighPart = 0;
2480     rock.shortName = shortName;
2481     rock.vnode = vnode;
2482     rock.maskp = lastNamep;
2483     code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2484
2485     cm_ReleaseSCache(dscp);
2486
2487     if (code == 0)
2488         return CM_ERROR_NOSUCHFILE;
2489     if (code == CM_ERROR_STOPNOW) {
2490         *shortNameLenp = rock.shortNameLen;
2491         return 0;
2492     }
2493     return code;
2494 }
2495
2496 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2497 {
2498     smb_tran2Packet_t *outp;
2499     time_t dosTime;
2500     FILETIME ft;
2501     unsigned short infoLevel;
2502     int nbytesRequired;
2503     unsigned short attributes;
2504     unsigned long extAttributes;
2505     char shortName[13];
2506     unsigned int len;
2507     cm_user_t *userp;
2508     cm_space_t *spacep;
2509     cm_scache_t *scp, *dscp;
2510     long code = 0;
2511     char *op;
2512     char *tidPathp;
2513     char *lastComp;
2514     cm_req_t req;
2515
2516     cm_InitReq(&req);
2517
2518     infoLevel = p->parmsp[0];
2519     if (infoLevel == 6) nbytesRequired = 0;
2520     else if (infoLevel == 1) nbytesRequired = 22;
2521     else if (infoLevel == 2) nbytesRequired = 26;
2522     else if (infoLevel == 0x101) nbytesRequired = 40;
2523     else if (infoLevel == 0x102) nbytesRequired = 24;
2524     else if (infoLevel == 0x103) nbytesRequired = 4;
2525     else if (infoLevel == 0x108) nbytesRequired = 30;
2526     else {
2527         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2528                   p->opcode, infoLevel);
2529         smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2530         return 0;
2531     }
2532     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2533               osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2534
2535     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2536
2537     if (infoLevel > 0x100)
2538         outp->totalParms = 2;
2539     else
2540         outp->totalParms = 0;
2541     outp->totalData = nbytesRequired;
2542         
2543     /* now, if we're at infoLevel 6, we're only being asked to check
2544      * the syntax, so we just OK things now.  In particular, we're *not*
2545      * being asked to verify anything about the state of any parent dirs.
2546      */
2547     if (infoLevel == 6) {
2548         smb_SendTran2Packet(vcp, outp, opx);
2549         smb_FreeTran2Packet(outp);
2550         return 0;
2551     }   
2552         
2553     userp = smb_GetTran2User(vcp, p);
2554     if (!userp) {
2555         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2556         smb_FreeTran2Packet(outp);
2557         return CM_ERROR_BADSMB;
2558     }
2559
2560     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2561     if(code) {
2562         cm_ReleaseUser(userp);
2563         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2564         smb_FreeTran2Packet(outp);
2565         return 0;
2566     }
2567
2568     /*
2569      * XXX Strange hack XXX
2570      *
2571      * As of Patch 7 (13 January 98), we are having the following problem:
2572      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2573      * requests to look up "desktop.ini" in all the subdirectories.
2574      * This can cause zillions of timeouts looking up non-existent cells
2575      * and volumes, especially in the top-level directory.
2576      *
2577      * We have not found any way to avoid this or work around it except
2578      * to explicitly ignore the requests for mount points that haven't
2579      * yet been evaluated and for directories that haven't yet been
2580      * fetched.
2581      */
2582     if (infoLevel == 0x101) {
2583         spacep = cm_GetSpace();
2584         smb_StripLastComponent(spacep->data, &lastComp,
2585                                 (char *)(&p->parmsp[3]));
2586 #ifndef SPECIAL_FOLDERS
2587         /* Make sure that lastComp is not NULL */
2588         if (lastComp) {
2589             if (stricmp(lastComp, "\\desktop.ini") == 0) {
2590                 code = cm_NameI(cm_rootSCachep, spacep->data,
2591                                  CM_FLAG_CASEFOLD
2592                                  | CM_FLAG_DIRSEARCH
2593                                  | CM_FLAG_FOLLOW,
2594                                  userp, tidPathp, &req, &dscp);
2595                 if (code == 0) {
2596                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2597                          && !dscp->mountRootFidp)
2598                         code = CM_ERROR_NOSUCHFILE;
2599                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2600                         cm_buf_t *bp = buf_Find(dscp, &hzero);
2601                         if (bp)
2602                             buf_Release(bp);
2603                         else
2604                             code = CM_ERROR_NOSUCHFILE;
2605                     }
2606                     cm_ReleaseSCache(dscp);
2607                     if (code) {
2608                         cm_FreeSpace(spacep);
2609                         cm_ReleaseUser(userp);
2610                         smb_SendTran2Error(vcp, p, opx, code);
2611                         smb_FreeTran2Packet(outp);
2612                         return 0;
2613                     }
2614                 }
2615             }
2616         }
2617 #endif /* SPECIAL_FOLDERS */
2618
2619         cm_FreeSpace(spacep);
2620     }
2621
2622     /* now do namei and stat, and copy out the info */
2623     code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2624                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2625
2626     if (code) {
2627         cm_ReleaseUser(userp);
2628         smb_SendTran2Error(vcp, p, opx, code);
2629         smb_FreeTran2Packet(outp);
2630         return 0;
2631     }
2632
2633     lock_ObtainMutex(&scp->mx);
2634     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2635                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2636     if (code) goto done;
2637         
2638     /* now we have the status in the cache entry, and everything is locked.
2639      * Marshall the output data.
2640      */
2641     op = outp->datap;
2642     /* for info level 108, figure out short name */
2643     if (infoLevel == 0x108) {
2644         code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2645                                 tidPathp, scp->fid.vnode, shortName,
2646                                 (size_t *) &len);
2647         if (code) {
2648             goto done;
2649         }
2650
2651         op = outp->datap;
2652         *((u_long *)op) = len * 2; op += 4;
2653         mbstowcs((unsigned short *)op, shortName, len);
2654         op += (len * 2);
2655
2656         goto done;
2657     }
2658     if (infoLevel == 1 || infoLevel == 2) {
2659         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2660         *((u_long *)op) = dosTime; op += 4;     /* creation time */
2661         *((u_long *)op) = dosTime; op += 4;     /* access time */
2662         *((u_long *)op) = dosTime; op += 4;     /* write time */
2663         *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2664         *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2665         attributes = smb_Attributes(scp);
2666         *((u_short *)op) = attributes; op += 2; /* attributes */
2667     }
2668     else if (infoLevel == 0x101) {
2669         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2670         *((FILETIME *)op) = ft; op += 8;        /* creation time */
2671         *((FILETIME *)op) = ft; op += 8;        /* last access time */
2672         *((FILETIME *)op) = ft; op += 8;        /* last write time */
2673         *((FILETIME *)op) = ft; op += 8;        /* last change time */
2674         extAttributes = smb_ExtAttributes(scp);
2675         *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2676         *((u_long *)op) = 0; op += 4;   /* don't know what this is */
2677     }
2678     else if (infoLevel == 0x102) {
2679         *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
2680         *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
2681         *((u_long *)op) = scp->linkCount; op += 4;
2682         *op++ = 0;
2683         *op++ = 0;
2684         *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2685         *op++ = 0;
2686     }
2687     else if (infoLevel == 0x103) {
2688         memset(op, 0, 4); op += 4;      /* EA size */
2689     }
2690
2691     /* now, if we are being asked about extended attrs, return a 0 size */
2692     if (infoLevel == 2) {
2693         *((u_long *)op) = 0; op += 4;
2694     }
2695
2696
2697     /* send and free the packets */
2698   done:
2699     lock_ReleaseMutex(&scp->mx);
2700     cm_ReleaseSCache(scp);
2701     cm_ReleaseUser(userp);
2702     if (code == 0) 
2703         smb_SendTran2Packet(vcp, outp, opx);
2704     else 
2705         smb_SendTran2Error(vcp, p, opx, code);
2706     smb_FreeTran2Packet(outp);
2707
2708     return 0;
2709 }
2710
2711 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2712 {
2713     osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2714     return CM_ERROR_BADOP;
2715 }
2716
2717 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2718 {
2719     smb_tran2Packet_t *outp;
2720     FILETIME ft;
2721     unsigned long attributes;
2722     unsigned short infoLevel;
2723     int nbytesRequired;
2724     unsigned short fid;
2725     cm_user_t *userp;
2726     smb_fid_t *fidp;
2727     cm_scache_t *scp;
2728     char *op;
2729     long code = 0;
2730     cm_req_t req;
2731
2732     cm_InitReq(&req);
2733
2734     fid = p->parmsp[0];
2735     fidp = smb_FindFID(vcp, fid, 0);
2736
2737     if (fidp == NULL) {
2738         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2739         return 0;
2740     }
2741
2742     infoLevel = p->parmsp[1];
2743     if (infoLevel == 0x101) nbytesRequired = 40;
2744     else if (infoLevel == 0x102) nbytesRequired = 24;
2745     else if (infoLevel == 0x103) nbytesRequired = 4;
2746     else if (infoLevel == 0x104) nbytesRequired = 6;
2747     else {
2748         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2749                   p->opcode, infoLevel);
2750         smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2751         smb_ReleaseFID(fidp);
2752         return 0;
2753     }
2754     osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2755
2756     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2757
2758     if (infoLevel > 0x100)
2759         outp->totalParms = 2;
2760     else
2761         outp->totalParms = 0;
2762     outp->totalData = nbytesRequired;
2763
2764     userp = smb_GetTran2User(vcp, p);
2765     if (!userp) {
2766         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2767         code = CM_ERROR_BADSMB;
2768         goto done;
2769     }   
2770
2771     scp = fidp->scp;
2772     lock_ObtainMutex(&scp->mx);
2773     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2774                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2775     if (code) 
2776         goto done;
2777
2778     /* now we have the status in the cache entry, and everything is locked.
2779      * Marshall the output data.
2780      */
2781     op = outp->datap;
2782     if (infoLevel == 0x101) {
2783         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2784         *((FILETIME *)op) = ft; op += 8;        /* creation time */
2785         *((FILETIME *)op) = ft; op += 8;        /* last access time */
2786         *((FILETIME *)op) = ft; op += 8;        /* last write time */
2787         *((FILETIME *)op) = ft; op += 8;        /* last change time */
2788         attributes = smb_ExtAttributes(scp);
2789         *((u_long *)op) = attributes; op += 4;
2790         *((u_long *)op) = 0; op += 4;
2791     }
2792     else if (infoLevel == 0x102) {
2793         *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
2794         *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
2795         *((u_long *)op) = scp->linkCount; op += 4;
2796         *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2797         *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2798         *op++ = 0;
2799         *op++ = 0;
2800     }
2801     else if (infoLevel == 0x103) {
2802         *((u_long *)op) = 0; op += 4;
2803     }
2804     else if (infoLevel == 0x104) {
2805         unsigned long len;
2806         char *name;
2807
2808         if (fidp->NTopen_wholepathp)
2809             name = fidp->NTopen_wholepathp;
2810         else
2811             name = "\\";        /* probably can't happen */
2812         len = strlen(name);
2813         outp->totalData = (len*2) + 4;  /* this is actually what we want to return */
2814         *((u_long *)op) = len * 2; op += 4;
2815         mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2816     }
2817
2818     /* send and free the packets */
2819   done:
2820     lock_ReleaseMutex(&scp->mx);
2821     cm_ReleaseUser(userp);
2822     smb_ReleaseFID(fidp);
2823     if (code == 0) 
2824         smb_SendTran2Packet(vcp, outp, opx);
2825     else 
2826         smb_SendTran2Error(vcp, p, opx, code);
2827     smb_FreeTran2Packet(outp);
2828
2829     return 0;
2830 }       
2831
2832 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2833 {
2834     long code = 0;
2835     unsigned short fid;
2836     smb_fid_t *fidp;
2837     unsigned short infoLevel;
2838     smb_tran2Packet_t *outp;
2839     cm_user_t *userp;
2840     cm_scache_t *scp;
2841     cm_req_t req;
2842
2843     cm_InitReq(&req);
2844
2845     fid = p->parmsp[0];
2846     fidp = smb_FindFID(vcp, fid, 0);
2847
2848     if (fidp == NULL) {
2849         smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2850         return 0;
2851     }
2852
2853     infoLevel = p->parmsp[1];
2854     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2855     if (infoLevel > 0x104 || infoLevel < 0x101) {
2856         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2857                   p->opcode, infoLevel);
2858         smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2859         smb_ReleaseFID(fidp);
2860         return 0;
2861     }
2862
2863     if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2864         smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2865         smb_ReleaseFID(fidp);
2866         return 0;
2867     }
2868     if ((infoLevel == 0x103 || infoLevel == 0x104)
2869          && !(fidp->flags & SMB_FID_OPENWRITE)) {
2870         smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2871         smb_ReleaseFID(fidp);
2872         return 0;
2873     }
2874
2875     osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2876
2877     outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2878
2879     outp->totalParms = 2;
2880     outp->totalData = 0;
2881
2882     userp = smb_GetTran2User(vcp, p);
2883     if (!userp) {
2884         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2885         code = CM_ERROR_BADSMB;
2886         goto done;
2887     }   
2888
2889     scp = fidp->scp;
2890
2891     if (infoLevel == 0x101) {
2892         FILETIME lastMod;
2893         unsigned int attribute;
2894         cm_attr_t attr;
2895
2896         /* lock the vnode with a callback; we need the current status
2897          * to determine what the new status is, in some cases.
2898          */
2899         lock_ObtainMutex(&scp->mx);
2900         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2901                           CM_SCACHESYNC_GETSTATUS
2902                          | CM_SCACHESYNC_NEEDCALLBACK);
2903         if (code) {
2904             lock_ReleaseMutex(&scp->mx);
2905             goto done;
2906         }
2907
2908         /* prepare for setattr call */
2909         attr.mask = 0;
2910
2911         lastMod = *((FILETIME *)(p->datap + 16));
2912         /* when called as result of move a b, lastMod is (-1, -1). 
2913          * If the check for -1 is not present, timestamp
2914          * of the resulting file will be 1969 (-1)
2915          */
2916         if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
2917              lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2918             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2919             smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2920                                              &lastMod);
2921             fidp->flags |= SMB_FID_MTIMESETDONE;
2922         }
2923                 
2924         attribute = *((u_long *)(p->datap + 32));
2925         if (attribute != 0) {
2926             if ((scp->unixModeBits & 0222)
2927                  && (attribute & 1) != 0) {
2928                 /* make a writable file read-only */
2929                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2930                 attr.unixModeBits = scp->unixModeBits & ~0222;
2931             }
2932             else if ((scp->unixModeBits & 0222) == 0
2933                       && (attribute & 1) == 0) {
2934                 /* make a read-only file writable */
2935                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2936                 attr.unixModeBits = scp->unixModeBits | 0222;
2937             }
2938         }
2939         lock_ReleaseMutex(&scp->mx);
2940
2941         /* call setattr */
2942         if (attr.mask)
2943             code = cm_SetAttr(scp, &attr, userp, &req);
2944         else
2945             code = 0;
2946     }               
2947     else if (infoLevel == 0x103 || infoLevel == 0x104) {
2948         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2949         cm_attr_t attr;
2950
2951         attr.mask = CM_ATTRMASK_LENGTH;
2952         attr.length.LowPart = size.LowPart;
2953         attr.length.HighPart = size.HighPart;
2954         code = cm_SetAttr(scp, &attr, userp, &req);
2955     }       
2956     else if (infoLevel == 0x102) {
2957         if (*((char *)(p->datap))) {
2958             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2959                                      &req);
2960             if (code == 0)          
2961                 fidp->flags |= SMB_FID_DELONCLOSE;
2962         }               
2963         else {  
2964             code = 0;
2965             fidp->flags &= ~SMB_FID_DELONCLOSE;
2966         }
2967     }       
2968
2969   done:
2970     cm_ReleaseUser(userp);
2971     smb_ReleaseFID(fidp);
2972     if (code == 0) 
2973         smb_SendTran2Packet(vcp, outp, op);
2974     else 
2975         smb_SendTran2Error(vcp, p, op, code);
2976     smb_FreeTran2Packet(outp);
2977
2978     return 0;
2979 }
2980
2981 long 
2982 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2983 {
2984     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
2985     return CM_ERROR_BADOP;
2986 }
2987
2988 long 
2989 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2990 {
2991     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
2992     return CM_ERROR_BADOP;
2993 }
2994
2995 long 
2996 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2997 {
2998     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
2999     return CM_ERROR_BADOP;
3000 }
3001
3002 long 
3003 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3004 {
3005     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3006     return CM_ERROR_BADOP;
3007 }
3008
3009 long 
3010 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3011 {
3012     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3013     return CM_ERROR_BADOP;
3014 }
3015
3016 long 
3017 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3018 {
3019     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3020     return CM_ERROR_BADOP;
3021 }
3022
3023 long 
3024 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3025 {
3026     osi_Log0(smb_logp,"ReceiveTran2GetDFSReferral - NOT_SUPPORTED");
3027     return CM_ERROR_BADOP;
3028 }
3029
3030 long 
3031 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3032 {
3033     osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3034     return CM_ERROR_BADOP;
3035 }
3036
3037 long 
3038 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3039         smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3040         cm_req_t *reqp)
3041 {
3042     long code = 0;
3043     cm_scache_t *scp;
3044     cm_scache_t *targetScp;                     /* target if scp is a symlink */
3045     char *dptr;
3046     time_t dosTime;
3047     FILETIME ft;
3048     int shortTemp;
3049     unsigned short attr;
3050     unsigned long lattr;
3051     smb_dirListPatch_t *patchp;
3052     smb_dirListPatch_t *npatchp;
3053         
3054     for(patchp = *dirPatchespp; patchp; patchp =
3055          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3056                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3057         if (code) continue;
3058         lock_ObtainMutex(&scp->mx);
3059         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3060                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3061         if (code) { 
3062             lock_ReleaseMutex(&scp->mx);
3063             cm_ReleaseSCache(scp);
3064
3065             dptr = patchp->dptr;
3066
3067             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3068                errors in the client. */
3069             if (infoLevel >= 0x101) {
3070                 /* 1969-12-31 23:59:59 +00 */
3071                 ft.dwHighDateTime = 0x19DB200;
3072                 ft.dwLowDateTime = 0x5BB78980;
3073
3074                 /* copy to Creation Time */
3075                 *((FILETIME *)dptr) = ft;
3076                 dptr += 8;
3077
3078                 /* copy to Last Access Time */
3079                 *((FILETIME *)dptr) = ft;
3080                 dptr += 8;
3081
3082                 /* copy to Last Write Time */
3083                 *((FILETIME *)dptr) = ft;
3084                 dptr += 8;
3085
3086                 /* copy to Change Time */
3087                 *((FILETIME *)dptr) = ft;
3088                 dptr += 24;
3089
3090                 /* merge in hidden attribute */
3091                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3092                     *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3093                 }
3094                 dptr += 4;
3095             } else {
3096                 /* 1969-12-31 23:59:58 +00*/
3097                 dosTime = 0xEBBFBF7D;
3098
3099                 /* and copy out date */
3100                 shortTemp = (dosTime>>16) & 0xffff;
3101                 *((u_short *)dptr) = shortTemp;
3102                 dptr += 2;
3103
3104                 /* copy out creation time */
3105                 shortTemp = dosTime & 0xffff;
3106                 *((u_short *)dptr) = shortTemp;
3107                 dptr += 2;
3108
3109                 /* and copy out date */
3110                 shortTemp = (dosTime>>16) & 0xffff;
3111                 *((u_short *)dptr) = shortTemp;
3112                 dptr += 2;
3113                         
3114                 /* copy out access time */
3115                 shortTemp = dosTime & 0xffff;
3116                 *((u_short *)dptr) = shortTemp;
3117                 dptr += 2;
3118
3119                 /* and copy out date */
3120                 shortTemp = (dosTime>>16) & 0xffff;
3121                 *((u_short *)dptr) = shortTemp;
3122                 dptr += 2;
3123                         
3124                 /* copy out mod time */
3125                 shortTemp = dosTime & 0xffff;
3126                 *((u_short *)dptr) = shortTemp;
3127                 dptr += 10;
3128
3129                 /* merge in hidden (dot file) attribute */
3130                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3131                     attr = SMB_ATTR_HIDDEN;
3132                     *dptr++ = attr & 0xff;
3133                     *dptr++ = (attr >> 8) & 0xff;
3134                 }       
3135             }
3136             continue;
3137         }
3138                 
3139         /* now watch for a symlink */
3140         code = 0;
3141         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3142             lock_ReleaseMutex(&scp->mx);
3143             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3144             if (code == 0) {
3145                 /* we have a more accurate file to use (the
3146                  * target of the symbolic link).  Otherwise,
3147                  * we'll just use the symlink anyway.
3148                  */
3149                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3150                           scp, targetScp);
3151                 cm_ReleaseSCache(scp);
3152                 scp = targetScp;
3153             }
3154             lock_ObtainMutex(&scp->mx);
3155         }
3156
3157         dptr = patchp->dptr;
3158
3159         if (infoLevel >= 0x101) {
3160             /* get filetime */
3161             smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3162
3163             /* copy to Creation Time */
3164             *((FILETIME *)dptr) = ft;
3165             dptr += 8;
3166
3167             /* copy to Last Access Time */
3168             *((FILETIME *)dptr) = ft;
3169             dptr += 8;
3170
3171             /* copy to Last Write Time */
3172             *((FILETIME *)dptr) = ft;
3173             dptr += 8;
3174
3175             /* copy to Change Time */
3176             *((FILETIME *)dptr) = ft;
3177             dptr += 8;
3178
3179             /* Use length for both file length and alloc length */
3180             *((LARGE_INTEGER *)dptr) = scp->length;
3181             dptr += 8;
3182             *((LARGE_INTEGER *)dptr) = scp->length;
3183             dptr += 8;
3184
3185             /* Copy attributes */
3186             lattr = smb_ExtAttributes(scp);
3187             /* merge in hidden (dot file) attribute */
3188             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3189                 lattr |= SMB_ATTR_HIDDEN;
3190             *((u_long *)dptr) = lattr;
3191             dptr += 4;
3192         }
3193         else {
3194             /* get dos time */
3195             smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3196
3197             /* and copy out date */
3198             shortTemp = (dosTime>>16) & 0xffff;
3199             *((u_short *)dptr) = shortTemp;
3200             dptr += 2;
3201
3202             /* copy out creation time */
3203             shortTemp = dosTime & 0xffff;
3204             *((u_short *)dptr) = shortTemp;
3205             dptr += 2;
3206
3207             /* and copy out date */
3208             shortTemp = (dosTime>>16) & 0xffff;
3209             *((u_short *)dptr) = shortTemp;
3210             dptr += 2;
3211
3212             /* copy out access time */
3213             shortTemp = dosTime & 0xffff;
3214             *((u_short *)dptr) = shortTemp;
3215             dptr += 2;
3216
3217             /* and copy out date */
3218             shortTemp = (dosTime>>16) & 0xffff;
3219             *((u_short *)dptr) = shortTemp;
3220             dptr += 2;
3221
3222             /* copy out mod time */
3223             shortTemp = dosTime & 0xffff;
3224             *((u_short *)dptr) = shortTemp;
3225             dptr += 2;
3226
3227             /* copy out file length and alloc length,
3228              * using the same for both
3229              */
3230             *((u_long *)dptr) = scp->length.LowPart;
3231             dptr += 4;
3232             *((u_long *)dptr) = scp->length.LowPart;
3233             dptr += 4;
3234
3235             /* finally copy out attributes as short */
3236             attr = smb_Attributes(scp);
3237             /* merge in hidden (dot file) attribute */
3238             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3239                 attr |= SMB_ATTR_HIDDEN;
3240             *dptr++ = attr & 0xff;
3241             *dptr++ = (attr >> 8) & 0xff;
3242         }
3243
3244         lock_ReleaseMutex(&scp->mx);
3245         cm_ReleaseSCache(scp);
3246     }
3247         
3248     /* now free the patches */
3249     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3250         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3251         free(patchp);
3252     }
3253         
3254     /* and mark the list as empty */
3255     *dirPatchespp = NULL;
3256
3257     return code;
3258 }
3259
3260 #ifndef USE_OLD_MATCHING
3261 // char table for case insensitive comparison
3262 char mapCaseTable[256];
3263
3264 VOID initUpperCaseTable(VOID) 
3265 {
3266     int i;
3267     for (i = 0; i < 256; ++i) 
3268        mapCaseTable[i] = toupper(i);
3269     // make '"' match '.' 
3270     mapCaseTable[(int)'"'] = toupper('.');
3271     // make '<' match '*' 
3272     mapCaseTable[(int)'<'] = toupper('*');
3273     // make '>' match '?' 
3274     mapCaseTable[(int)'>'] = toupper('?');    
3275 }
3276
3277 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3278 // name 'name'.
3279 // Note : this procedure works recursively calling itself.
3280 // Parameters
3281 // PSZ pattern    : string containing metacharacters.
3282 // PSZ name       : file name to be compared with 'pattern'.
3283 // Return value
3284 // BOOL : TRUE/FALSE (match/mistmatch)
3285
3286 BOOL 
3287 szWildCardMatchFileName(PSZ pattern, PSZ name) 
3288 {
3289     PSZ pename;         // points to the last 'name' character
3290     PSZ p;
3291     pename = name + strlen(name) - 1;
3292     while (*name) {
3293         switch (*pattern) {
3294         case '?':
3295             if (*name == '.') 
3296                 return FALSE;
3297             ++pattern, ++name;
3298             break;
3299          case '*':
3300             ++pattern;
3301             if (*pattern == '\0')
3302                 return TRUE;
3303             for (p = pename; p >= name; --p) {
3304                 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3305                      szWildCardMatchFileName(pattern + 1, p + 1))
3306                     return TRUE;
3307             } /* endfor */
3308             return FALSE;
3309         default:
3310             if (mapCaseTable[*name] != mapCaseTable[*pattern]) 
3311                 return FALSE;
3312             ++pattern, ++name;
3313             break;
3314         } /* endswitch */
3315     } /* endwhile */ 
3316
3317     if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
3318         return TRUE;
3319     else 
3320         return FALSE;
3321 }
3322
3323 /* do a case-folding search of the star name mask with the name in namep.
3324  * Return 1 if we match, otherwise 0.
3325  */
3326 int smb_V3MatchMask(char *namep, char *maskp, int flags) 
3327 {
3328     char * newmask;
3329     int    i, j, star, qmark, retval;
3330
3331     /* make sure we only match 8.3 names, if requested */
3332     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
3333         return 0;
3334     
3335     /* optimize the pattern:
3336      * if there is a mixture of '?' and '*',
3337      * for example  the sequence "*?*?*?*"
3338      * must be turned into the form "*"
3339      */
3340     newmask = (char *)malloc(strlen(maskp)+1);
3341     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3342         switch ( maskp[i] ) {
3343         case '?':
3344         case '>':
3345             qmark++;
3346             break;
3347         case '<':
3348         case '*':
3349             star++;
3350             break;
3351         default:
3352             if ( star ) {
3353                 newmask[j++] = '*';
3354             } else if ( qmark ) {
3355                 while ( qmark-- )
3356                     newmask[j++] = '?';
3357             }
3358             newmask[j++] = maskp[i];
3359             star = 0;
3360             qmark = 0;
3361         }
3362     }
3363     if ( star ) {
3364         newmask[j++] = '*';
3365     } else if ( qmark ) {
3366         while ( qmark-- )
3367             newmask[j++] = '?';
3368     }
3369     newmask[j++] = '\0';
3370
3371     retval = szWildCardMatchFileName(newmask, namep) ? 1:0;
3372
3373     free(newmask);
3374     return retval;
3375 }
3376
3377 #else /* USE_OLD_MATCHING */
3378 /* do a case-folding search of the star name mask with the name in namep.
3379  * Return 1 if we match, otherwise 0.
3380  */
3381 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3382 {
3383     unsigned char tcp1, tcp2;   /* Pattern characters */
3384     unsigned char tcn1;         /* Name characters */
3385     int sawDot = 0, sawStar = 0, req8dot3 = 0;
3386     char *starNamep, *starMaskp;
3387     static char nullCharp[] = {0};
3388     int casefold = flags & CM_FLAG_CASEFOLD;
3389
3390     /* make sure we only match 8.3 names, if requested */
3391     req8dot3 = (flags & CM_FLAG_8DOT3);
3392     if (req8dot3 && !cm_Is8Dot3(namep)) 
3393         return 0;
3394
3395     /* loop */
3396     while (1) {
3397         /* Next pattern character */
3398         tcp1 = *maskp++;
3399
3400         /* Next name character */
3401         tcn1 = *namep;
3402
3403         if (tcp1 == 0) {
3404             /* 0 - end of pattern */
3405             if (tcn1 == 0)
3406                 return 1;
3407             else
3408                 return 0;
3409         }
3410         else if (tcp1 == '.' || tcp1 == '"') {
3411             if (sawDot) {
3412                 if (tcn1 == '.') {
3413                     namep++;
3414                     continue;
3415                 } else
3416                     return 0;
3417             }
3418             else {
3419                 /*
3420                  * first dot in pattern;
3421                  * must match dot or end of name
3422                  */
3423                 sawDot = 1;
3424                 if (tcn1 == 0)
3425                     continue;
3426                 else if (tcn1 == '.') {
3427                     sawStar = 0;
3428                     namep++;
3429                     continue;
3430                 }
3431                 else
3432                     return 0;
3433             }
3434         }
3435         else if (tcp1 == '?') {
3436             if (tcn1 == 0 || tcn1 == '.')
3437                 return 0;
3438             namep++;
3439             continue;
3440         }
3441         else if (tcp1 == '>') {
3442             if (tcn1 != 0 && tcn1 != '.')
3443                 namep++;
3444             continue;
3445         }
3446         else if (tcp1 == '*' || tcp1 == '<') {
3447             tcp2 = *maskp++;
3448             if (tcp2 == 0)
3449                 return 1;
3450             else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3451                 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3452                     tcn1 = *++namep;
3453                 if (tcn1 == 0) {
3454                     if (sawDot)
3455                         return 0;
3456                     else
3457                         continue;
3458                 }
3459                 else {
3460                     namep++;
3461                     continue;
3462                 }
3463             }
3464             else {
3465                 /*
3466                  * pattern character after '*' is not null or
3467                  * period.  If it is '?' or '>', we are not
3468                  * going to understand it.  If it is '*' or
3469                  * '<', we are going to skip over it.  None of
3470                  * these are likely, I hope.
3471                  */
3472                 /* skip over '*' and '<' */
3473                 while (tcp2 == '*' || tcp2 == '<')
3474                     tcp2 = *maskp++;
3475
3476                 /* skip over characters that don't match tcp2 */
3477                 while (req8dot3 && tcn1 != '.' && tcn1 != 0 && 
3478                         ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
3479                           (!casefold && tcn1 != tcp2)))
3480                     tcn1 = *++namep;
3481
3482                 /* No match */
3483                 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3484                     return 0;
3485
3486                 /* Remember where we are */
3487                 sawStar = 1;
3488                 starMaskp = maskp;
3489                 starNamep = namep;
3490
3491                 namep++;
3492                 continue;
3493             }
3494         }
3495         else {
3496             /* tcp1 is not a wildcard */
3497             if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
3498                  (!casefold && tcn1 == tcp1)) {
3499                 /* they match */
3500                 namep++;
3501                 continue;
3502             }
3503             /* if trying to match a star pattern, go back */
3504             if (sawStar) {
3505                 maskp = starMaskp - 2;
3506                 namep = starNamep + 1;
3507                 sawStar = 0;
3508                 continue;
3509             }
3510             /* that's all */
3511             return 0;
3512         }
3513     }
3514 }
3515 #endif /* USE_OLD_MATCHING */
3516
3517 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3518 {
3519     int attribute;
3520     long nextCookie;
3521     char *tp;
3522     long code = 0;
3523     char *pathp;
3524     cm_dirEntry_t *dep;
3525     int maxCount;
3526     smb_dirListPatch_t *dirListPatchesp;
3527     smb_dirListPatch_t *curPatchp;
3528     cm_buf_t *bufferp;
3529     long temp;
3530     long orbytes;                       /* # of bytes in this output record */
3531     long ohbytes;                       /* # of bytes, except file name */
3532     long onbytes;                       /* # of bytes in name, incl. term. null */
3533     osi_hyper_t dirLength;
3534     osi_hyper_t bufferOffset;
3535     osi_hyper_t curOffset;
3536     osi_hyper_t thyper;
3537     smb_dirSearch_t *dsp;
3538     cm_scache_t *scp;
3539     long entryInDir;
3540     long entryInBuffer;
3541     cm_pageHeader_t *pageHeaderp;
3542     cm_user_t *userp = NULL;
3543     int slotInPage;
3544     int returnedNames;
3545     long nextEntryCookie;
3546     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
3547     char *op;                   /* output data ptr */
3548     char *origOp;                       /* original value of op */
3549     cm_space_t *spacep;         /* for pathname buffer */
3550     long maxReturnData;         /* max # of return data */
3551     long maxReturnParms;                /* max # of return parms */
3552     long bytesInBuffer;         /* # data bytes in the output buffer */
3553     int starPattern;
3554     char *maskp;                        /* mask part of path */
3555     int infoLevel;
3556     int searchFlags;
3557     int eos;
3558     smb_tran2Packet_t *outp;    /* response packet */
3559     char *tidPathp;
3560     int align;
3561     char shortName[13];         /* 8.3 name if needed */
3562     int NeedShortName;
3563     int foundInexact;
3564     char *shortNameEnd;
3565     int fileType;
3566     cm_fid_t fid;
3567     cm_req_t req;
3568
3569     cm_InitReq(&req);
3570
3571     eos = 0;
3572     if (p->opcode == 1) {
3573         /* find first; obtain basic parameters from request */
3574         attribute = p->parmsp[0];
3575         maxCount = p->parmsp[1];
3576         infoLevel = p->parmsp[3];
3577         searchFlags = p->parmsp[2];
3578         dsp = smb_NewDirSearch(1);
3579         dsp->attribute = attribute;
3580         pathp = ((char *) p->parmsp) + 12;      /* points to path */
3581         nextCookie = 0;
3582         maskp = strrchr(pathp, '\\');
3583         if (maskp == NULL) 
3584             maskp = pathp;
3585         else 
3586             maskp++;    /* skip over backslash */
3587         strcpy(dsp->mask, maskp);       /* and save mask */
3588         /* track if this is likely to match a lot of entries */
3589         starPattern = smb_V3IsStarMask(maskp);
3590     }
3591     else {
3592         osi_assert(p->opcode == 2);
3593         /* find next; obtain basic parameters from request or open dir file */
3594         dsp = smb_FindDirSearch(p->parmsp[0]);
3595         if (!dsp) 
3596             return CM_ERROR_BADFD;
3597         attribute = dsp->attribute;
3598         maxCount = p->parmsp[1];
3599         infoLevel = p->parmsp[2];
3600         searchFlags = p->parmsp[5];
3601         pathp = NULL;
3602         nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3603         maskp = dsp->mask;
3604         starPattern = 1;        /* assume, since required a Find Next */
3605     }
3606
3607     osi_Log4(smb_logp,
3608               "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3609               attribute, infoLevel, maxCount, searchFlags);
3610
3611     osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3612               p->opcode, nextCookie);
3613
3614     if (infoLevel >= 0x101)
3615         searchFlags &= ~4;      /* no resume keys */
3616
3617     dirListPatchesp = NULL;
3618
3619     maxReturnData = p->maxReturnData;
3620     if (p->opcode == 1) /* find first */
3621         maxReturnParms = 10;    /* bytes */
3622     else    
3623         maxReturnParms = 8;     /* bytes */
3624
3625 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3626     if (maxReturnData > 6000) 
3627         maxReturnData = 6000;
3628 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3629
3630     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3631                                       maxReturnData);
3632
3633     osi_Log1(smb_logp, "T2 receive search dir %s",
3634              osi_LogSaveString(smb_logp, pathp));
3635         
3636     /* bail out if request looks bad */
3637     if (p->opcode == 1 && !pathp) {
3638         smb_ReleaseDirSearch(dsp);
3639         smb_FreeTran2Packet(outp);
3640         return CM_ERROR_BADSMB;
3641     }
3642         
3643     osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3644              nextCookie, dsp->cookie);
3645
3646     userp = smb_GetTran2User(vcp, p);
3647     if (!userp) {
3648         osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3649         smb_ReleaseDirSearch(dsp);
3650         smb_FreeTran2Packet(outp);
3651         return CM_ERROR_BADSMB;
3652     }
3653
3654     /* try to get the vnode for the path name next */
3655     lock_ObtainMutex(&dsp->mx);
3656     if (dsp->scp) {
3657         scp = dsp->scp;
3658         cm_HoldSCache(scp);
3659         code = 0;
3660     }
3661     else {
3662         spacep = cm_GetSpace();
3663         smb_StripLastComponent(spacep->data, NULL, pathp);
3664         code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3665         if (code) {
3666             lock_ReleaseMutex(&dsp->mx);
3667             cm_ReleaseUser(userp);
3668             smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3669             smb_FreeTran2Packet(outp);
3670             smb_DeleteDirSearch(dsp);
3671             smb_ReleaseDirSearch(dsp);
3672             return 0;
3673         }
3674         code = cm_NameI(cm_rootSCachep, spacep->data,
3675                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3676                         userp, tidPathp, &req, &scp);
3677         cm_FreeSpace(spacep);
3678
3679         if (code == 0) {
3680             if (dsp->scp != 0) 
3681                 cm_ReleaseSCache(dsp->scp);
3682             dsp->scp = scp;
3683             /* we need one hold for the entry we just stored into,
3684              * and one for our own processing.  When we're done
3685              * with this function, we'll drop the one for our own
3686              * processing.  We held it once from the namei call,
3687              * and so we do another hold now.
3688              */
3689             cm_HoldSCache(scp);
3690             lock_ObtainMutex(&scp->mx);
3691             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3692                  LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3693                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3694                 dsp->flags |= SMB_DIRSEARCH_BULKST;
3695             }
3696             lock_ReleaseMutex(&scp->mx);
3697         }       
3698     }
3699     lock_ReleaseMutex(&dsp->mx);
3700     if (code) {
3701         cm_ReleaseUser(userp);
3702         smb_FreeTran2Packet(outp);
3703         smb_DeleteDirSearch(dsp);
3704         smb_ReleaseDirSearch(dsp);
3705         return code;
3706     }
3707
3708     /* get the directory size */
3709     lock_ObtainMutex(&scp->mx);
3710     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3711                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3712     if (code) {
3713         lock_ReleaseMutex(&scp->mx);
3714         cm_ReleaseSCache(scp);
3715         cm_ReleaseUser(userp);
3716         smb_FreeTran2Packet(outp);
3717         smb_DeleteDirSearch(dsp);
3718         smb_ReleaseDirSearch(dsp);
3719         return code;
3720     }
3721
3722   startsearch:
3723     dirLength = scp->length;
3724     bufferp = NULL;
3725     bufferOffset.LowPart = bufferOffset.HighPart = 0;
3726     curOffset.HighPart = 0;
3727     curOffset.LowPart = nextCookie;
3728     origOp = outp->datap;
3729
3730     foundInexact = 0;
3731     code = 0;
3732     returnedNames = 0;
3733     bytesInBuffer = 0;
3734     while (1) {
3735         op = origOp;
3736         if (searchFlags & 4)
3737             /* skip over resume key */
3738             op += 4;
3739
3740         /* make sure that curOffset.LowPart doesn't point to the first
3741          * 32 bytes in the 2nd through last dir page, and that it doesn't
3742          * point at the first 13 32-byte chunks in the first dir page,
3743          * since those are dir and page headers, and don't contain useful
3744          * information.
3745          */
3746         temp = curOffset.LowPart & (2048-1);
3747         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3748             /* we're in the first page */
3749             if (temp < 13*32) temp = 13*32;
3750         }
3751         else {
3752             /* we're in a later dir page */
3753             if (temp < 32) temp = 32;
3754         }
3755                 
3756         /* make sure the low order 5 bits are zero */
3757         temp &= ~(32-1);
3758                 
3759         /* now put temp bits back ito curOffset.LowPart */
3760         curOffset.LowPart &= ~(2048-1);
3761         curOffset.LowPart |= temp;
3762
3763         /* check if we've passed the dir's EOF */
3764         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
3765             eos = 1;
3766             break;
3767         }
3768
3769         /* check if we've returned all the names that will fit in the
3770          * response packet; we check return count as well as the number
3771          * of bytes requested.  We check the # of bytes after we find
3772          * the dir entry, since we'll need to check its size.
3773          */
3774         if (returnedNames >= maxCount) {
3775             break;
3776         }
3777
3778         /* see if we can use the bufferp we have now; compute in which
3779          * page the current offset would be, and check whether that's
3780          * the offset of the buffer we have.  If not, get the buffer.
3781          */
3782         thyper.HighPart = curOffset.HighPart;
3783         thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3784         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3785             /* wrong buffer */
3786             if (bufferp) {
3787                 buf_Release(bufferp);
3788                 bufferp = NULL;
3789             }       
3790             lock_ReleaseMutex(&scp->mx);
3791             lock_ObtainRead(&scp->bufCreateLock);
3792             code = buf_Get(scp, &thyper, &bufferp);
3793             lock_ReleaseRead(&scp->bufCreateLock);
3794             lock_ObtainMutex(&dsp->mx);
3795
3796             /* now, if we're doing a star match, do bulk fetching
3797              * of all of the status info for files in the dir.
3798              */
3799             if (starPattern) {
3800                 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
3801                                            infoLevel, userp,
3802                                            &req);
3803                 lock_ObtainMutex(&scp->mx);
3804                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
3805                     LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
3806                     /* Don't bulk stat if risking timeout */
3807                     int now = GetCurrentTime();
3808                     if (now - req.startTime > 5000) {
3809                         scp->bulkStatProgress = thyper;
3810                         scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3811                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3812                     } else
3813                         cm_TryBulkStat(scp, &thyper, userp, &req);
3814                 }
3815             } else {
3816                 lock_ObtainMutex(&scp->mx);
3817             }
3818             lock_ReleaseMutex(&dsp->mx);
3819             if (code) 
3820                 break;
3821
3822             bufferOffset = thyper;
3823
3824             /* now get the data in the cache */
3825             while (1) {
3826                 code = cm_SyncOp(scp, bufferp, userp, &req,
3827                                  PRSFS_LOOKUP,
3828                                  CM_SCACHESYNC_NEEDCALLBACK
3829                                  | CM_SCACHESYNC_READ);
3830                 if (code) break;
3831                                 
3832                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3833
3834                 /* otherwise, load the buffer and try again */
3835                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3836                                     &req);
3837                 if (code) break;
3838             }
3839             if (code) {
3840                 buf_Release(bufferp);
3841                 bufferp = NULL;
3842                 break;
3843             }
3844         }       /* if (wrong buffer) ... */
3845                 
3846         /* now we have the buffer containing the entry we're interested
3847          * in; copy it out if it represents a non-deleted entry.
3848          */
3849         entryInDir = curOffset.LowPart & (2048-1);
3850         entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3851
3852         /* page header will help tell us which entries are free.  Page
3853          * header can change more often than once per buffer, since
3854          * AFS 3 dir page size may be less than (but not more than)
3855          * a buffer package buffer.
3856          */
3857         /* only look intra-buffer */
3858         temp = curOffset.LowPart & (buf_bufferSize - 1);
3859         temp &= ~(2048 - 1);    /* turn off intra-page bits */
3860         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3861
3862         /* now determine which entry we're looking at in the page.
3863          * If it is free (there's a free bitmap at the start of the
3864          * dir), we should skip these 32 bytes.
3865          */
3866         slotInPage = (entryInDir & 0x7e0) >> 5;
3867         if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
3868             (1 << (slotInPage & 0x7)))) {
3869             /* this entry is free */
3870             numDirChunks = 1;   /* only skip this guy */
3871             goto nextEntry;
3872         }
3873
3874         tp = bufferp->datap + entryInBuffer;
3875         dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
3876
3877         /* while we're here, compute the next entry's location, too,
3878          * since we'll need it when writing out the cookie into the dir
3879          * listing stream.
3880          *
3881          * XXXX Probably should do more sanity checking.
3882          */
3883         numDirChunks = cm_NameEntries(dep->name, &onbytes);
3884                 
3885         /* compute offset of cookie representing next entry */
3886         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3887
3888         /* Need 8.3 name? */
3889         NeedShortName = 0;
3890         if (infoLevel == 0x104
3891              && dep->fid.vnode != 0
3892              && !cm_Is8Dot3(dep->name)) {
3893             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3894             NeedShortName = 1;
3895         }
3896
3897         /* When matching, we are using doing a case fold if we have a wildcard mask.
3898          * If we get a non-wildcard match, it's a lookup for a specific file. 
3899          */
3900         if (dep->fid.vnode != 0 && 
3901             (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
3902              (NeedShortName &&
3903               smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
3904
3905             /* Eliminate entries that don't match requested attributes */
3906             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
3907                  smb_IsDotFile(dep->name))
3908                 goto nextEntry; /* no hidden files */
3909                     
3910             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
3911             {
3912                 /* We have already done the cm_TryBulkStat above */
3913                 fid.cell = scp->fid.cell;
3914                 fid.volume = scp->fid.volume;
3915                 fid.vnode = ntohl(dep->fid.vnode);
3916                 fid.unique = ntohl(dep->fid.unique);
3917                 fileType = cm_FindFileType(&fid);
3918                 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
3919                  "has filetype %d", dep->name,
3920                  fileType);*/
3921                 if (fileType == CM_SCACHETYPE_DIRECTORY)
3922                     goto nextEntry;
3923             }
3924
3925             /* finally check if this name will fit */
3926
3927             /* standard dir entry stuff */
3928             if (infoLevel < 0x101)
3929                 ohbytes = 23;   /* pre-NT */
3930             else if (infoLevel == 0x103)
3931                 ohbytes = 12;   /* NT names only */
3932             else
3933                 ohbytes = 64;   /* NT */
3934
3935             if (infoLevel == 0x104)
3936                 ohbytes += 26;  /* Short name & length */
3937
3938             if (searchFlags & 4) {
3939                 ohbytes += 4;   /* if resume key required */
3940             }   
3941
3942             if (infoLevel != 1
3943                  && infoLevel != 0x101
3944                  && infoLevel != 0x103)
3945                 ohbytes += 4;   /* EASIZE */
3946
3947             /* add header to name & term. null */
3948             orbytes = onbytes + ohbytes + 1;
3949
3950             /* now, we round up the record to a 4 byte alignment,
3951              * and we make sure that we have enough room here for
3952              * even the aligned version (so we don't have to worry
3953              * about an * overflow when we pad things out below).
3954              * That's the reason for the alignment arithmetic below.
3955              */
3956             if (infoLevel >= 0x101)
3957                 align = (4 - (orbytes & 3)) & 3;
3958             else
3959                 align = 0;
3960             if (orbytes + bytesInBuffer + align > maxReturnData)
3961                 break;
3962
3963             /* this is one of the entries to use: it is not deleted
3964              * and it matches the star pattern we're looking for.
3965              * Put out the name, preceded by its length.
3966              */
3967             /* First zero everything else */
3968             memset(origOp, 0, ohbytes);
3969
3970             if (infoLevel <= 0x101)
3971                 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
3972             else if (infoLevel == 0x103)
3973                 *((u_long *)(op + 8)) = onbytes;
3974             else
3975                 *((u_long *)(op + 60)) = onbytes;
3976             strcpy(origOp+ohbytes, dep->name);
3977
3978             /* Short name if requested and needed */
3979             if (infoLevel == 0x104) {
3980                 if (NeedShortName) {
3981                     strcpy(op + 70, shortName);
3982                     *(op + 68) = shortNameEnd - shortName;
3983                 }
3984             }
3985
3986             /* now, adjust the # of entries copied */
3987             returnedNames++;
3988
3989             /* NextEntryOffset and FileIndex */
3990             if (infoLevel >= 101) {
3991                 int entryOffset = orbytes + align;
3992                 *((u_long *)op) = entryOffset;
3993                 *((u_long *)(op+4)) = nextEntryCookie;
3994             }
3995
3996             /* now we emit the attribute.  This is tricky, since
3997              * we need to really stat the file to find out what
3998              * type of entry we've got.  Right now, we're copying
3999              * out data from * a buffer, while holding the scp
4000              * locked, so it isn't really convenient to stat
4001              * something now.  We'll put in a place holder
4002              * now, and make a second pass before returning this
4003              * to get the real attributes.  So, we just skip the
4004              * data for now, and adjust it later.  We allocate a
4005              * patch record to make it easy to find this point
4006              * later.  The replay will happen at a time when it is
4007              * safe to unlock the directory.
4008              */
4009             if (infoLevel != 0x103) {
4010                 curPatchp = malloc(sizeof(*curPatchp));
4011                 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4012                           &curPatchp->q);
4013                 curPatchp->dptr = op;
4014                 if (infoLevel >= 0x101)
4015                     curPatchp->dptr += 8;
4016
4017                 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4018                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4019                 }       
4020                 else    
4021                     curPatchp->flags = 0;
4022
4023                 curPatchp->fid.cell = scp->fid.cell;
4024                 curPatchp->fid.volume = scp->fid.volume;
4025                 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4026                 curPatchp->fid.unique = ntohl(dep->fid.unique);
4027
4028                 /* temp */
4029                 curPatchp->dep = dep;
4030             }   
4031
4032             if (searchFlags & 4)
4033                 /* put out resume key */
4034                 *((u_long *)origOp) = nextEntryCookie;
4035
4036             /* Adjust byte ptr and count */
4037             origOp += orbytes;  /* skip entire record */
4038             bytesInBuffer += orbytes;
4039
4040             /* and pad the record out */
4041             while (--align >= 0) {
4042                 *origOp++ = 0;
4043                 bytesInBuffer++;
4044             }
4045         }       /* if we're including this name */
4046         else if (!NeedShortName &&
4047                  !starPattern &&
4048                  !foundInexact &&
4049                  dep->fid.vnode != 0 &&
4050                  smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4051             /* We were looking for exact matches, but here's an inexact one*/
4052             foundInexact = 1;
4053         }
4054                 
4055       nextEntry:
4056         /* and adjust curOffset to be where the new cookie is */
4057         thyper.HighPart = 0;
4058         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4059         curOffset = LargeIntegerAdd(thyper, curOffset);
4060     } /* while copying data for dir listing */
4061
4062     /* If we didn't get a star pattern, we did an exact match during the first pass. 
4063      * If there were no exact matches found, we fail over to inexact matches by
4064      * marking the query as a star pattern (matches all case permutations), and
4065      * re-running the query. 
4066      */
4067     if (returnedNames == 0 && !starPattern && foundInexact) {
4068         osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4069         starPattern = 1;
4070         goto startsearch;
4071     }
4072
4073     /* release the mutex */
4074     lock_ReleaseMutex(&scp->mx);
4075     if (bufferp) buf_Release(bufferp);
4076
4077     /* apply and free last set of patches; if not doing a star match, this
4078      * will be empty, but better safe (and freeing everything) than sorry.
4079      */
4080     smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4081                               &req);
4082         
4083     /* now put out the final parameters */
4084     if (returnedNames == 0) eos = 1;
4085     if (p->opcode == 1) {
4086         /* find first */
4087         outp->parmsp[0] = (unsigned short) dsp->cookie;
4088         outp->parmsp[1] = returnedNames;
4089         outp->parmsp[2] = eos;
4090         outp->parmsp[3] = 0;            /* nothing wrong with EAS */
4091         outp->parmsp[4] = 0;    
4092         /* don't need last name to continue
4093          * search, cookie is enough.  Normally,
4094          * this is the offset of the file name
4095          * of the last entry returned.
4096          */
4097         outp->totalParms = 10;  /* in bytes */
4098     }
4099     else {
4100         /* find next */
4101         outp->parmsp[0] = returnedNames;
4102         outp->parmsp[1] = eos;
4103         outp->parmsp[2] = 0;    /* EAS error */
4104         outp->parmsp[3] = 0;    /* last name, as above */
4105         outp->totalParms = 8;   /* in bytes */
4106     }   
4107
4108     /* return # of bytes in the buffer */
4109     outp->totalData = bytesInBuffer;
4110
4111     osi_Log2(smb_logp, "T2 search dir done, %d names, code %d",
4112              returnedNames, code);
4113
4114     /* Return error code if unsuccessful on first request */
4115     if (code == 0 && p->opcode == 1 && returnedNames == 0)
4116         code = CM_ERROR_NOSUCHFILE;
4117
4118     /* if we're supposed to close the search after this request, or if
4119      * we're supposed to close the search if we're done, and we're done,
4120      * or if something went wrong, close the search.
4121      */
4122     /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4123     if ((searchFlags & 1) || (returnedNames == 0) || 
4124          ((searchFlags & 2) && eos) || code != 0)
4125         smb_DeleteDirSearch(dsp);
4126     if (code)
4127         smb_SendTran2Error(vcp, p, opx, code);
4128     else {
4129         smb_SendTran2Packet(vcp, outp, opx);
4130     }
4131     smb_FreeTran2Packet(outp);
4132     smb_ReleaseDirSearch(dsp);
4133     cm_ReleaseSCache(scp);
4134     cm_ReleaseUser(userp);
4135     return 0;
4136 }
4137
4138 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4139 {
4140     int dirHandle;
4141     smb_dirSearch_t *dsp;
4142
4143     dirHandle = smb_GetSMBParm(inp, 0);
4144         
4145     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4146
4147     dsp = smb_FindDirSearch(dirHandle);
4148         
4149     if (!dsp)
4150         return CM_ERROR_BADFD;
4151         
4152     /* otherwise, we have an FD to destroy */
4153     smb_DeleteDirSearch(dsp);
4154     smb_ReleaseDirSearch(dsp);
4155         
4156     /* and return results */
4157     smb_SetSMBDataLength(outp, 0);
4158
4159     return 0;
4160 }
4161
4162 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4163 {
4164     smb_SetSMBDataLength(outp, 0);
4165     return 0;
4166 }
4167
4168 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4169 {
4170     char *pathp;
4171     long code = 0;
4172     cm_space_t *spacep;
4173     int excl;
4174     cm_user_t *userp;
4175     cm_scache_t *dscp;          /* dir we're dealing with */
4176     cm_scache_t *scp;           /* file we're creating */
4177     cm_attr_t setAttr;
4178     int initialModeBits;
4179     smb_fid_t *fidp;
4180     int attributes;
4181     char *lastNamep;
4182     time_t dosTime;
4183     int openFun;
4184     int trunc;
4185     int openMode;
4186     int extraInfo;
4187     int openAction;
4188     int parmSlot;                       /* which parm we're dealing with */
4189     char *tidPathp;
4190     cm_req_t req;
4191
4192     cm_InitReq(&req);
4193
4194     scp = NULL;
4195         
4196     extraInfo = (smb_GetSMBParm(inp, 2) & 1);   /* return extra info */
4197     openFun = smb_GetSMBParm(inp, 8);   /* open function */
4198     excl = ((openFun & 3) == 0);
4199     trunc = ((openFun & 3) == 2);               /* truncate it */
4200     openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4201     openAction = 0;                     /* tracks what we did */
4202
4203     attributes = smb_GetSMBParm(inp, 5);
4204     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4205
4206         /* compute initial mode bits based on read-only flag in attributes */
4207     initialModeBits = 0666;
4208     if (attributes & 1) initialModeBits &= ~0222;
4209         
4210     pathp = smb_GetSMBData(inp, NULL);
4211
4212     spacep = inp->spacep;
4213     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4214