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