winnotes-20041207
[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     if (smb_StoreAnsiFilenames)
940         OemToChar(pathp,pathp);
941     servicep = smb_ParseString(tp, &tp);
942
943     tp = strrchr(pathp, '\\');
944     if (!tp) {
945         return CM_ERROR_BADSMB;
946     }
947     strcpy(shareName, tp+1);
948
949     osi_Log2(smb_logp, "Tree connect pathp[%s] shareName[%s]",
950              osi_LogSaveString(smb_logp, pathp),
951              osi_LogSaveString(smb_logp, shareName));
952
953     if (strcmp(servicep, "IPC") == 0 || strcmp(shareName, "IPC$") == 0) {
954 #ifndef NO_IPC
955         osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
956         ipc = 1;
957 #else
958         return CM_ERROR_NOIPC;
959 #endif
960     }
961
962     userp = smb_GetUser(vcp, inp);
963
964     lock_ObtainMutex(&vcp->mx);
965     newTid = vcp->tidCounter++;
966     lock_ReleaseMutex(&vcp->mx);
967         
968     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
969
970     if(!ipc) {
971         uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
972         shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
973         if (uidp)
974             smb_ReleaseUID(uidp);
975         if (!shareFound) {
976             smb_ReleaseTID(tidp);
977             return CM_ERROR_BADSHARENAME;
978         }
979
980         if (vcp->flags & SMB_VCFLAG_USENT)
981         {
982             int policy = smb_FindShareCSCPolicy(shareName);
983             smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | (policy << 2));
984         }
985     } else {
986         smb_SetSMBParm(outp, 2, 0);
987         sharePath = NULL;
988     }
989
990     lock_ObtainMutex(&tidp->mx);
991     tidp->userp = userp;
992     tidp->pathname = sharePath;
993     if(ipc) tidp->flags |= SMB_TIDFLAG_IPC;
994     lock_ReleaseMutex(&tidp->mx);
995     smb_ReleaseTID(tidp);
996
997     ((smb_t *)outp)->tid = newTid;
998     ((smb_t *)inp)->tid = newTid;
999     tp = smb_GetSMBData(outp, NULL);
1000     if (!ipc) {
1001         *tp++ = 'A';
1002         *tp++ = ':';
1003         *tp++ = 0;
1004         smb_SetSMBDataLength(outp, 3);
1005     } else {
1006         strcpy(tp, "IPC");
1007         smb_SetSMBDataLength(outp, 4);
1008     }
1009
1010     osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1011     return 0;
1012 }
1013
1014 /* must be called with global tran lock held */
1015 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1016 {
1017     smb_tran2Packet_t *tp;
1018     smb_t *smbp;
1019         
1020     smbp = (smb_t *) inp->data;
1021     for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1022         if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1023             return tp;
1024     }
1025     return NULL;
1026 }
1027
1028 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1029         int totalParms, int totalData)
1030 {
1031     smb_tran2Packet_t *tp;
1032     smb_t *smbp;
1033         
1034     smbp = (smb_t *) inp->data;
1035     tp = malloc(sizeof(*tp));
1036     memset(tp, 0, sizeof(*tp));
1037     tp->vcp = vcp;
1038     smb_HoldVC(vcp);
1039     tp->curData = tp->curParms = 0;
1040     tp->totalData = totalData;
1041     tp->totalParms = totalParms;
1042     tp->tid = smbp->tid;
1043     tp->mid = smbp->mid;
1044     tp->uid = smbp->uid;
1045     tp->pid = smbp->pid;
1046     tp->res[0] = smbp->res[0];
1047     osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1048     if (totalParms != 0)
1049         tp->parmsp = malloc(totalParms);
1050     if (totalData != 0)
1051         tp->datap = malloc(totalData);
1052     if (smbp->com == 0x25 || smbp->com == 0x26)
1053         tp->com = 0x25;
1054     else {
1055         tp->opcode = smb_GetSMBParm(inp, 14);
1056         tp->com = 0x32;
1057     }
1058     tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1059     return tp;
1060 }
1061
1062 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1063                                                smb_tran2Packet_t *inp, smb_packet_t *outp,
1064                                                int totalParms, int totalData)  
1065 {
1066     smb_tran2Packet_t *tp;
1067     unsigned short parmOffset;
1068     unsigned short dataOffset;
1069     unsigned short dataAlign;
1070         
1071     tp = malloc(sizeof(*tp));
1072     memset(tp, 0, sizeof(*tp));
1073     tp->vcp = NULL;
1074     tp->curData = tp->curParms = 0;
1075     tp->totalData = totalData;
1076     tp->totalParms = totalParms;
1077     tp->oldTotalParms = totalParms;
1078     tp->tid = inp->tid;
1079     tp->mid = inp->mid;
1080     tp->uid = inp->uid;
1081     tp->pid = inp->pid;
1082     tp->res[0] = inp->res[0];
1083     tp->opcode = inp->opcode;
1084     tp->com = inp->com;
1085
1086     /*
1087      * We calculate where the parameters and data will start.
1088      * This calculation must parallel the calculation in
1089      * smb_SendTran2Packet.
1090      */
1091
1092     parmOffset = 10*2 + 35;
1093     parmOffset++;                       /* round to even */
1094     tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1095
1096     dataOffset = parmOffset + totalParms;
1097     dataAlign = dataOffset & 2; /* quad-align */
1098     dataOffset += dataAlign;
1099     tp->datap = outp->data + dataOffset;
1100
1101     return tp;
1102 }       
1103
1104 /* free a tran2 packet; must be called with smb_globalLock held */
1105 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1106 {
1107     if (t2p->vcp) smb_ReleaseVC(t2p->vcp);
1108     if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1109         if (t2p->parmsp)
1110             free(t2p->parmsp);
1111         if (t2p->datap)
1112             free(t2p->datap);
1113     }       
1114     free(t2p);
1115 }
1116
1117 /* called with a VC, an input packet to respond to, and an error code.
1118  * sends an error response.
1119  */
1120 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1121         smb_packet_t *tp, long code)
1122 {
1123     smb_t *smbp;
1124     unsigned short errCode;
1125     unsigned char errClass;
1126     unsigned long NTStatus;
1127
1128     if (vcp->flags & SMB_VCFLAG_STATUS32)
1129         smb_MapNTError(code, &NTStatus);
1130     else
1131         smb_MapCoreError(code, vcp, &errCode, &errClass);
1132
1133     smb_FormatResponsePacket(vcp, NULL, tp);
1134     smbp = (smb_t *) tp;
1135
1136     /* We can handle long names */
1137     if (vcp->flags & SMB_VCFLAG_USENT)
1138         smbp->flg2 |= 0x40;     /* IS_LONG_NAME */
1139         
1140     /* now copy important fields from the tran 2 packet */
1141     smbp->com = t2p->com;
1142     smbp->tid = t2p->tid;
1143     smbp->mid = t2p->mid;
1144     smbp->pid = t2p->pid;
1145     smbp->uid = t2p->uid;
1146     smbp->res[0] = t2p->res[0];
1147     if (vcp->flags & SMB_VCFLAG_STATUS32) {
1148         smbp->rcls = (unsigned char) (NTStatus & 0xff);
1149         smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1150         smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1151         smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1152         smbp->flg2 |= 0x4000;
1153     }
1154     else {
1155         smbp->rcls = errClass;
1156         smbp->errLow = (unsigned char) (errCode & 0xff);
1157         smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1158     }
1159         
1160     /* send packet */
1161     smb_SendPacket(vcp, tp);
1162 }        
1163
1164 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1165 {
1166     smb_t *smbp;
1167     unsigned short parmOffset;
1168     unsigned short dataOffset;
1169     unsigned short totalLength;
1170     unsigned short dataAlign;
1171     char *datap;
1172
1173     smb_FormatResponsePacket(vcp, NULL, tp);
1174     smbp = (smb_t *) tp;
1175
1176     /* We can handle long names */
1177     if (vcp->flags & SMB_VCFLAG_USENT)
1178         smbp->flg2 |= 0x40;     /* IS_LONG_NAME */
1179
1180     /* now copy important fields from the tran 2 packet */
1181     smbp->com = t2p->com;
1182     smbp->tid = t2p->tid;
1183     smbp->mid = t2p->mid;
1184     smbp->pid = t2p->pid;
1185     smbp->uid = t2p->uid;
1186     smbp->res[0] = t2p->res[0];
1187
1188     totalLength = 1 + t2p->totalData + t2p->totalParms;
1189
1190     /* now add the core parameters (tran2 info) to the packet */
1191     smb_SetSMBParm(tp, 0, t2p->totalParms);     /* parm bytes */
1192     smb_SetSMBParm(tp, 1, t2p->totalData);      /* data bytes */
1193     smb_SetSMBParm(tp, 2, 0);           /* reserved */
1194     smb_SetSMBParm(tp, 3, t2p->totalParms);     /* parm bytes in this packet */
1195     parmOffset = 10*2 + 35;                     /* parm offset in packet */
1196     parmOffset++;                               /* round to even */
1197     smb_SetSMBParm(tp, 4, parmOffset);  /* 11 parm words plus *
1198     * hdr, bcc and wct */
1199     smb_SetSMBParm(tp, 5, 0);           /* parm displacement */
1200     smb_SetSMBParm(tp, 6, t2p->totalData);      /* data in this packet */
1201     dataOffset = parmOffset + t2p->oldTotalParms;
1202     dataAlign = dataOffset & 2;         /* quad-align */
1203     dataOffset += dataAlign;
1204     smb_SetSMBParm(tp, 7, dataOffset);  /* offset of data */
1205     smb_SetSMBParm(tp, 8, 0);           /* data displacement */
1206     smb_SetSMBParm(tp, 9, 0);           /* low: setup word count *
1207                                          * high: resvd */
1208
1209     datap = smb_GetSMBData(tp, NULL);
1210     *datap++ = 0;                               /* we rounded to even */
1211
1212     totalLength += dataAlign;
1213     smb_SetSMBDataLength(tp, totalLength);
1214         
1215     /* next, send the datagram */
1216     smb_SendPacket(vcp, tp);
1217 }   
1218
1219 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1220 {
1221     smb_tran2Packet_t *asp;
1222     int totalParms;
1223     int totalData;
1224     int parmDisp;
1225     int dataDisp;
1226     int parmOffset;
1227     int dataOffset;
1228     int parmCount;
1229     int dataCount;
1230     int firstPacket;
1231     int rapOp;
1232     long code = 0;
1233
1234     /* We sometimes see 0 word count.  What to do? */
1235     if (*inp->wctp == 0) {
1236 #ifndef DJGPP
1237         HANDLE h;
1238         char *ptbuf[1];
1239
1240         osi_Log0(smb_logp, "TRANSACTION word count = 0"); 
1241
1242         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1243         ptbuf[0] = "Transaction2 word count = 0";
1244         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1245                     1, inp->ncb_length, ptbuf, inp);
1246         DeregisterEventSource(h);
1247 #else /* DJGPP */
1248         osi_Log0(smb_logp, "TRANSACTION word count = 0"); 
1249 #endif /* !DJGPP */
1250
1251         smb_SetSMBDataLength(outp, 0);
1252         smb_SendPacket(vcp, outp);
1253         return 0;
1254     }
1255
1256     totalParms = smb_GetSMBParm(inp, 0);
1257     totalData = smb_GetSMBParm(inp, 1);
1258         
1259     firstPacket = (inp->inCom == 0x25);
1260         
1261     /* find the packet we're reassembling */
1262     lock_ObtainWrite(&smb_globalLock);
1263     asp = smb_FindTran2Packet(vcp, inp);
1264     if (!asp) {
1265         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1266     }
1267     lock_ReleaseWrite(&smb_globalLock);
1268         
1269     /* now merge in this latest packet; start by looking up offsets */
1270     if (firstPacket) {
1271         parmDisp = dataDisp = 0;
1272         parmOffset = smb_GetSMBParm(inp, 10);
1273         dataOffset = smb_GetSMBParm(inp, 12);
1274         parmCount = smb_GetSMBParm(inp, 9);
1275         dataCount = smb_GetSMBParm(inp, 11);
1276         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1277         asp->maxReturnData = smb_GetSMBParm(inp, 3);
1278
1279         osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1280                   totalData, dataCount, asp->maxReturnData);
1281     }
1282     else {
1283         parmDisp = smb_GetSMBParm(inp, 4);
1284         parmOffset = smb_GetSMBParm(inp, 3);
1285         dataDisp = smb_GetSMBParm(inp, 7);
1286         dataOffset = smb_GetSMBParm(inp, 6);
1287         parmCount = smb_GetSMBParm(inp, 2);
1288         dataCount = smb_GetSMBParm(inp, 5);
1289
1290         osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1291                  parmCount, dataCount);
1292     }   
1293
1294     /* now copy the parms and data */
1295     if ( asp->totalParms > 0 && parmCount != 0 )
1296     {
1297         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1298     }
1299     if ( asp->totalData > 0 && dataCount != 0 ) {
1300         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1301     }
1302
1303     /* account for new bytes */
1304     asp->curData += dataCount;
1305     asp->curParms += parmCount;
1306
1307     /* finally, if we're done, remove the packet from the queue and dispatch it */
1308     if (asp->totalParms > 0 &&
1309         asp->curParms > 0 &&
1310         asp->totalData <= asp->curData &&
1311         asp->totalParms <= asp->curParms) {
1312         /* we've received it all */
1313         lock_ObtainWrite(&smb_globalLock);
1314         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1315         lock_ReleaseWrite(&smb_globalLock);
1316
1317         /* now dispatch it */
1318         rapOp = asp->parmsp[0];
1319
1320         if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1321             osi_LogEvent("AFS-Dispatch-RAP[%s]",myCrt_RapDispatch(rapOp),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1322             osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%x] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1323             code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1324         }
1325         else {
1326             osi_LogEvent("AFS-Dispatch-RAP [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1327             osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1328             code = CM_ERROR_BADOP;
1329         }
1330
1331         /* if an error is returned, we're supposed to send an error packet,
1332          * otherwise the dispatched function already did the data sending.
1333          * We give dispatched proc the responsibility since it knows how much
1334          * space to allocate.
1335          */
1336         if (code != 0) {
1337             smb_SendTran2Error(vcp, asp, outp, code);
1338         }
1339
1340         /* free the input tran 2 packet */
1341         lock_ObtainWrite(&smb_globalLock);
1342         smb_FreeTran2Packet(asp);
1343         lock_ReleaseWrite(&smb_globalLock);
1344     }
1345     else if (firstPacket) {
1346         /* the first packet in a multi-packet request, we need to send an
1347          * ack to get more data.
1348          */
1349         smb_SetSMBDataLength(outp, 0);
1350         smb_SendPacket(vcp, outp);
1351     }
1352
1353     return 0;
1354 }
1355
1356 /* ANSI versions.  The unicode versions support arbitrary length
1357    share names, but we don't support unicode yet. */
1358
1359 typedef struct smb_rap_share_info_0 {
1360     char        shi0_netname[13];
1361 } smb_rap_share_info_0_t;
1362
1363 typedef struct smb_rap_share_info_1 {
1364     char                        shi1_netname[13];
1365     char                        shi1_pad;
1366     WORD                        shi1_type;
1367     DWORD                       shi1_remark; /* char *shi1_remark; data offset */
1368 } smb_rap_share_info_1_t;
1369
1370 typedef struct smb_rap_share_info_2 {
1371     char                                shi2_netname[13];
1372     char                                shi2_pad;
1373     unsigned short              shi2_type;
1374     DWORD                               shi2_remark; /* char *shi2_remark; data offset */
1375     unsigned short              shi2_permissions;
1376     unsigned short              shi2_max_uses;
1377     unsigned short              shi2_current_uses;
1378     DWORD                               shi2_path;  /* char *shi2_path; data offset */
1379     unsigned short              shi2_passwd[9];
1380     unsigned short              shi2_pad2;
1381 } smb_rap_share_info_2_t;
1382
1383 #define SMB_RAP_MAX_SHARES 512
1384
1385 typedef struct smb_rap_share_list {
1386     int cShare;
1387     int maxShares;
1388     smb_rap_share_info_0_t * shares;
1389 } smb_rap_share_list_t;
1390
1391 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1392     smb_rap_share_list_t * sp;
1393     char * name;
1394
1395     name = dep->name;
1396
1397     if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
1398         return 0; /* skip over '.' and '..' */
1399
1400     sp = (smb_rap_share_list_t *) vrockp;
1401
1402     strncpy(sp->shares[sp->cShare].shi0_netname, name, 12);
1403     sp->shares[sp->cShare].shi0_netname[12] = 0;
1404
1405     sp->cShare++;
1406
1407     if (sp->cShare >= sp->maxShares)
1408         return CM_ERROR_STOPNOW;
1409     else
1410         return 0;
1411 }       
1412
1413 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1414 {
1415     smb_tran2Packet_t *outp;
1416     unsigned short * tp;
1417     int len;
1418     int infoLevel;
1419     int bufsize;
1420     int outParmsTotal;  /* total parameter bytes */
1421     int outDataTotal;   /* total data bytes */
1422     int code = 0;
1423     DWORD rv;
1424     DWORD allSubmount;
1425     USHORT nShares;
1426     DWORD nRegShares;
1427     DWORD nSharesRet;
1428     HKEY hkParam;
1429     HKEY hkSubmount = NULL;
1430     smb_rap_share_info_1_t * shares;
1431     USHORT cshare = 0;
1432     char * cstrp;
1433     char thisShare[256];
1434     int i,j;
1435     int nonrootShares;
1436     smb_rap_share_list_t rootShares;
1437     cm_req_t req;
1438     cm_user_t * userp;
1439     osi_hyper_t thyper;
1440
1441     tp = p->parmsp + 1; /* skip over function number (always 0) */
1442     (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1443     (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1444     infoLevel = tp[0];
1445     bufsize = tp[1];
1446
1447     if (infoLevel != 1) {
1448         return CM_ERROR_INVAL;
1449     }
1450
1451     /* first figure out how many shares there are */
1452     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1453                       KEY_QUERY_VALUE, &hkParam);
1454     if (rv == ERROR_SUCCESS) {
1455         len = sizeof(allSubmount);
1456         rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1457                              (BYTE *) &allSubmount, &len);
1458         if (rv != ERROR_SUCCESS || allSubmount != 0) {
1459             allSubmount = 1;
1460         }
1461         RegCloseKey (hkParam);
1462     }
1463
1464     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts",
1465                       0, KEY_QUERY_VALUE, &hkSubmount);
1466     if (rv == ERROR_SUCCESS) {
1467         rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1468                              NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1469         if (rv != ERROR_SUCCESS)
1470             nRegShares = 0;
1471     } else {
1472         hkSubmount = NULL;
1473     }
1474
1475     /* fetch the root shares */
1476     rootShares.maxShares = SMB_RAP_MAX_SHARES;
1477     rootShares.cShare = 0;
1478     rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1479
1480     cm_InitReq(&req);
1481
1482     userp = smb_GetTran2User(vcp,p);
1483
1484     thyper.HighPart = 0;
1485     thyper.LowPart = 0;
1486
1487     cm_HoldSCache(cm_rootSCachep);
1488     cm_ApplyDir(cm_rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1489     cm_ReleaseSCache(cm_rootSCachep);
1490
1491     cm_ReleaseUser(userp);
1492
1493     nShares = rootShares.cShare + nRegShares + allSubmount;
1494
1495 #define REMARK_LEN 1
1496     outParmsTotal = 8; /* 4 dwords */
1497     outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1498     if(outDataTotal > bufsize) {
1499         nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1500         outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1501     }
1502     else {
1503         nSharesRet = nShares;
1504     }
1505     
1506     outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1507
1508     /* now for the submounts */
1509     shares = (smb_rap_share_info_1_t *) outp->datap;
1510     cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1511
1512     memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1513
1514     if (allSubmount) {
1515         strcpy( shares[cshare].shi1_netname, "all" );
1516         shares[cshare].shi1_remark = cstrp - outp->datap;
1517         /* type and pad are zero already */
1518         cshare++;
1519         cstrp+=REMARK_LEN;
1520     }
1521
1522     if (hkSubmount) {
1523         for (i=0; i < nRegShares && cshare < nSharesRet; i++) {
1524             len = sizeof(thisShare);
1525             rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1526             if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1527                 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1528                 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1529                 shares[cshare].shi1_remark = cstrp - outp->datap;
1530                 cshare++;
1531                 cstrp+=REMARK_LEN;
1532             }
1533             else
1534                 nShares--; /* uncount key */
1535         }
1536
1537         RegCloseKey(hkSubmount);
1538     }
1539
1540     nonrootShares = cshare;
1541
1542     for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1543         /* in case there are collisions with submounts, submounts have higher priority */               
1544         for (j=0; j < nonrootShares; j++)
1545             if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1546                 break;
1547                 
1548         if (j < nonrootShares) {
1549             nShares--; /* uncount */
1550             continue;
1551         }
1552
1553         strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1554         shares[cshare].shi1_remark = cstrp - outp->datap;
1555         cshare++;
1556         cstrp+=REMARK_LEN;
1557     }
1558
1559     outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1560     outp->parmsp[1] = 0;
1561     outp->parmsp[2] = cshare;
1562     outp->parmsp[3] = nShares;
1563
1564     outp->totalData = cstrp - outp->datap;
1565     outp->totalParms = outParmsTotal;
1566
1567     smb_SendTran2Packet(vcp, outp, op);
1568     smb_FreeTran2Packet(outp);
1569
1570     free(rootShares.shares);
1571
1572     return code;
1573 }
1574
1575 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1576 {
1577     smb_tran2Packet_t *outp;
1578     unsigned short * tp;
1579     char * shareName;
1580     BOOL shareFound = FALSE;
1581     unsigned short infoLevel;
1582     unsigned short bufsize;
1583     int totalData;
1584     int totalParam;
1585     DWORD len;
1586     HKEY hkParam;
1587     HKEY hkSubmount;
1588     DWORD allSubmount;
1589     LONG rv;
1590     long code = 0;
1591
1592     tp = p->parmsp + 1; /* skip over function number (always 1) */
1593     (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1594     (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1595     shareName = smb_ParseString( (char *) tp, (char **) &tp);
1596     infoLevel = *tp++;
1597     bufsize = *tp++;
1598     
1599     totalParam = 6;
1600
1601     if (infoLevel == 0)
1602         totalData = sizeof(smb_rap_share_info_0_t);
1603     else if(infoLevel == 1)
1604         totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1605     else if(infoLevel == 2)
1606         totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1607     else
1608         return CM_ERROR_INVAL;
1609
1610     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1611
1612     if(!stricmp(shareName,"all")) {
1613         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1614                           KEY_QUERY_VALUE, &hkParam);
1615         if (rv == ERROR_SUCCESS) {
1616             len = sizeof(allSubmount);
1617             rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1618                                   (BYTE *) &allSubmount, &len);
1619             if (rv != ERROR_SUCCESS || allSubmount != 0) {
1620                 allSubmount = 1;
1621             }
1622             RegCloseKey (hkParam);
1623         }
1624
1625         if (allSubmount)
1626             shareFound = TRUE;
1627
1628     } else {
1629         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1630                           KEY_QUERY_VALUE, &hkSubmount);
1631         if (rv == ERROR_SUCCESS) {
1632             rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1633             if (rv == ERROR_SUCCESS) {
1634                 shareFound = TRUE;
1635             }
1636             RegCloseKey(hkSubmount);
1637         }
1638     }
1639
1640     if (!shareFound) {
1641         smb_FreeTran2Packet(outp);
1642         return CM_ERROR_BADSHARENAME;
1643     }
1644
1645     memset(outp->datap, 0, totalData);
1646
1647     outp->parmsp[0] = 0;
1648     outp->parmsp[1] = 0;
1649     outp->parmsp[2] = totalData;
1650
1651     if (infoLevel == 0) {
1652         smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1653         strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1654         info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1655     } else if(infoLevel == 1) {
1656         smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1657         strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1658         info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1659         info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1660         /* type and pad are already zero */
1661     } else { /* infoLevel==2 */
1662         smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1663         strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1664         info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1665         info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1666         info->shi2_permissions = ACCESS_ALL;
1667         info->shi2_max_uses = (unsigned short) -1;
1668         info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1669     }
1670
1671     outp->totalData = totalData;
1672     outp->totalParms = totalParam;
1673
1674     smb_SendTran2Packet(vcp, outp, op);
1675     smb_FreeTran2Packet(outp);
1676
1677     return code;
1678 }
1679
1680 typedef struct smb_rap_wksta_info_10 {
1681     DWORD       wki10_computername;     /*char *wki10_computername;*/
1682     DWORD       wki10_username; /* char *wki10_username; */
1683     DWORD       wki10_langroup; /* char *wki10_langroup;*/
1684     unsigned char       wki10_ver_major;
1685     unsigned char       wki10_ver_minor;
1686     DWORD       wki10_logon_domain;     /*char *wki10_logon_domain;*/
1687     DWORD       wki10_oth_domains; /* char *wki10_oth_domains;*/
1688 } smb_rap_wksta_info_10_t;
1689
1690
1691 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1692 {
1693     smb_tran2Packet_t *outp;
1694     long code = 0;
1695     int infoLevel;
1696     int bufsize;
1697     unsigned short * tp;
1698     int totalData;
1699     int totalParams;
1700     smb_rap_wksta_info_10_t * info;
1701     char * cstrp;
1702     smb_user_t *uidp;
1703
1704     tp = p->parmsp + 1; /* Skip over function number */
1705     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1706     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1707     infoLevel = *tp++;
1708     bufsize = *tp++;
1709
1710     if (infoLevel != 10) {
1711         return CM_ERROR_INVAL;
1712     }
1713
1714     totalParams = 6;
1715         
1716     /* infolevel 10 */
1717     totalData = sizeof(*info) +         /* info */
1718         MAX_COMPUTERNAME_LENGTH +       /* wki10_computername */
1719         SMB_MAX_USERNAME_LENGTH +       /* wki10_username */
1720         MAX_COMPUTERNAME_LENGTH +       /* wki10_langroup */
1721         MAX_COMPUTERNAME_LENGTH +       /* wki10_logon_domain */
1722         1;                              /* wki10_oth_domains (null)*/
1723
1724     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1725
1726     memset(outp->parmsp,0,totalParams);
1727     memset(outp->datap,0,totalData);
1728
1729     info = (smb_rap_wksta_info_10_t *) outp->datap;
1730     cstrp = (char *) (info + 1);
1731
1732     info->wki10_computername = (DWORD) (cstrp - outp->datap);
1733     strcpy(cstrp, smb_localNamep);
1734     cstrp += strlen(cstrp) + 1;
1735
1736     info->wki10_username = (DWORD) (cstrp - outp->datap);
1737     uidp = smb_FindUID(vcp, p->uid, 0);
1738     if (uidp) {
1739         lock_ObtainMutex(&uidp->mx);
1740         if(uidp->unp && uidp->unp->name)
1741             strcpy(cstrp, uidp->unp->name);
1742         lock_ReleaseMutex(&uidp->mx);
1743         smb_ReleaseUID(uidp);
1744     }
1745     cstrp += strlen(cstrp) + 1;
1746
1747     info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1748     strcpy(cstrp, "WORKGROUP");
1749     cstrp += strlen(cstrp) + 1;
1750
1751     /* TODO: Not sure what values these should take, but these work */
1752     info->wki10_ver_major = 5;
1753     info->wki10_ver_minor = 1;
1754
1755     info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1756     strcpy(cstrp, smb_ServerDomainName);
1757     cstrp += strlen(cstrp) + 1;
1758
1759     info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1760     cstrp ++; /* no other domains */
1761
1762     outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1763     outp->parmsp[2] = outp->totalData;
1764     outp->totalParms = totalParams;
1765
1766     smb_SendTran2Packet(vcp,outp,op);
1767     smb_FreeTran2Packet(outp);
1768
1769     return code;
1770 }
1771
1772 typedef struct smb_rap_server_info_0 {
1773     char    sv0_name[16];
1774 } smb_rap_server_info_0_t;
1775
1776 typedef struct smb_rap_server_info_1 {
1777     char            sv1_name[16];
1778     char            sv1_version_major;
1779     char            sv1_version_minor;
1780     unsigned long   sv1_type;
1781     DWORD           *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1782 } smb_rap_server_info_1_t;
1783
1784 char smb_ServerComment[] = "OpenAFS Client";
1785 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1786
1787 #define SMB_SV_TYPE_SERVER              0x00000002L
1788 #define SMB_SV_TYPE_NT              0x00001000L
1789 #define SMB_SV_TYPE_SERVER_NT       0x00008000L
1790
1791 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1792 {
1793     smb_tran2Packet_t *outp;
1794     long code = 0;
1795     int infoLevel;
1796     int bufsize;
1797     unsigned short * tp;
1798     int totalData;
1799     int totalParams;
1800     smb_rap_server_info_0_t * info0;
1801     smb_rap_server_info_1_t * info1;
1802     char * cstrp;
1803
1804     tp = p->parmsp + 1; /* Skip over function number */
1805     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1806     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1807     infoLevel = *tp++;
1808     bufsize = *tp++;
1809
1810     if (infoLevel != 0 && infoLevel != 1) {
1811         return CM_ERROR_INVAL;
1812     }
1813
1814     totalParams = 6;
1815
1816     totalData = 
1817         (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1818         : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1819
1820     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1821
1822     memset(outp->parmsp,0,totalParams);
1823     memset(outp->datap,0,totalData);
1824
1825     if (infoLevel == 0) {
1826         info0 = (smb_rap_server_info_0_t *) outp->datap;
1827         cstrp = (char *) (info0 + 1);
1828         strcpy(info0->sv0_name, "AFS");
1829     } else { /* infoLevel == 1 */
1830         info1 = (smb_rap_server_info_1_t *) outp->datap;
1831         cstrp = (char *) (info1 + 1);
1832         strcpy(info1->sv1_name, "AFS");
1833
1834         info1->sv1_type = 
1835             SMB_SV_TYPE_SERVER |
1836             SMB_SV_TYPE_NT |
1837             SMB_SV_TYPE_SERVER_NT;
1838
1839         info1->sv1_version_major = 5;
1840         info1->sv1_version_minor = 1;
1841         info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1842
1843         strcpy(cstrp, smb_ServerComment);
1844
1845         cstrp += smb_ServerCommentLen;
1846     }
1847
1848     totalData = cstrp - outp->datap;
1849     outp->totalData = min(bufsize,totalData); /* actual data size */
1850     outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1851     outp->parmsp[2] = totalData;
1852     outp->totalParms = totalParams;
1853
1854     smb_SendTran2Packet(vcp,outp,op);
1855     smb_FreeTran2Packet(outp);
1856
1857     return code;
1858 }
1859
1860 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1861 {
1862     smb_tran2Packet_t *asp;
1863     int totalParms;
1864     int totalData;
1865     int parmDisp;
1866     int dataDisp;
1867     int parmOffset;
1868     int dataOffset;
1869     int parmCount;
1870     int dataCount;
1871     int firstPacket;
1872     long code = 0;
1873
1874     /* We sometimes see 0 word count.  What to do? */
1875     if (*inp->wctp == 0) {
1876 #ifndef DJGPP
1877         HANDLE h;
1878         char *ptbuf[1];
1879
1880         osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
1881
1882         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1883         ptbuf[0] = "Transaction2 word count = 0";
1884         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1885                     1, inp->ncb_length, ptbuf, inp);
1886         DeregisterEventSource(h);
1887 #else /* DJGPP */
1888         osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
1889 #endif /* !DJGPP */
1890
1891         smb_SetSMBDataLength(outp, 0);
1892         smb_SendPacket(vcp, outp);
1893         return 0;
1894     }
1895
1896     totalParms = smb_GetSMBParm(inp, 0);
1897     totalData = smb_GetSMBParm(inp, 1);
1898         
1899     firstPacket = (inp->inCom == 0x32);
1900         
1901     /* find the packet we're reassembling */
1902     lock_ObtainWrite(&smb_globalLock);
1903     asp = smb_FindTran2Packet(vcp, inp);
1904     if (!asp) {
1905         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1906     }
1907     lock_ReleaseWrite(&smb_globalLock);
1908         
1909     /* now merge in this latest packet; start by looking up offsets */
1910     if (firstPacket) {
1911         parmDisp = dataDisp = 0;
1912         parmOffset = smb_GetSMBParm(inp, 10);
1913         dataOffset = smb_GetSMBParm(inp, 12);
1914         parmCount = smb_GetSMBParm(inp, 9);
1915         dataCount = smb_GetSMBParm(inp, 11);
1916         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1917         asp->maxReturnData = smb_GetSMBParm(inp, 3);
1918
1919         osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1920                  totalData, dataCount, asp->maxReturnData);
1921     }
1922     else {
1923         parmDisp = smb_GetSMBParm(inp, 4);
1924         parmOffset = smb_GetSMBParm(inp, 3);
1925         dataDisp = smb_GetSMBParm(inp, 7);
1926         dataOffset = smb_GetSMBParm(inp, 6);
1927         parmCount = smb_GetSMBParm(inp, 2);
1928         dataCount = smb_GetSMBParm(inp, 5);
1929
1930         osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1931                  parmCount, dataCount);
1932     }   
1933
1934     /* now copy the parms and data */
1935     if ( asp->totalParms > 0 && parmCount != 0 )
1936     {
1937         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1938     }
1939     if ( asp->totalData > 0 && dataCount != 0 ) {
1940         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1941     }
1942
1943     /* account for new bytes */
1944     asp->curData += dataCount;
1945     asp->curParms += parmCount;
1946
1947     /* finally, if we're done, remove the packet from the queue and dispatch it */
1948     if (asp->totalParms > 0 &&
1949         asp->curParms > 0 &&
1950         asp->totalData <= asp->curData &&
1951         asp->totalParms <= asp->curParms) {
1952         /* we've received it all */
1953         lock_ObtainWrite(&smb_globalLock);
1954         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1955         lock_ReleaseWrite(&smb_globalLock);
1956
1957         /* now dispatch it */
1958         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1959             osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1960             osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1961             code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1962         }
1963         else {
1964             osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1965             osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1966             code = CM_ERROR_BADOP;
1967         }
1968
1969         /* if an error is returned, we're supposed to send an error packet,
1970          * otherwise the dispatched function already did the data sending.
1971          * We give dispatched proc the responsibility since it knows how much
1972          * space to allocate.
1973          */
1974         if (code != 0) {
1975             smb_SendTran2Error(vcp, asp, outp, code);
1976         }
1977
1978         /* free the input tran 2 packet */
1979         lock_ObtainWrite(&smb_globalLock);
1980         smb_FreeTran2Packet(asp);
1981         lock_ReleaseWrite(&smb_globalLock);
1982     }
1983     else if (firstPacket) {
1984         /* the first packet in a multi-packet request, we need to send an
1985          * ack to get more data.
1986          */
1987         smb_SetSMBDataLength(outp, 0);
1988         smb_SendPacket(vcp, outp);
1989     }
1990
1991     return 0;
1992 }
1993
1994 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1995 {
1996     char *pathp;
1997     smb_tran2Packet_t *outp;
1998     long code = 0;
1999     cm_space_t *spacep;
2000     int excl;
2001     cm_user_t *userp;
2002     cm_scache_t *dscp;          /* dir we're dealing with */
2003     cm_scache_t *scp;           /* file we're creating */
2004     cm_attr_t setAttr;
2005     int initialModeBits;
2006     smb_fid_t *fidp;
2007     int attributes;
2008     char *lastNamep;
2009     time_t dosTime;
2010     int openFun;
2011     int trunc;
2012     int openMode;
2013     int extraInfo;
2014     int openAction;
2015     int parmSlot;                       /* which parm we're dealing with */
2016     long returnEALength;
2017     char *tidPathp;
2018     cm_req_t req;
2019
2020     cm_InitReq(&req);
2021
2022     scp = NULL;
2023         
2024     extraInfo = (p->parmsp[0] & 1);     /* return extra info */
2025     returnEALength = (p->parmsp[0] & 8);        /* return extended attr length */
2026
2027     openFun = p->parmsp[6];             /* open function */
2028     excl = ((openFun & 3) == 0);
2029     trunc = ((openFun & 3) == 2);       /* truncate it */
2030     openMode = (p->parmsp[1] & 0x7);
2031     openAction = 0;                     /* tracks what we did */
2032
2033     attributes = p->parmsp[3];
2034     dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2035         
2036     /* compute initial mode bits based on read-only flag in attributes */
2037     initialModeBits = 0666;
2038     if (attributes & 1) initialModeBits &= ~0222;
2039         
2040     pathp = (char *) (&p->parmsp[14]);
2041     if (smb_StoreAnsiFilenames)
2042         OemToChar(pathp,pathp);
2043     
2044     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2045
2046     spacep = cm_GetSpace();
2047     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2048
2049     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2050         /* special case magic file name for receiving IOCTL requests
2051          * (since IOCTL calls themselves aren't getting through).
2052          */
2053         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2054         smb_SetupIoctlFid(fidp, spacep);
2055
2056         /* copy out remainder of the parms */
2057         parmSlot = 0;
2058         outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2059         if (extraInfo) {
2060             outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
2061             outp->parmsp[parmSlot] = 0; parmSlot++;     /* mod time */
2062             outp->parmsp[parmSlot] = 0; parmSlot++;
2063             outp->parmsp[parmSlot] = 0; parmSlot++;     /* len */
2064             outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
2065             outp->parmsp[parmSlot] = openMode; parmSlot++;
2066             outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2067             outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2068         }   
2069         /* and the final "always present" stuff */
2070         outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
2071         /* next write out the "unique" ID */
2072         outp->parmsp[parmSlot] = 0x1234; parmSlot++;
2073         outp->parmsp[parmSlot] = 0x5678; parmSlot++;
2074         outp->parmsp[parmSlot] = 0; parmSlot++;
2075         if (returnEALength) {
2076             outp->parmsp[parmSlot] = 0; parmSlot++;
2077             outp->parmsp[parmSlot] = 0; parmSlot++;
2078         }       
2079                 
2080         outp->totalData = 0;
2081         outp->totalParms = parmSlot * 2;
2082                 
2083         smb_SendTran2Packet(vcp, outp, op);
2084                 
2085         smb_FreeTran2Packet(outp);
2086
2087         /* and clean up fid reference */
2088         smb_ReleaseFID(fidp);
2089         return 0;
2090     }
2091
2092 #ifdef DEBUG_VERBOSE
2093     {
2094         char *hexp, *asciip;
2095         asciip = (lastNamep ? lastNamep : pathp);
2096         hexp = osi_HexifyString( asciip );
2097         DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2098         free(hexp);
2099     }       
2100 #endif
2101
2102     userp = smb_GetTran2User(vcp, p);
2103     /* In the off chance that userp is NULL, we log and abandon */
2104     if (!userp) {
2105         osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2106         smb_FreeTran2Packet(outp);
2107         return CM_ERROR_BADSMB;
2108     }
2109
2110     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2111     if (code == CM_ERROR_TIDIPC) {
2112         /* Attempt to use TID allocated for IPC.  The client is
2113            probably trying to locate DCE RPC end points, which
2114            we don't support. */
2115         osi_Log0(smb_logp, "Tran2Open received IPC TID");
2116         cm_ReleaseUser(userp);
2117         smb_FreeTran2Packet(outp);
2118         return CM_ERROR_NOSUCHPATH;
2119     }
2120
2121     dscp = NULL;
2122     code = cm_NameI(cm_rootSCachep, pathp,
2123                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2124                      userp, tidPathp, &req, &scp);
2125     if (code != 0) {
2126         code = cm_NameI(cm_rootSCachep, spacep->data,
2127                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2128                          userp, tidPathp, &req, &dscp);
2129         cm_FreeSpace(spacep);
2130
2131         if (code) {
2132             cm_ReleaseUser(userp);
2133             smb_FreeTran2Packet(outp);
2134             return code;
2135         }
2136         
2137         /* otherwise, scp points to the parent directory.  Do a lookup,
2138          * and truncate the file if we find it, otherwise we create the
2139          * file.
2140          */
2141         if (!lastNamep) 
2142             lastNamep = pathp;
2143         else 
2144             lastNamep++;
2145         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2146                          &req, &scp);
2147         if (code && code != CM_ERROR_NOSUCHFILE) {
2148             cm_ReleaseSCache(dscp);
2149             cm_ReleaseUser(userp);
2150             smb_FreeTran2Packet(outp);
2151             return code;
2152         }
2153     }
2154     else {
2155         cm_FreeSpace(spacep);
2156     }
2157         
2158     /* if we get here, if code is 0, the file exists and is represented by
2159      * scp.  Otherwise, we have to create it.
2160      */
2161     if (code == 0) {
2162         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2163         if (code) {
2164             if (dscp) cm_ReleaseSCache(dscp);
2165             cm_ReleaseSCache(scp);
2166             cm_ReleaseUser(userp);
2167             smb_FreeTran2Packet(outp);
2168             return code;
2169         }
2170
2171         if (excl) {
2172             /* oops, file shouldn't be there */
2173             if (dscp) cm_ReleaseSCache(dscp);
2174             cm_ReleaseSCache(scp);
2175             cm_ReleaseUser(userp);
2176             smb_FreeTran2Packet(outp);
2177             return CM_ERROR_EXISTS;
2178         }
2179
2180         if (trunc) {
2181             setAttr.mask = CM_ATTRMASK_LENGTH;
2182             setAttr.length.LowPart = 0;
2183             setAttr.length.HighPart = 0;
2184             code = cm_SetAttr(scp, &setAttr, userp, &req);
2185             openAction = 3;     /* truncated existing file */
2186         }   
2187         else 
2188             openAction = 1;     /* found existing file */
2189     }
2190     else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2191         /* don't create if not found */
2192         if (dscp) cm_ReleaseSCache(dscp);
2193         osi_assert(scp == NULL);
2194         cm_ReleaseUser(userp);
2195         smb_FreeTran2Packet(outp);
2196         return CM_ERROR_NOSUCHFILE;
2197     }
2198     else {
2199         osi_assert(dscp != NULL && scp == NULL);
2200         openAction = 2; /* created file */
2201         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2202         smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2203         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2204                           &req);
2205         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2206             smb_NotifyChange(FILE_ACTION_ADDED,
2207                              FILE_NOTIFY_CHANGE_FILE_NAME,  
2208                              dscp, lastNamep, NULL, TRUE);
2209         if (!excl && code == CM_ERROR_EXISTS) {
2210             /* not an exclusive create, and someone else tried
2211              * creating it already, then we open it anyway.  We
2212              * don't bother retrying after this, since if this next
2213              * fails, that means that the file was deleted after we
2214              * started this call.
2215              */
2216             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2217                               userp, &req, &scp);
2218             if (code == 0) {
2219                 if (trunc) {
2220                     setAttr.mask = CM_ATTRMASK_LENGTH;
2221                     setAttr.length.LowPart = 0;
2222                     setAttr.length.HighPart = 0;
2223                     code = cm_SetAttr(scp, &setAttr, userp,
2224                                        &req);
2225                 }   
2226             }   /* lookup succeeded */
2227         }
2228     }
2229         
2230     /* we don't need this any longer */
2231     if (dscp) cm_ReleaseSCache(dscp);
2232
2233     if (code) {
2234         /* something went wrong creating or truncating the file */
2235         if (scp) cm_ReleaseSCache(scp);
2236         cm_ReleaseUser(userp);
2237         smb_FreeTran2Packet(outp);
2238         return code;
2239     }
2240         
2241     /* make sure we're about to open a file */
2242     if (scp->fileType != CM_SCACHETYPE_FILE) {
2243         code = 0;
2244         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2245             cm_scache_t * targetScp = 0;
2246             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2247             if (code == 0) {
2248                 /* we have a more accurate file to use (the
2249                 * target of the symbolic link).  Otherwise,
2250                 * we'll just use the symlink anyway.
2251                 */
2252                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2253                           scp, targetScp);
2254                 cm_ReleaseSCache(scp);
2255                 scp = targetScp;
2256             }
2257         }
2258         if (scp->fileType != CM_SCACHETYPE_FILE) {
2259             cm_ReleaseSCache(scp);
2260             cm_ReleaseUser(userp);
2261             smb_FreeTran2Packet(outp);
2262             return CM_ERROR_ISDIR;
2263         }
2264     }
2265
2266     /* now all we have to do is open the file itself */
2267     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2268     osi_assert(fidp);
2269         
2270     /* save a pointer to the vnode */
2271     fidp->scp = scp;
2272         
2273     /* compute open mode */
2274     if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2275     if (openMode == 1 || openMode == 2)
2276         fidp->flags |= SMB_FID_OPENWRITE;
2277
2278     smb_ReleaseFID(fidp);
2279         
2280     cm_Open(scp, 0, userp);
2281
2282     /* copy out remainder of the parms */
2283     parmSlot = 0;
2284     outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2285     lock_ObtainMutex(&scp->mx);
2286     if (extraInfo) {
2287         outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2288         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2289         outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2290         outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2291         outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2292         parmSlot++;
2293         outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2294         parmSlot++;
2295         outp->parmsp[parmSlot] = openMode; parmSlot++;
2296         outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2297         outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2298     }   
2299     /* and the final "always present" stuff */
2300     outp->parmsp[parmSlot] = openAction; parmSlot++;
2301     /* next write out the "unique" ID */
2302     outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2303     outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2304     outp->parmsp[parmSlot] = 0; parmSlot++;
2305     if (returnEALength) {
2306         outp->parmsp[parmSlot] = 0; parmSlot++;
2307         outp->parmsp[parmSlot] = 0; parmSlot++;
2308     }   
2309     lock_ReleaseMutex(&scp->mx);
2310     outp->totalData = 0;                /* total # of data bytes */
2311     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
2312
2313     smb_SendTran2Packet(vcp, outp, op);
2314
2315     smb_FreeTran2Packet(outp);
2316
2317     cm_ReleaseUser(userp);
2318     /* leave scp held since we put it in fidp->scp */
2319     return 0;
2320 }   
2321
2322 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2323 {
2324     osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2325     return CM_ERROR_BADOP;
2326 }
2327
2328 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2329 {
2330     osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2331     return CM_ERROR_BADOP;
2332 }
2333
2334 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2335 {
2336     smb_tran2Packet_t *outp;
2337     smb_tran2QFSInfo_t qi;
2338     int responseSize;
2339     osi_hyper_t temp;
2340     static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2341         
2342     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2343
2344     switch (p->parmsp[0]) {
2345     case 1: responseSize = sizeof(qi.u.allocInfo); break;
2346     case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2347     case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2348     case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2349     case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2350     case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2351     default: return CM_ERROR_INVAL;
2352     }
2353
2354     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2355     switch (p->parmsp[0]) {
2356     case 1:
2357         /* alloc info */
2358         qi.u.allocInfo.FSID = 0;
2359         qi.u.allocInfo.sectorsPerAllocUnit = 1;
2360         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2361         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2362         qi.u.allocInfo.bytesPerSector = 1024;
2363         break;
2364
2365     case 2:
2366         /* volume info */
2367         qi.u.volumeInfo.vsn = 1234;
2368         qi.u.volumeInfo.vnCount = 4;
2369         /* we're supposed to pad it out with zeroes to the end */
2370         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2371         memcpy(qi.u.volumeInfo.label, "AFS", 4);
2372         break;
2373
2374     case 0x102:
2375         /* FS volume info */
2376         memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2377         qi.u.FSvolumeInfo.vsn = 1234;
2378         qi.u.FSvolumeInfo.vnCount = 8;
2379         memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2380         break;
2381
2382     case 0x103:
2383         /* FS size info */
2384         temp.HighPart = 0;
2385         temp.LowPart = 0x7fffffff;
2386         qi.u.FSsizeInfo.totalAllocUnits = temp;
2387         temp.LowPart = 0x3fffffff;
2388         qi.u.FSsizeInfo.availAllocUnits = temp;
2389         qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2390         qi.u.FSsizeInfo.bytesPerSector = 1024;
2391         break;
2392
2393     case 0x104:
2394         /* FS device info */
2395         qi.u.FSdeviceInfo.devType = 0;  /* don't have a number */
2396         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2397         break;
2398
2399         case 0x105:
2400         /* FS attribute info */
2401         /* attributes, defined in WINNT.H:
2402          *      FILE_CASE_SENSITIVE_SEARCH      0x1
2403          *      FILE_CASE_PRESERVED_NAMES       0x2
2404          *      <no name defined>               0x4000
2405          *         If bit 0x4000 is not set, Windows 95 thinks
2406          *         we can't handle long (non-8.3) names,
2407          *         despite our protestations to the contrary.
2408          */
2409         qi.u.FSattributeInfo.attributes = 0x4003;
2410         qi.u.FSattributeInfo.maxCompLength = 255;
2411         qi.u.FSattributeInfo.FSnameLength = 6;
2412         memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2413         break;
2414     }   
2415         
2416     /* copy out return data, and set corresponding sizes */
2417     outp->totalParms = 0;
2418     outp->totalData = responseSize;
2419     memcpy(outp->datap, &qi, responseSize);
2420
2421     /* send and free the packets */
2422     smb_SendTran2Packet(vcp, outp, op);
2423     smb_FreeTran2Packet(outp);
2424
2425     return 0;
2426 }
2427
2428 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2429 {
2430     osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2431     return CM_ERROR_BADOP;
2432 }
2433
2434 struct smb_ShortNameRock {
2435     char *maskp;
2436     unsigned int vnode;
2437     char *shortName;
2438     size_t shortNameLen;
2439 };      
2440
2441 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2442                          osi_hyper_t *offp)
2443 {       
2444     struct smb_ShortNameRock *rockp;
2445     char *shortNameEnd;
2446
2447     rockp = vrockp;
2448     /* compare both names and vnodes, though probably just comparing vnodes
2449      * would be safe enough.
2450      */
2451     if (cm_stricmp(dep->name, rockp->maskp) != 0)
2452         return 0;
2453     if (ntohl(dep->fid.vnode) != rockp->vnode)
2454         return 0;
2455     /* This is the entry */
2456     cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2457     rockp->shortNameLen = shortNameEnd - rockp->shortName;
2458     return CM_ERROR_STOPNOW;
2459 }       
2460
2461 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2462         char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2463 {
2464     struct smb_ShortNameRock rock;
2465     char *lastNamep;
2466     cm_space_t *spacep;
2467     cm_scache_t *dscp;
2468     int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2469     long code = 0;
2470     osi_hyper_t thyper;
2471
2472     spacep = cm_GetSpace();
2473     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2474
2475     code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2476                      reqp, &dscp);
2477     cm_FreeSpace(spacep);
2478     if (code) return code;
2479
2480     if (!lastNamep) lastNamep = pathp;
2481     else lastNamep++;
2482     thyper.LowPart = 0;
2483     thyper.HighPart = 0;
2484     rock.shortName = shortName;
2485     rock.vnode = vnode;
2486     rock.maskp = lastNamep;
2487     code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2488
2489     cm_ReleaseSCache(dscp);
2490
2491     if (code == 0)
2492         return CM_ERROR_NOSUCHFILE;
2493     if (code == CM_ERROR_STOPNOW) {
2494         *shortNameLenp = rock.shortNameLen;
2495         return 0;
2496     }
2497     return code;
2498 }
2499
2500 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2501 {
2502     smb_tran2Packet_t *outp;
2503     time_t dosTime;
2504     FILETIME ft;
2505     unsigned short infoLevel;
2506     int nbytesRequired;
2507     unsigned short attributes;
2508     unsigned long extAttributes;
2509     char shortName[13];
2510     unsigned int len;
2511     cm_user_t *userp;
2512     cm_space_t *spacep;
2513     cm_scache_t *scp, *dscp;
2514     long code = 0;
2515     char *op;
2516     char *tidPathp;
2517     char *lastComp;
2518     cm_req_t req;
2519
2520     cm_InitReq(&req);
2521
2522     infoLevel = p->parmsp[0];
2523     if (infoLevel == 6) nbytesRequired = 0;
2524     else if (infoLevel == 1) nbytesRequired = 22;
2525     else if (infoLevel == 2) nbytesRequired = 26;
2526     else if (infoLevel == 0x101) nbytesRequired = 40;
2527     else if (infoLevel == 0x102) nbytesRequired = 24;
2528     else if (infoLevel == 0x103) nbytesRequired = 4;
2529     else if (infoLevel == 0x108) nbytesRequired = 30;
2530     else {
2531         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2532                   p->opcode, infoLevel);
2533         smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2534         return 0;
2535     }
2536     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2537               osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2538
2539     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2540
2541     if (infoLevel > 0x100)
2542         outp->totalParms = 2;
2543     else
2544         outp->totalParms = 0;
2545     outp->totalData = nbytesRequired;
2546         
2547     /* now, if we're at infoLevel 6, we're only being asked to check
2548      * the syntax, so we just OK things now.  In particular, we're *not*
2549      * being asked to verify anything about the state of any parent dirs.
2550      */
2551     if (infoLevel == 6) {
2552         smb_SendTran2Packet(vcp, outp, opx);
2553         smb_FreeTran2Packet(outp);
2554         return 0;
2555     }   
2556         
2557     userp = smb_GetTran2User(vcp, p);
2558     if (!userp) {
2559         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2560         smb_FreeTran2Packet(outp);
2561         return CM_ERROR_BADSMB;
2562     }
2563
2564     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2565     if(code) {
2566         cm_ReleaseUser(userp);
2567         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2568         smb_FreeTran2Packet(outp);
2569         return 0;
2570     }
2571
2572     /*
2573      * XXX Strange hack XXX
2574      *
2575      * As of Patch 7 (13 January 98), we are having the following problem:
2576      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2577      * requests to look up "desktop.ini" in all the subdirectories.
2578      * This can cause zillions of timeouts looking up non-existent cells
2579      * and volumes, especially in the top-level directory.
2580      *
2581      * We have not found any way to avoid this or work around it except
2582      * to explicitly ignore the requests for mount points that haven't
2583      * yet been evaluated and for directories that haven't yet been
2584      * fetched.
2585      */
2586     if (infoLevel == 0x101) {
2587         spacep = cm_GetSpace();
2588         smb_StripLastComponent(spacep->data, &lastComp,
2589                                 (char *)(&p->parmsp[3]));
2590 #ifndef SPECIAL_FOLDERS
2591         /* Make sure that lastComp is not NULL */
2592         if (lastComp) {
2593             if (stricmp(lastComp, "\\desktop.ini") == 0) {
2594                 code = cm_NameI(cm_rootSCachep, spacep->data,
2595                                  CM_FLAG_CASEFOLD
2596                                  | CM_FLAG_DIRSEARCH
2597                                  | CM_FLAG_FOLLOW,
2598                                  userp, tidPathp, &req, &dscp);
2599                 if (code == 0) {
2600                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2601                          && !dscp->mountRootFidp)
2602                         code = CM_ERROR_NOSUCHFILE;
2603                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2604                         cm_buf_t *bp = buf_Find(dscp, &hzero);
2605                         if (bp)
2606                             buf_Release(bp);
2607                         else
2608                             code = CM_ERROR_NOSUCHFILE;
2609                     }
2610                     cm_ReleaseSCache(dscp);
2611                     if (code) {
2612                         cm_FreeSpace(spacep);
2613                         cm_ReleaseUser(userp);
2614                         smb_SendTran2Error(vcp, p, opx, code);
2615                         smb_FreeTran2Packet(outp);
2616                         return 0;
2617                     }
2618                 }
2619             }
2620         }
2621 #endif /* SPECIAL_FOLDERS */
2622
2623         cm_FreeSpace(spacep);
2624     }
2625
2626     /* now do namei and stat, and copy out the info */
2627     code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2628                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2629
2630     if (code) {
2631         cm_ReleaseUser(userp);
2632         smb_SendTran2Error(vcp, p, opx, code);
2633         smb_FreeTran2Packet(outp);
2634         return 0;
2635     }
2636
2637     lock_ObtainMutex(&scp->mx);
2638     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2639                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2640     if (code) goto done;
2641         
2642     /* now we have the status in the cache entry, and everything is locked.
2643      * Marshall the output data.
2644      */
2645     op = outp->datap;
2646     /* for info level 108, figure out short name */
2647     if (infoLevel == 0x108) {
2648         code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2649                                 tidPathp, scp->fid.vnode, shortName,
2650                                 (size_t *) &len);
2651         if (code) {
2652             goto done;
2653         }
2654
2655         op = outp->datap;
2656         *((u_long *)op) = len * 2; op += 4;
2657         mbstowcs((unsigned short *)op, shortName, len);
2658         op += (len * 2);
2659
2660         goto done;
2661     }
2662     if (infoLevel == 1 || infoLevel == 2) {
2663         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2664         *((u_long *)op) = dosTime; op += 4;     /* creation time */
2665         *((u_long *)op) = dosTime; op += 4;     /* access time */
2666         *((u_long *)op) = dosTime; op += 4;     /* write time */
2667         *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2668         *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2669         attributes = smb_Attributes(scp);
2670         *((u_short *)op) = attributes; op += 2; /* attributes */
2671     }
2672     else if (infoLevel == 0x101) {
2673         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2674         *((FILETIME *)op) = ft; op += 8;        /* creation time */
2675         *((FILETIME *)op) = ft; op += 8;        /* last access time */
2676         *((FILETIME *)op) = ft; op += 8;        /* last write time */
2677         *((FILETIME *)op) = ft; op += 8;        /* last change time */
2678         extAttributes = smb_ExtAttributes(scp);
2679         *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2680         *((u_long *)op) = 0; op += 4;   /* don't know what this is */
2681     }
2682     else if (infoLevel == 0x102) {
2683         *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
2684         *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
2685         *((u_long *)op) = scp->linkCount; op += 4;
2686         *op++ = 0;
2687         *op++ = 0;
2688         *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2689         *op++ = 0;
2690     }
2691     else if (infoLevel == 0x103) {
2692         memset(op, 0, 4); op += 4;      /* EA size */
2693     }
2694
2695     /* now, if we are being asked about extended attrs, return a 0 size */
2696     if (infoLevel == 2) {
2697         *((u_long *)op) = 0; op += 4;
2698     }
2699
2700
2701     /* send and free the packets */
2702   done:
2703     lock_ReleaseMutex(&scp->mx);
2704     cm_ReleaseSCache(scp);
2705     cm_ReleaseUser(userp);
2706     if (code == 0) 
2707         smb_SendTran2Packet(vcp, outp, opx);
2708     else 
2709         smb_SendTran2Error(vcp, p, opx, code);
2710     smb_FreeTran2Packet(outp);
2711
2712     return 0;
2713 }
2714
2715 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2716 {
2717     osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2718     return CM_ERROR_BADOP;
2719 }
2720
2721 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2722 {
2723     smb_tran2Packet_t *outp;
2724     FILETIME ft;
2725     unsigned long attributes;
2726     unsigned short infoLevel;
2727     int nbytesRequired;
2728     unsigned short fid;
2729     cm_user_t *userp;
2730     smb_fid_t *fidp;
2731     cm_scache_t *scp;
2732     char *op;
2733     long code = 0;
2734     cm_req_t req;
2735
2736     cm_InitReq(&req);
2737
2738     fid = p->parmsp[0];
2739     fidp = smb_FindFID(vcp, fid, 0);
2740
2741     if (fidp == NULL) {
2742         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2743         return 0;
2744     }
2745
2746     infoLevel = p->parmsp[1];
2747     if (infoLevel == 0x101) nbytesRequired = 40;
2748     else if (infoLevel == 0x102) nbytesRequired = 24;
2749     else if (infoLevel == 0x103) nbytesRequired = 4;
2750     else if (infoLevel == 0x104) nbytesRequired = 6;
2751     else {
2752         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2753                   p->opcode, infoLevel);
2754         smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2755         smb_ReleaseFID(fidp);
2756         return 0;
2757     }
2758     osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2759
2760     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2761
2762     if (infoLevel > 0x100)
2763         outp->totalParms = 2;
2764     else
2765         outp->totalParms = 0;
2766     outp->totalData = nbytesRequired;
2767
2768     userp = smb_GetTran2User(vcp, p);
2769     if (!userp) {
2770         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2771         code = CM_ERROR_BADSMB;
2772         goto done;
2773     }   
2774
2775     scp = fidp->scp;
2776     lock_ObtainMutex(&scp->mx);
2777     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2778                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2779     if (code) 
2780         goto done;
2781
2782     /* now we have the status in the cache entry, and everything is locked.
2783      * Marshall the output data.
2784      */
2785     op = outp->datap;
2786     if (infoLevel == 0x101) {
2787         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2788         *((FILETIME *)op) = ft; op += 8;        /* creation time */
2789         *((FILETIME *)op) = ft; op += 8;        /* last access time */
2790         *((FILETIME *)op) = ft; op += 8;        /* last write time */
2791         *((FILETIME *)op) = ft; op += 8;        /* last change time */
2792         attributes = smb_ExtAttributes(scp);
2793         *((u_long *)op) = attributes; op += 4;
2794         *((u_long *)op) = 0; op += 4;
2795     }
2796     else if (infoLevel == 0x102) {
2797         *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
2798         *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
2799         *((u_long *)op) = scp->linkCount; op += 4;
2800         *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2801         *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2802         *op++ = 0;
2803         *op++ = 0;
2804     }
2805     else if (infoLevel == 0x103) {
2806         *((u_long *)op) = 0; op += 4;
2807     }
2808     else if (infoLevel == 0x104) {
2809         unsigned long len;
2810         char *name;
2811
2812         if (fidp->NTopen_wholepathp)
2813             name = fidp->NTopen_wholepathp;
2814         else
2815             name = "\\";        /* probably can't happen */
2816         len = strlen(name);
2817         outp->totalData = (len*2) + 4;  /* this is actually what we want to return */
2818         *((u_long *)op) = len * 2; op += 4;
2819         mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2820     }
2821
2822     /* send and free the packets */
2823   done:
2824     lock_ReleaseMutex(&scp->mx);
2825     cm_ReleaseUser(userp);
2826     smb_ReleaseFID(fidp);
2827     if (code == 0) 
2828         smb_SendTran2Packet(vcp, outp, opx);
2829     else 
2830         smb_SendTran2Error(vcp, p, opx, code);
2831     smb_FreeTran2Packet(outp);
2832
2833     return 0;
2834 }       
2835
2836 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2837 {
2838     long code = 0;
2839     unsigned short fid;
2840     smb_fid_t *fidp;
2841     unsigned short infoLevel;
2842     smb_tran2Packet_t *outp;
2843     cm_user_t *userp;
2844     cm_scache_t *scp;
2845     cm_req_t req;
2846
2847     cm_InitReq(&req);
2848
2849     fid = p->parmsp[0];
2850     fidp = smb_FindFID(vcp, fid, 0);
2851
2852     if (fidp == NULL) {
2853         smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2854         return 0;
2855     }
2856
2857     infoLevel = p->parmsp[1];
2858     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2859     if (infoLevel > 0x104 || infoLevel < 0x101) {
2860         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2861                   p->opcode, infoLevel);
2862         smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2863         smb_ReleaseFID(fidp);
2864         return 0;
2865     }
2866
2867     if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2868         smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2869         smb_ReleaseFID(fidp);
2870         return 0;
2871     }
2872     if ((infoLevel == 0x103 || infoLevel == 0x104)
2873          && !(fidp->flags & SMB_FID_OPENWRITE)) {
2874         smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2875         smb_ReleaseFID(fidp);
2876         return 0;
2877     }
2878
2879     osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2880
2881     outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2882
2883     outp->totalParms = 2;
2884     outp->totalData = 0;
2885
2886     userp = smb_GetTran2User(vcp, p);
2887     if (!userp) {
2888         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2889         code = CM_ERROR_BADSMB;
2890         goto done;
2891     }   
2892
2893     scp = fidp->scp;
2894
2895     if (infoLevel == 0x101) {
2896         FILETIME lastMod;
2897         unsigned int attribute;
2898         cm_attr_t attr;
2899
2900         /* lock the vnode with a callback; we need the current status
2901          * to determine what the new status is, in some cases.
2902          */
2903         lock_ObtainMutex(&scp->mx);
2904         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2905                           CM_SCACHESYNC_GETSTATUS
2906                          | CM_SCACHESYNC_NEEDCALLBACK);
2907         if (code) {
2908             lock_ReleaseMutex(&scp->mx);
2909             goto done;
2910         }
2911
2912         /* prepare for setattr call */
2913         attr.mask = 0;
2914
2915         lastMod = *((FILETIME *)(p->datap + 16));
2916         /* when called as result of move a b, lastMod is (-1, -1). 
2917          * If the check for -1 is not present, timestamp
2918          * of the resulting file will be 1969 (-1)
2919          */
2920         if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
2921              lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2922             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2923             smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2924                                              &lastMod);
2925             fidp->flags |= SMB_FID_MTIMESETDONE;
2926         }
2927                 
2928         attribute = *((u_long *)(p->datap + 32));
2929         if (attribute != 0) {
2930             if ((scp->unixModeBits & 0222)
2931                  && (attribute & 1) != 0) {
2932                 /* make a writable file read-only */
2933                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2934                 attr.unixModeBits = scp->unixModeBits & ~0222;
2935             }
2936             else if ((scp->unixModeBits & 0222) == 0
2937                       && (attribute & 1) == 0) {
2938                 /* make a read-only file writable */
2939                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2940                 attr.unixModeBits = scp->unixModeBits | 0222;
2941             }
2942         }
2943         lock_ReleaseMutex(&scp->mx);
2944
2945         /* call setattr */
2946         if (attr.mask)
2947             code = cm_SetAttr(scp, &attr, userp, &req);
2948         else
2949             code = 0;
2950     }               
2951     else if (infoLevel == 0x103 || infoLevel == 0x104) {
2952         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2953         cm_attr_t attr;
2954
2955         attr.mask = CM_ATTRMASK_LENGTH;
2956         attr.length.LowPart = size.LowPart;
2957         attr.length.HighPart = size.HighPart;
2958         code = cm_SetAttr(scp, &attr, userp, &req);
2959     }       
2960     else if (infoLevel == 0x102) {
2961         if (*((char *)(p->datap))) {
2962             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2963                                      &req);
2964             if (code == 0)          
2965                 fidp->flags |= SMB_FID_DELONCLOSE;
2966         }               
2967         else {  
2968             code = 0;
2969             fidp->flags &= ~SMB_FID_DELONCLOSE;
2970         }
2971     }       
2972
2973   done:
2974     cm_ReleaseUser(userp);
2975     smb_ReleaseFID(fidp);
2976     if (code == 0) 
2977         smb_SendTran2Packet(vcp, outp, op);
2978     else 
2979         smb_SendTran2Error(vcp, p, op, code);
2980     smb_FreeTran2Packet(outp);
2981
2982     return 0;
2983 }
2984
2985 long 
2986 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2987 {
2988     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
2989     return CM_ERROR_BADOP;
2990 }
2991
2992 long 
2993 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2994 {
2995     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
2996     return CM_ERROR_BADOP;
2997 }
2998
2999 long 
3000 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3001 {
3002     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3003     return CM_ERROR_BADOP;
3004 }
3005
3006 long 
3007 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3008 {
3009     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3010     return CM_ERROR_BADOP;
3011 }
3012
3013 long 
3014 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3015 {
3016     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3017     return CM_ERROR_BADOP;
3018 }
3019
3020 long 
3021 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3022 {
3023     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3024     return CM_ERROR_BADOP;
3025 }
3026
3027 long 
3028 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3029 {
3030     osi_Log0(smb_logp,"ReceiveTran2GetDFSReferral - NOT_SUPPORTED");
3031     return CM_ERROR_BADOP;
3032 }
3033
3034 long 
3035 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3036 {
3037     osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3038     return CM_ERROR_BADOP;
3039 }
3040
3041 long 
3042 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3043         smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3044         cm_req_t *reqp)
3045 {
3046     long code = 0;
3047     cm_scache_t *scp;
3048     cm_scache_t *targetScp;                     /* target if scp is a symlink */
3049     char *dptr;
3050     time_t dosTime;
3051     FILETIME ft;
3052     int shortTemp;
3053     unsigned short attr;
3054     unsigned long lattr;
3055     smb_dirListPatch_t *patchp;
3056     smb_dirListPatch_t *npatchp;
3057         
3058     for(patchp = *dirPatchespp; patchp; patchp =
3059          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3060                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3061         if (code) continue;
3062         lock_ObtainMutex(&scp->mx);
3063         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3064                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3065         if (code) { 
3066             lock_ReleaseMutex(&scp->mx);
3067             cm_ReleaseSCache(scp);
3068
3069             dptr = patchp->dptr;
3070
3071             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3072                errors in the client. */
3073             if (infoLevel >= 0x101) {
3074                 /* 1969-12-31 23:59:59 +00 */
3075                 ft.dwHighDateTime = 0x19DB200;
3076                 ft.dwLowDateTime = 0x5BB78980;
3077
3078                 /* copy to Creation Time */
3079                 *((FILETIME *)dptr) = ft;
3080                 dptr += 8;
3081
3082                 /* copy to Last Access Time */
3083                 *((FILETIME *)dptr) = ft;
3084                 dptr += 8;
3085
3086                 /* copy to Last Write Time */
3087                 *((FILETIME *)dptr) = ft;
3088                 dptr += 8;
3089
3090                 /* copy to Change Time */
3091                 *((FILETIME *)dptr) = ft;
3092                 dptr += 24;
3093
3094                 /* merge in hidden attribute */
3095                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3096                     *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3097                 }
3098                 dptr += 4;
3099             } else {
3100                 /* 1969-12-31 23:59:58 +00*/
3101                 dosTime = 0xEBBFBF7D;
3102
3103                 /* and copy out date */
3104                 shortTemp = (dosTime>>16) & 0xffff;
3105                 *((u_short *)dptr) = shortTemp;
3106                 dptr += 2;
3107
3108                 /* copy out creation time */
3109                 shortTemp = dosTime & 0xffff;
3110                 *((u_short *)dptr) = shortTemp;
3111                 dptr += 2;
3112
3113                 /* and copy out date */
3114                 shortTemp = (dosTime>>16) & 0xffff;
3115                 *((u_short *)dptr) = shortTemp;
3116                 dptr += 2;
3117                         
3118                 /* copy out access time */
3119                 shortTemp = dosTime & 0xffff;
3120                 *((u_short *)dptr) = shortTemp;
3121                 dptr += 2;
3122
3123                 /* and copy out date */
3124                 shortTemp = (dosTime>>16) & 0xffff;
3125                 *((u_short *)dptr) = shortTemp;
3126                 dptr += 2;
3127                         
3128                 /* copy out mod time */
3129                 shortTemp = dosTime & 0xffff;
3130                 *((u_short *)dptr) = shortTemp;
3131                 dptr += 10;
3132
3133                 /* merge in hidden (dot file) attribute */
3134                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3135                     attr = SMB_ATTR_HIDDEN;
3136                     *dptr++ = attr & 0xff;
3137                     *dptr++ = (attr >> 8) & 0xff;
3138                 }       
3139             }
3140             continue;
3141         }
3142                 
3143         /* now watch for a symlink */
3144         code = 0;
3145         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3146             lock_ReleaseMutex(&scp->mx);
3147             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3148             if (code == 0) {
3149                 /* we have a more accurate file to use (the
3150                  * target of the symbolic link).  Otherwise,
3151                  * we'll just use the symlink anyway.
3152                  */
3153                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3154                           scp, targetScp);
3155                 cm_ReleaseSCache(scp);
3156                 scp = targetScp;
3157             }
3158             lock_ObtainMutex(&scp->mx);
3159         }
3160
3161         dptr = patchp->dptr;
3162
3163         if (infoLevel >= 0x101) {
3164             /* get filetime */
3165             smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3166
3167             /* copy to Creation Time */
3168             *((FILETIME *)dptr) = ft;
3169             dptr += 8;
3170
3171             /* copy to Last Access Time */
3172             *((FILETIME *)dptr) = ft;
3173             dptr += 8;
3174
3175             /* copy to Last Write Time */
3176             *((FILETIME *)dptr) = ft;
3177             dptr += 8;
3178
3179             /* copy to Change Time */
3180             *((FILETIME *)dptr) = ft;
3181             dptr += 8;
3182
3183             /* Use length for both file length and alloc length */
3184             *((LARGE_INTEGER *)dptr) = scp->length;
3185             dptr += 8;
3186             *((LARGE_INTEGER *)dptr) = scp->length;
3187             dptr += 8;
3188
3189             /* Copy attributes */
3190             lattr = smb_ExtAttributes(scp);
3191             /* merge in hidden (dot file) attribute */
3192             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3193                 lattr |= SMB_ATTR_HIDDEN;
3194             *((u_long *)dptr) = lattr;
3195             dptr += 4;
3196         }
3197         else {
3198             /* get dos time */
3199             smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3200
3201             /* and copy out date */
3202             shortTemp = (dosTime>>16) & 0xffff;
3203             *((u_short *)dptr) = shortTemp;
3204             dptr += 2;
3205
3206             /* copy out creation time */
3207             shortTemp = dosTime & 0xffff;
3208             *((u_short *)dptr) = shortTemp;
3209             dptr += 2;
3210
3211             /* and copy out date */
3212             shortTemp = (dosTime>>16) & 0xffff;
3213             *((u_short *)dptr) = shortTemp;
3214             dptr += 2;
3215
3216             /* copy out access time */
3217             shortTemp = dosTime & 0xffff;
3218             *((u_short *)dptr) = shortTemp;
3219             dptr += 2;
3220
3221             /* and copy out date */
3222             shortTemp = (dosTime>>16) & 0xffff;
3223             *((u_short *)dptr) = shortTemp;
3224             dptr += 2;
3225
3226             /* copy out mod time */
3227             shortTemp = dosTime & 0xffff;
3228             *((u_short *)dptr) = shortTemp;
3229             dptr += 2;
3230
3231             /* copy out file length and alloc length,
3232              * using the same for both
3233              */
3234             *((u_long *)dptr) = scp->length.LowPart;
3235             dptr += 4;
3236             *((u_long *)dptr) = scp->length.LowPart;
3237             dptr += 4;
3238
3239             /* finally copy out attributes as short */
3240             attr = smb_Attributes(scp);
3241             /* merge in hidden (dot file) attribute */
3242             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3243                 attr |= SMB_ATTR_HIDDEN;
3244             *dptr++ = attr & 0xff;
3245             *dptr++ = (attr >> 8) & 0xff;
3246         }
3247
3248         lock_ReleaseMutex(&scp->mx);
3249         cm_ReleaseSCache(scp);
3250     }
3251         
3252     /* now free the patches */
3253     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3254         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3255         free(patchp);
3256     }
3257         
3258     /* and mark the list as empty */
3259     *dirPatchespp = NULL;
3260
3261     return code;
3262 }
3263
3264 #ifndef USE_OLD_MATCHING
3265 // char table for case insensitive comparison
3266 char mapCaseTable[256];
3267
3268 VOID initUpperCaseTable(VOID) 
3269 {
3270     int i;
3271     for (i = 0; i < 256; ++i) 
3272        mapCaseTable[i] = toupper(i);
3273     // make '"' match '.' 
3274     mapCaseTable[(int)'"'] = toupper('.');
3275     // make '<' match '*' 
3276     mapCaseTable[(int)'<'] = toupper('*');
3277     // make '>' match '?' 
3278     mapCaseTable[(int)'>'] = toupper('?');    
3279 }
3280
3281 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3282 // name 'name'.
3283 // Note : this procedure works recursively calling itself.
3284 // Parameters
3285 // PSZ pattern    : string containing metacharacters.
3286 // PSZ name       : file name to be compared with 'pattern'.
3287 // Return value
3288 // BOOL : TRUE/FALSE (match/mistmatch)
3289
3290 BOOL 
3291 szWildCardMatchFileName(PSZ pattern, PSZ name) 
3292 {
3293     PSZ pename;         // points to the last 'name' character
3294     PSZ p;
3295     pename = name + strlen(name) - 1;
3296     while (*name) {
3297         switch (*pattern) {
3298         case '?':
3299             if (*name == '.') 
3300                 return FALSE;
3301             ++pattern, ++name;
3302             break;
3303          case '*':
3304             ++pattern;
3305             if (*pattern == '\0')
3306                 return TRUE;
3307             for (p = pename; p >= name; --p) {
3308                 if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3309                      szWildCardMatchFileName(pattern + 1, p + 1))
3310                     return TRUE;
3311             } /* endfor */
3312             return FALSE;
3313         default:
3314             if (mapCaseTable[*name] != mapCaseTable[*pattern]) 
3315                 return FALSE;
3316             ++pattern, ++name;
3317             break;
3318         } /* endswitch */
3319     } /* endwhile */ 
3320
3321     if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
3322         return TRUE;
3323     else 
3324         return FALSE;
3325 }
3326
3327 /* do a case-folding search of the star name mask with the name in namep.
3328  * Return 1 if we match, otherwise 0.
3329  */
3330 int smb_V3MatchMask(char *namep, char *maskp, int flags) 
3331 {
3332     char * newmask;
3333     int    i, j, star, qmark, retval;
3334
3335     /* make sure we only match 8.3 names, if requested */
3336     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
3337         return 0;
3338     
3339     /* optimize the pattern:
3340      * if there is a mixture of '?' and '*',
3341      * for example  the sequence "*?*?*?*"
3342      * must be turned into the form "*"
3343      */
3344     newmask = (char *)malloc(strlen(maskp)+1);
3345     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3346         switch ( maskp[i] ) {
3347         case '?':
3348         case '>':
3349             qmark++;
3350             break;
3351         case '<':
3352         case '*':
3353             star++;
3354             break;
3355         default:
3356             if ( star ) {
3357                 newmask[j++] = '*';
3358             } else if ( qmark ) {
3359                 while ( qmark-- )
3360                     newmask[j++] = '?';
3361             }
3362             newmask[j++] = maskp[i];
3363             star = 0;
3364             qmark = 0;
3365         }
3366     }
3367     if ( star ) {
3368         newmask[j++] = '*';
3369     } else if ( qmark ) {
3370         while ( qmark-- )
3371             newmask[j++] = '?';
3372     }
3373     newmask[j++] = '\0';
3374
3375     retval = szWildCardMatchFileName(newmask, namep) ? 1:0;
3376
3377     free(newmask);
3378     return retval;
3379 }
3380
3381 #else /* USE_OLD_MATCHING */
3382 /* do a case-folding search of the star name mask with the name in namep.
3383  * Return 1 if we match, otherwise 0.
3384  */
3385 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3386 {
3387     unsigned char tcp1, tcp2;   /* Pattern characters */
3388     unsigned char tcn1;         /* Name characters */
3389     int sawDot = 0, sawStar = 0, req8dot3 = 0;
3390     char *starNamep, *starMaskp;
3391     static char nullCharp[] = {0};
3392     int casefold = flags & CM_FLAG_CASEFOLD;
3393
3394     /* make sure we only match 8.3 names, if requested */
3395     req8dot3 = (flags & CM_FLAG_8DOT3);
3396     if (req8dot3 && !cm_Is8Dot3(namep)) 
3397         return 0;
3398
3399     /* loop */
3400     while (1) {
3401         /* Next pattern character */
3402         tcp1 = *maskp++;
3403
3404         /* Next name character */
3405         tcn1 = *namep;
3406
3407         if (tcp1 == 0) {
3408             /* 0 - end of pattern */
3409             if (tcn1 == 0)
3410                 return 1;
3411             else
3412                 return 0;
3413         }
3414         else if (tcp1 == '.' || tcp1 == '"') {
3415             if (sawDot) {
3416                 if (tcn1 == '.') {
3417                     namep++;
3418                     continue;
3419                 } else
3420                     return 0;
3421             }
3422             else {
3423                 /*
3424                  * first dot in pattern;
3425                  * must match dot or end of name
3426                  */
3427                 sawDot = 1;
3428                 if (tcn1 == 0)
3429                     continue;
3430                 else if (tcn1 == '.') {
3431                     sawStar = 0;
3432                     namep++;
3433                     continue;
3434                 }
3435                 else
3436                     return 0;
3437             }
3438         }
3439         else if (tcp1 == '?') {
3440             if (tcn1 == 0 || tcn1 == '.')
3441                 return 0;
3442             namep++;
3443             continue;
3444         }
3445         else if (tcp1 == '>') {
3446             if (tcn1 != 0 && tcn1 != '.')
3447                 namep++;
3448             continue;
3449         }
3450         else if (tcp1 == '*' || tcp1 == '<') {
3451             tcp2 = *maskp++;
3452             if (tcp2 == 0)
3453                 return 1;
3454             else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3455                 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3456                     tcn1 = *++namep;
3457                 if (tcn1 == 0) {
3458                     if (sawDot)
3459                         return 0;
3460                     else
3461                         continue;
3462                 }
3463                 else {
3464                     namep++;
3465                     continue;
3466                 }
3467             }
3468             else {
3469                 /*
3470                  * pattern character after '*' is not null or
3471                  * period.  If it is '?' or '>', we are not
3472                  * going to understand it.  If it is '*' or
3473                  * '<', we are going to skip over it.  None of
3474                  * these are likely, I hope.
3475                  */
3476                 /* skip over '*' and '<' */
3477                 while (tcp2 == '*' || tcp2 == '<')
3478                     tcp2 = *maskp++;
3479
3480                 /* skip over characters that don't match tcp2 */
3481                 while (req8dot3 && tcn1 != '.' && tcn1 != 0 && 
3482                         ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
3483                           (!casefold && tcn1 != tcp2)))
3484                     tcn1 = *++namep;
3485
3486                 /* No match */
3487                 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3488                     return 0;
3489
3490                 /* Remember where we are */
3491                 sawStar = 1;
3492                 starMaskp = maskp;
3493                 starNamep = namep;
3494
3495                 namep++;
3496                 continue;
3497             }
3498         }
3499         else {
3500             /* tcp1 is not a wildcard */
3501             if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
3502                  (!casefold && tcn1 == tcp1)) {
3503                 /* they match */
3504                 namep++;
3505                 continue;
3506             }
3507             /* if trying to match a star pattern, go back */
3508             if (sawStar) {
3509                 maskp = starMaskp - 2;
3510                 namep = starNamep + 1;
3511                 sawStar = 0;
3512                 continue;
3513             }
3514             /* that's all */
3515             return 0;
3516         }
3517     }
3518 }
3519 #endif /* USE_OLD_MATCHING */
3520
3521 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3522 {
3523     int attribute;
3524     long nextCookie;
3525     char *tp;
3526     long code = 0;
3527     char *pathp;
3528     cm_dirEntry_t *dep;
3529     int maxCount;
3530     smb_dirListPatch_t *dirListPatchesp;
3531     smb_dirListPatch_t *curPatchp;
3532     cm_buf_t *bufferp;
3533     long temp;
3534     long orbytes;                       /* # of bytes in this output record */
3535     long ohbytes;                       /* # of bytes, except file name */
3536     long onbytes;                       /* # of bytes in name, incl. term. null */
3537     osi_hyper_t dirLength;
3538     osi_hyper_t bufferOffset;
3539     osi_hyper_t curOffset;
3540     osi_hyper_t thyper;
3541     smb_dirSearch_t *dsp;
3542     cm_scache_t *scp;
3543     long entryInDir;
3544     long entryInBuffer;
3545     cm_pageHeader_t *pageHeaderp;
3546     cm_user_t *userp = NULL;
3547     int slotInPage;
3548     int returnedNames;
3549     long nextEntryCookie;
3550     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
3551     char *op;                   /* output data ptr */
3552     char *origOp;                       /* original value of op */
3553     cm_space_t *spacep;         /* for pathname buffer */
3554     long maxReturnData;         /* max # of return data */
3555     long maxReturnParms;                /* max # of return parms */
3556     long bytesInBuffer;         /* # data bytes in the output buffer */
3557     int starPattern;
3558     char *maskp;                        /* mask part of path */
3559     int infoLevel;
3560     int searchFlags;
3561     int eos;
3562     smb_tran2Packet_t *outp;    /* response packet */
3563     char *tidPathp;
3564     int align;
3565     char shortName[13];         /* 8.3 name if needed */
3566     int NeedShortName;
3567     int foundInexact;
3568     char *shortNameEnd;
3569     int fileType;
3570     cm_fid_t fid;
3571     cm_req_t req;
3572
3573     cm_InitReq(&req);
3574
3575     eos = 0;
3576     if (p->opcode == 1) {
3577         /* find first; obtain basic parameters from request */
3578         attribute = p->parmsp[0];
3579         maxCount = p->parmsp[1];
3580         infoLevel = p->parmsp[3];
3581         searchFlags = p->parmsp[2];
3582         dsp = smb_NewDirSearch(1);
3583         dsp->attribute = attribute;
3584         pathp = ((char *) p->parmsp) + 12;      /* points to path */
3585         if (smb_StoreAnsiFilenames)
3586             OemToChar(pathp,pathp);
3587         nextCookie = 0;
3588         maskp = strrchr(pathp, '\\');
3589         if (maskp == NULL) 
3590             maskp = pathp;
3591         else 
3592             maskp++;    /* skip over backslash */
3593         strcpy(dsp->mask, maskp);       /* and save mask */
3594         /* track if this is likely to match a lot of entries */
3595         starPattern = smb_V3IsStarMask(maskp);
3596     }
3597     else {
3598         osi_assert(p->opcode == 2);
3599         /* find next; obtain basic parameters from request or open dir file */
3600         dsp = smb_FindDirSearch(p->parmsp[0]);
3601         if (!dsp) 
3602             return CM_ERROR_BADFD;
3603         attribute = dsp->attribute;
3604         maxCount = p->parmsp[1];
3605         infoLevel = p->parmsp[2];
3606         searchFlags = p->parmsp[5];
3607         pathp = NULL;
3608         nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3609         maskp = dsp->mask;