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