registry-docs-logoff-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         DWORD nShares;
1413         DWORD nRegShares;
1414         DWORD nSharesRet;
1415         HKEY hkParam;
1416         HKEY hkSubmount = NULL;
1417         smb_rap_share_info_1_t * shares;
1418         int 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         outParmsTotal = 8; /* 4 dwords */
1483         outDataTotal = (sizeof(smb_rap_share_info_1_t) + 1) * nShares ;
1484         if(outDataTotal > bufsize) {
1485                 nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + 1);
1486                 outDataTotal = (sizeof(smb_rap_share_info_1_t) + 1) * nSharesRet;
1487         }
1488         else {
1489                 nSharesRet = nShares;
1490         }
1491     
1492         outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1493
1494         /* now for the submounts */
1495     shares = (smb_rap_share_info_1_t *) outp->datap;
1496         cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1497
1498         memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + 1) * nSharesRet);
1499
1500         if(allSubmount) {
1501                 strcpy( shares[cshare].shi1_netname, "all" );
1502                 shares[cshare].shi1_remark = cstrp - outp->datap;
1503                 /* type and pad are zero already */
1504                 cshare++;
1505                 cstrp++;
1506         }
1507
1508         if(hkSubmount) {
1509                 for(i=0; i < nRegShares && cshare < nSharesRet; i++) {
1510                         len = sizeof(thisShare);
1511             rv = RegEnumValue(hkSubmount, i, thisShare, &len, NULL, NULL, NULL, NULL);
1512                         if(rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1513                                 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1514                                 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1515                                 shares[cshare].shi1_remark = cstrp - outp->datap;
1516                                 cshare++;
1517                                 cstrp++;
1518                         }
1519                         else
1520                                 nShares--; /* uncount key */
1521                 }
1522
1523                 RegCloseKey(hkSubmount);
1524         }
1525
1526         nonrootShares = cshare;
1527
1528         for(i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1529         /* in case there are collisions with submounts, submounts have higher priority */               
1530                 for(j=0; j < nonrootShares; j++)
1531                         if(!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1532                                 break;
1533                 
1534                 if(j < nonrootShares) {
1535                         nShares--; /* uncount */
1536                         continue;
1537                 }
1538
1539                 strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1540                 shares[cshare].shi1_remark = cstrp - outp->datap;
1541                 cshare++;
1542                 cstrp++;
1543         }
1544
1545         outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1546         outp->parmsp[1] = 0;
1547         outp->parmsp[2] = cshare;
1548         outp->parmsp[3] = nShares;
1549
1550         outp->totalData = (sizeof(smb_rap_share_info_1_t) + 1) * cshare;
1551         outp->totalParms = outParmsTotal;
1552
1553         smb_SendTran2Packet(vcp, outp, op);
1554         smb_FreeTran2Packet(outp);
1555
1556         free(rootShares.shares);
1557
1558         return code;
1559 }
1560
1561 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1562 {
1563         smb_tran2Packet_t *outp;
1564         unsigned short * tp;
1565         char * shareName;
1566         BOOL shareFound = FALSE;
1567         unsigned short infoLevel;
1568         unsigned short bufsize;
1569         int totalData;
1570         int totalParam;
1571         DWORD len;
1572         HKEY hkParam;
1573         HKEY hkSubmount;
1574         DWORD allSubmount;
1575         LONG rv;
1576         long code = 0;
1577
1578         tp = p->parmsp + 1; /* skip over function number (always 1) */
1579         (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1580         (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1581         shareName = smb_ParseString( (char *) tp, (char **) &tp);
1582     infoLevel = *tp++;
1583     bufsize = *tp++;
1584     
1585         totalParam = 6;
1586
1587         if(infoLevel == 0)
1588                 totalData = sizeof(smb_rap_share_info_0_t);
1589         else if(infoLevel == 1)
1590                 totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1591         else if(infoLevel == 2)
1592                 totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1593         else
1594                 return CM_ERROR_INVAL;
1595
1596         outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1597
1598         if(!stricmp(shareName,"all")) {
1599                 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName, 0,
1600                         KEY_QUERY_VALUE, &hkParam);
1601                 if (rv == ERROR_SUCCESS) {
1602                         len = sizeof(allSubmount);
1603                         rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1604                                                                         (BYTE *) &allSubmount, &len);
1605                         if (rv != ERROR_SUCCESS || allSubmount != 0) {
1606                                 allSubmount = 1;
1607                         }
1608                         RegCloseKey (hkParam);
1609                 }
1610
1611                 if(allSubmount)
1612                         shareFound = TRUE;
1613
1614         } else {
1615                 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\OpenAFS\\Client\\Submounts", 0,
1616                         KEY_QUERY_VALUE, &hkSubmount);
1617                 if(rv == ERROR_SUCCESS) {
1618             rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1619                         if(rv == ERROR_SUCCESS) {
1620                                 shareFound = TRUE;
1621                         }
1622                         RegCloseKey(hkSubmount);
1623                 }
1624         }
1625
1626         if(!shareFound) {
1627                 smb_FreeTran2Packet(outp);
1628                 return CM_ERROR_BADSHARENAME;
1629         }
1630
1631         memset(outp->datap, 0, totalData);
1632
1633         outp->parmsp[0] = 0;
1634         outp->parmsp[1] = 0;
1635         outp->parmsp[2] = totalData;
1636
1637         if(infoLevel == 0) {
1638                 smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1639                 strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1640                 info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1641         } else if(infoLevel == 1) {
1642                 smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1643         strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1644                 info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1645                 info->shi1_remark = ((unsigned char *) (info + 1)) - outp->datap;
1646                 /* type and pad are already zero */
1647         } else { /* infoLevel==2 */
1648                 smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1649                 strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1650                 info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1651                 info->shi2_remark = ((unsigned char *) (info + 1)) - outp->datap;
1652         info->shi2_permissions = ACCESS_ALL;
1653                 info->shi2_max_uses = (unsigned short) -1;
1654         info->shi2_path = 1 + (((unsigned char *) (info + 1)) - outp->datap);
1655         }
1656
1657         outp->totalData = totalData;
1658         outp->totalParms = totalParam;
1659
1660         smb_SendTran2Packet(vcp, outp, op);
1661         smb_FreeTran2Packet(outp);
1662
1663         return code;
1664 }
1665
1666 typedef struct smb_rap_wksta_info_10 {
1667         DWORD   wki10_computername;     /*char *wki10_computername;*/
1668         DWORD   wki10_username; /* char *wki10_username; */
1669         DWORD   wki10_langroup; /* char *wki10_langroup;*/
1670         unsigned char   wki10_ver_major;
1671         unsigned char   wki10_ver_minor;
1672         DWORD   wki10_logon_domain;     /*char *wki10_logon_domain;*/
1673         DWORD   wki10_oth_domains; /* char *wki10_oth_domains;*/
1674 } smb_rap_wksta_info_10_t;
1675
1676
1677 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1678 {
1679         smb_tran2Packet_t *outp;
1680     long code = 0;
1681         int infoLevel;
1682         int bufsize;
1683         unsigned short * tp;
1684         int totalData;
1685         int totalParams;
1686         smb_rap_wksta_info_10_t * info;
1687         char * cstrp;
1688         smb_user_t *uidp;
1689
1690         tp = p->parmsp + 1; /* Skip over function number */
1691         (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1692         (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1693         infoLevel = *tp++;
1694         bufsize = *tp++;
1695
1696         if(infoLevel != 10) {
1697                 return CM_ERROR_INVAL;
1698         }
1699
1700         totalParams = 6;
1701         
1702         /* infolevel 10 */
1703         totalData = sizeof(*info) +             /* info */
1704                 MAX_COMPUTERNAME_LENGTH +       /* wki10_computername */
1705                 SMB_MAX_USERNAME_LENGTH +       /* wki10_username */
1706                 MAX_COMPUTERNAME_LENGTH +       /* wki10_langroup */
1707                 MAX_COMPUTERNAME_LENGTH +       /* wki10_logon_domain */
1708                 1;                                                      /* wki10_oth_domains (null)*/
1709
1710         outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1711
1712         memset(outp->parmsp,0,totalParams);
1713         memset(outp->datap,0,totalData);
1714
1715     info = (smb_rap_wksta_info_10_t *) outp->datap;
1716         cstrp = (char *) (info + 1);
1717
1718         info->wki10_computername = (DWORD) (cstrp - outp->datap);
1719         strcpy(cstrp, smb_localNamep);
1720         cstrp += strlen(cstrp) + 1;
1721
1722         info->wki10_username = (DWORD) (cstrp - outp->datap);
1723         uidp = smb_FindUID(vcp, p->uid, 0);
1724         if(uidp) {
1725                 lock_ObtainMutex(&uidp->mx);
1726                 if(uidp->unp && uidp->unp->name)
1727                         strcpy(cstrp, uidp->unp->name);
1728                 lock_ReleaseMutex(&uidp->mx);
1729                 smb_ReleaseUID(uidp);
1730         }
1731         cstrp += strlen(cstrp) + 1;
1732
1733         info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1734         strcpy(cstrp, "WORKGROUP");
1735         cstrp += strlen(cstrp) + 1;
1736
1737         /* TODO: Not sure what values these should take, but these work */
1738         info->wki10_ver_major = 5;
1739         info->wki10_ver_minor = 1;
1740
1741         info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1742         strcpy(cstrp, smb_ServerDomainName);
1743         cstrp += strlen(cstrp) + 1;
1744
1745         info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1746         cstrp ++; /* no other domains */
1747
1748         outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1749         outp->parmsp[2] = outp->totalData;
1750         outp->totalParms = totalParams;
1751
1752         smb_SendTran2Packet(vcp,outp,op);
1753         smb_FreeTran2Packet(outp);
1754
1755         return code;
1756 }
1757
1758 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1759 {
1760         return CM_ERROR_BADOP;
1761 }
1762
1763 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1764 {
1765     smb_tran2Packet_t *asp;
1766     int totalParms;
1767     int totalData;
1768     int parmDisp;
1769     int dataDisp;
1770     int parmOffset;
1771     int dataOffset;
1772     int parmCount;
1773     int dataCount;
1774     int firstPacket;
1775     long code = 0;
1776
1777         /* We sometimes see 0 word count.  What to do? */
1778         if (*inp->wctp == 0) {
1779 #ifndef DJGPP
1780                 HANDLE h;
1781                 char *ptbuf[1];
1782
1783                 osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
1784
1785                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1786                 ptbuf[0] = "Transaction2 word count = 0";
1787                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1003, NULL,
1788                             1, inp->ncb_length, ptbuf, inp);
1789                 DeregisterEventSource(h);
1790 #else /* DJGPP */
1791                 osi_Log0(smb_logp, "TRANSACTION2 word count = 0"); 
1792 #endif /* !DJGPP */
1793
1794         smb_SetSMBDataLength(outp, 0);
1795         smb_SendPacket(vcp, outp);
1796                 return 0;
1797         }
1798
1799     totalParms = smb_GetSMBParm(inp, 0);
1800     totalData = smb_GetSMBParm(inp, 1);
1801         
1802     firstPacket = (inp->inCom == 0x32);
1803         
1804         /* find the packet we're reassembling */
1805         lock_ObtainWrite(&smb_globalLock);
1806     asp = smb_FindTran2Packet(vcp, inp);
1807     if (!asp) {
1808         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1809         }
1810     lock_ReleaseWrite(&smb_globalLock);
1811         
1812     /* now merge in this latest packet; start by looking up offsets */
1813         if (firstPacket) {
1814                 parmDisp = dataDisp = 0;
1815         parmOffset = smb_GetSMBParm(inp, 10);
1816         dataOffset = smb_GetSMBParm(inp, 12);
1817         parmCount = smb_GetSMBParm(inp, 9);
1818         dataCount = smb_GetSMBParm(inp, 11);
1819                 asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1820         asp->maxReturnData = smb_GetSMBParm(inp, 3);
1821
1822                 osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1823                  totalData, dataCount, asp->maxReturnData);
1824     }
1825     else {
1826         parmDisp = smb_GetSMBParm(inp, 4);
1827         parmOffset = smb_GetSMBParm(inp, 3);
1828         dataDisp = smb_GetSMBParm(inp, 7);
1829         dataOffset = smb_GetSMBParm(inp, 6);
1830         parmCount = smb_GetSMBParm(inp, 2);
1831         dataCount = smb_GetSMBParm(inp, 5);
1832
1833         osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1834                  parmCount, dataCount);
1835     }   
1836
1837     /* now copy the parms and data */
1838     if ( parmCount != 0 )
1839     {
1840         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1841     }
1842     if ( dataCount != 0 ) {
1843         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1844     }
1845
1846     /* account for new bytes */
1847     asp->curData += dataCount;
1848     asp->curParms += parmCount;
1849
1850     /* finally, if we're done, remove the packet from the queue and dispatch it */
1851     if (asp->totalData <= asp->curData && asp->totalParms <= asp->curParms) {
1852                 /* we've received it all */
1853         lock_ObtainWrite(&smb_globalLock);
1854                 osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1855         lock_ReleaseWrite(&smb_globalLock);
1856
1857         /* now dispatch it */
1858         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
1859             osi_LogEvent("AFS-Dispatch-2[%s]",myCrt_2Dispatch(asp->opcode),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
1860             osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%x] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
1861             code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
1862         }
1863         else {
1864             osi_LogEvent("AFS-Dispatch-2 [invalid]", NULL, "op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1865             osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%x] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
1866             code = CM_ERROR_BADOP;
1867         }
1868
1869                 /* if an error is returned, we're supposed to send an error packet,
1870          * otherwise the dispatched function already did the data sending.
1871          * We give dispatched proc the responsibility since it knows how much
1872          * space to allocate.
1873          */
1874         if (code != 0) {
1875             smb_SendTran2Error(vcp, asp, outp, code);
1876         }
1877
1878                 /* free the input tran 2 packet */
1879                 lock_ObtainWrite(&smb_globalLock);
1880         smb_FreeTran2Packet(asp);
1881                 lock_ReleaseWrite(&smb_globalLock);
1882     }
1883     else if (firstPacket) {
1884                 /* the first packet in a multi-packet request, we need to send an
1885          * ack to get more data.
1886          */
1887         smb_SetSMBDataLength(outp, 0);
1888         smb_SendPacket(vcp, outp);
1889     }
1890
1891         return 0;
1892 }
1893
1894 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1895 {
1896         char *pathp;
1897     smb_tran2Packet_t *outp;
1898     long code = 0;
1899         cm_space_t *spacep;
1900     int excl;
1901     cm_user_t *userp;
1902     cm_scache_t *dscp;          /* dir we're dealing with */
1903     cm_scache_t *scp;           /* file we're creating */
1904     cm_attr_t setAttr;
1905     int initialModeBits;
1906     smb_fid_t *fidp;
1907     int attributes;
1908     char *lastNamep;
1909     long dosTime;
1910     int openFun;
1911     int trunc;
1912     int openMode;
1913     int extraInfo;
1914     int openAction;
1915     int parmSlot;                       /* which parm we're dealing with */
1916     long returnEALength;
1917         char *tidPathp;
1918         cm_req_t req;
1919
1920         cm_InitReq(&req);
1921
1922     scp = NULL;
1923         
1924         extraInfo = (p->parmsp[0] & 1); /* return extra info */
1925     returnEALength = (p->parmsp[0] & 8);        /* return extended attr length */
1926
1927         openFun = p->parmsp[6];         /* open function */
1928     excl = ((openFun & 3) == 0);
1929     trunc = ((openFun & 3) == 2);       /* truncate it */
1930         openMode = (p->parmsp[1] & 0x7);
1931     openAction = 0;                     /* tracks what we did */
1932
1933     attributes = p->parmsp[3];
1934     dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
1935         
1936         /* compute initial mode bits based on read-only flag in attributes */
1937     initialModeBits = 0666;
1938     if (attributes & 1) initialModeBits &= ~0222;
1939         
1940     pathp = (char *) (&p->parmsp[14]);
1941         
1942     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
1943
1944         spacep = cm_GetSpace();
1945     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
1946
1947         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
1948                 /* special case magic file name for receiving IOCTL requests
1949          * (since IOCTL calls themselves aren't getting through).
1950          */
1951         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
1952         smb_SetupIoctlFid(fidp, spacep);
1953
1954         /* copy out remainder of the parms */
1955                 parmSlot = 0;
1956                 outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
1957                 if (extraInfo) {
1958             outp->parmsp[parmSlot] = /* attrs */ 0; parmSlot++;
1959             outp->parmsp[parmSlot] = 0; parmSlot++;     /* mod time */
1960             outp->parmsp[parmSlot] = 0; parmSlot++;
1961             outp->parmsp[parmSlot] = 0; parmSlot++;     /* len */
1962             outp->parmsp[parmSlot] = 0x7fff; parmSlot++;
1963             outp->parmsp[parmSlot] = openMode; parmSlot++;
1964             outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
1965             outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
1966                 }   
1967                 /* and the final "always present" stuff */
1968         outp->parmsp[parmSlot] = /* openAction found existing file */ 1; parmSlot++;
1969                 /* next write out the "unique" ID */
1970                 outp->parmsp[parmSlot] = 0x1234; parmSlot++;
1971                 outp->parmsp[parmSlot] = 0x5678; parmSlot++;
1972         outp->parmsp[parmSlot] = 0; parmSlot++;
1973                 if (returnEALength) {
1974                         outp->parmsp[parmSlot] = 0; parmSlot++;
1975                         outp->parmsp[parmSlot] = 0; parmSlot++;
1976         }
1977                 
1978         outp->totalData = 0;
1979         outp->totalParms = parmSlot * 2;
1980                 
1981         smb_SendTran2Packet(vcp, outp, op);
1982                 
1983         smb_FreeTran2Packet(outp);
1984
1985                 /* and clean up fid reference */
1986         smb_ReleaseFID(fidp);
1987         return 0;
1988     }
1989
1990 #ifdef DEBUG_VERBOSE
1991         {
1992                 char *hexp, *asciip;
1993                 asciip = (lastNamep ? lastNamep : pathp);
1994                 hexp = osi_HexifyString( asciip );
1995                 DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
1996                 free(hexp);
1997         }
1998 #endif
1999
2000         userp = smb_GetTran2User(vcp, p);
2001     /* In the off chance that userp is NULL, we log and abandon */
2002     if (!userp) {
2003         osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2004         smb_FreeTran2Packet(outp);
2005         return CM_ERROR_BADSMB;
2006     }
2007
2008         tidPathp = smb_GetTIDPath(vcp, p->tid);
2009
2010         dscp = NULL;
2011         code = cm_NameI(cm_rootSCachep, pathp,
2012                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2013                     userp, tidPathp, &req, &scp);
2014         if (code != 0) {
2015                 code = cm_NameI(cm_rootSCachep, spacep->data,
2016                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2017                         userp, tidPathp, &req, &dscp);
2018                 cm_FreeSpace(spacep);
2019
2020         if (code) {
2021             cm_ReleaseUser(userp);
2022                         smb_FreeTran2Packet(outp);
2023             return code;
2024         }
2025         
2026         /* otherwise, scp points to the parent directory.  Do a lookup,
2027                  * and truncate the file if we find it, otherwise we create the
2028                  * file.
2029          */
2030         if (!lastNamep) lastNamep = pathp;
2031         else lastNamep++;
2032         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2033                          &req, &scp);
2034         if (code && code != CM_ERROR_NOSUCHFILE) {
2035                         cm_ReleaseSCache(dscp);
2036             cm_ReleaseUser(userp);
2037                         smb_FreeTran2Packet(outp);
2038             return code;
2039         }
2040         }
2041     else {
2042         cm_FreeSpace(spacep);
2043         }
2044         
2045     /* if we get here, if code is 0, the file exists and is represented by
2046      * scp.  Otherwise, we have to create it.
2047      */
2048         if (code == 0) {
2049         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2050         if (code) {
2051             if (dscp) cm_ReleaseSCache(dscp);
2052             cm_ReleaseSCache(scp);
2053             cm_ReleaseUser(userp);
2054                         smb_FreeTran2Packet(outp);
2055             return code;
2056         }
2057
2058                 if (excl) {
2059                         /* oops, file shouldn't be there */
2060             if (dscp) cm_ReleaseSCache(dscp);
2061             cm_ReleaseSCache(scp);
2062             cm_ReleaseUser(userp);
2063                         smb_FreeTran2Packet(outp);
2064             return CM_ERROR_EXISTS;
2065         }
2066
2067                 if (trunc) {
2068                         setAttr.mask = CM_ATTRMASK_LENGTH;
2069             setAttr.length.LowPart = 0;
2070             setAttr.length.HighPart = 0;
2071                         code = cm_SetAttr(scp, &setAttr, userp, &req);
2072             openAction = 3;     /* truncated existing file */
2073                 }   
2074         else openAction = 1;    /* found existing file */
2075     }
2076         else if (!(openFun & SMB_ATTR_DIRECTORY)) {
2077                 /* don't create if not found */
2078         if (dscp) cm_ReleaseSCache(dscp);
2079         osi_assert(scp == NULL);
2080         cm_ReleaseUser(userp);
2081                 smb_FreeTran2Packet(outp);
2082         return CM_ERROR_NOSUCHFILE;
2083     }
2084     else {
2085                 osi_assert(dscp != NULL && scp == NULL);
2086                 openAction = 2; /* created file */
2087                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2088                 smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2089         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2090                          &req);
2091                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
2092                         smb_NotifyChange(FILE_ACTION_ADDED,
2093                              FILE_NOTIFY_CHANGE_FILE_NAME,  
2094                              dscp, lastNamep, NULL, TRUE);
2095         if (!excl && code == CM_ERROR_EXISTS) {
2096                         /* not an exclusive create, and someone else tried
2097                          * creating it already, then we open it anyway.  We
2098                          * don't bother retrying after this, since if this next
2099                          * fails, that means that the file was deleted after we
2100                          * started this call.
2101              */
2102             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2103                              userp, &req, &scp);
2104             if (code == 0) {
2105                 if (trunc) {
2106                                         setAttr.mask = CM_ATTRMASK_LENGTH;
2107                     setAttr.length.LowPart = 0;
2108                     setAttr.length.HighPart = 0;
2109                     code = cm_SetAttr(scp, &setAttr, userp,
2110                                       &req);
2111                 }   
2112                         }       /* lookup succeeded */
2113         }
2114     }
2115         
2116         /* we don't need this any longer */
2117         if (dscp) cm_ReleaseSCache(dscp);
2118
2119     if (code) {
2120                 /* something went wrong creating or truncating the file */
2121         if (scp) cm_ReleaseSCache(scp);
2122         cm_ReleaseUser(userp);
2123                 smb_FreeTran2Packet(outp);
2124         return code;
2125     }
2126         
2127         /* make sure we're about to open a file */
2128         if (scp->fileType != CM_SCACHETYPE_FILE) {
2129                 cm_ReleaseSCache(scp);
2130                 cm_ReleaseUser(userp);
2131                 smb_FreeTran2Packet(outp);
2132                 return CM_ERROR_ISDIR;
2133         }
2134
2135     /* now all we have to do is open the file itself */
2136     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2137     osi_assert(fidp);
2138         
2139         /* save a pointer to the vnode */
2140     fidp->scp = scp;
2141         
2142         /* compute open mode */
2143     if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2144     if (openMode == 1 || openMode == 2)
2145         fidp->flags |= SMB_FID_OPENWRITE;
2146
2147         smb_ReleaseFID(fidp);
2148         
2149         cm_Open(scp, 0, userp);
2150
2151     /* copy out remainder of the parms */
2152         parmSlot = 0;
2153         outp->parmsp[parmSlot] = fidp->fid; parmSlot++;
2154         lock_ObtainMutex(&scp->mx);
2155         if (extraInfo) {
2156         outp->parmsp[parmSlot] = smb_Attributes(scp); parmSlot++;
2157                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2158         outp->parmsp[parmSlot] = (unsigned short)(dosTime & 0xffff); parmSlot++;
2159         outp->parmsp[parmSlot] = (unsigned short)((dosTime>>16) & 0xffff); parmSlot++;
2160         outp->parmsp[parmSlot] = (unsigned short) (scp->length.LowPart & 0xffff);
2161         parmSlot++;
2162         outp->parmsp[parmSlot] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2163         parmSlot++;
2164         outp->parmsp[parmSlot] = openMode; parmSlot++;
2165         outp->parmsp[parmSlot] = 0; parmSlot++; /* file type 0 ==> normal file or dir */
2166         outp->parmsp[parmSlot] = 0; parmSlot++; /* IPC junk */
2167         }   
2168         /* and the final "always present" stuff */
2169     outp->parmsp[parmSlot] = openAction; parmSlot++;
2170         /* next write out the "unique" ID */
2171         outp->parmsp[parmSlot] = (unsigned short) (scp->fid.vnode & 0xffff); parmSlot++;
2172         outp->parmsp[parmSlot] = (unsigned short) (scp->fid.volume & 0xffff); parmSlot++;
2173     outp->parmsp[parmSlot] = 0; parmSlot++;
2174     if (returnEALength) {
2175                 outp->parmsp[parmSlot] = 0; parmSlot++;
2176                 outp->parmsp[parmSlot] = 0; parmSlot++;
2177     }
2178         lock_ReleaseMutex(&scp->mx);
2179         outp->totalData = 0;            /* total # of data bytes */
2180     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
2181
2182         smb_SendTran2Packet(vcp, outp, op);
2183         
2184     smb_FreeTran2Packet(outp);
2185
2186     cm_ReleaseUser(userp);
2187     /* leave scp held since we put it in fidp->scp */
2188     return 0;
2189 }   
2190
2191 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2192 {
2193     return CM_ERROR_BADOP;
2194 }
2195
2196 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2197 {
2198     return CM_ERROR_BADOP;
2199 }
2200
2201 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2202 {
2203         smb_tran2Packet_t *outp;
2204     smb_tran2QFSInfo_t qi;
2205         int responseSize;
2206         osi_hyper_t temp;
2207         static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2208         
2209         osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2210
2211         switch (p->parmsp[0]) {
2212         case 1: responseSize = sizeof(qi.u.allocInfo); break;
2213         case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2214         case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2215         case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2216         case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2217         case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2218         default: return CM_ERROR_INVAL;
2219         }
2220
2221     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2222         switch (p->parmsp[0]) {
2223         case 1:
2224                 /* alloc info */
2225         qi.u.allocInfo.FSID = 0;
2226         qi.u.allocInfo.sectorsPerAllocUnit = 1;
2227         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2228         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2229         qi.u.allocInfo.bytesPerSector = 1024;
2230                 break;
2231
2232     case 2:
2233                 /* volume info */
2234         qi.u.volumeInfo.vsn = 1234;
2235         qi.u.volumeInfo.vnCount = 4;
2236                 /* we're supposed to pad it out with zeroes to the end */
2237                 memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2238         memcpy(qi.u.volumeInfo.label, "AFS", 4);
2239                 break;
2240
2241         case 0x102:
2242                 /* FS volume info */
2243                 memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2244                 qi.u.FSvolumeInfo.vsn = 1234;
2245                 qi.u.FSvolumeInfo.vnCount = 8;
2246                 memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2247                 break;
2248
2249         case 0x103:
2250                 /* FS size info */
2251                 temp.HighPart = 0;
2252                 temp.LowPart = 0x7fffffff;
2253                 qi.u.FSsizeInfo.totalAllocUnits = temp;
2254                 temp.LowPart = 0x3fffffff;
2255                 qi.u.FSsizeInfo.availAllocUnits = temp;
2256                 qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2257                 qi.u.FSsizeInfo.bytesPerSector = 1024;
2258                 break;
2259
2260         case 0x104:
2261                 /* FS device info */
2262                 qi.u.FSdeviceInfo.devType = 0;  /* don't have a number */
2263                 qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2264                 break;
2265
2266         case 0x105:
2267                 /* FS attribute info */
2268                 /* attributes, defined in WINNT.H:
2269                  *      FILE_CASE_SENSITIVE_SEARCH      0x1
2270                  *      FILE_CASE_PRESERVED_NAMES       0x2
2271                  *      <no name defined>               0x4000
2272                  *         If bit 0x4000 is not set, Windows 95 thinks
2273                  *         we can't handle long (non-8.3) names,
2274                  *         despite our protestations to the contrary.
2275                  */
2276                 qi.u.FSattributeInfo.attributes = 0x4003;
2277                 qi.u.FSattributeInfo.maxCompLength = 255;
2278                 qi.u.FSattributeInfo.FSnameLength = 6;
2279                 memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2280                 break;
2281     }
2282         
2283         /* copy out return data, and set corresponding sizes */
2284         outp->totalParms = 0;
2285     outp->totalData = responseSize;
2286     memcpy(outp->datap, &qi, responseSize);
2287
2288         /* send and free the packets */
2289         smb_SendTran2Packet(vcp, outp, op);
2290     smb_FreeTran2Packet(outp);
2291
2292     return 0;
2293 }
2294
2295 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2296 {
2297     return CM_ERROR_BADOP;
2298 }
2299
2300 struct smb_ShortNameRock {
2301         char *maskp;
2302         unsigned int vnode;
2303         char *shortName;
2304         size_t shortNameLen;
2305 };
2306
2307 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2308         osi_hyper_t *offp)
2309 {
2310         struct smb_ShortNameRock *rockp;
2311         char *shortNameEnd;
2312
2313         rockp = vrockp;
2314         /* compare both names and vnodes, though probably just comparing vnodes
2315          * would be safe enough.
2316          */
2317         if (cm_stricmp(dep->name, rockp->maskp) != 0)
2318                 return 0;
2319         if (ntohl(dep->fid.vnode) != rockp->vnode)
2320                 return 0;
2321         /* This is the entry */
2322         cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2323         rockp->shortNameLen = shortNameEnd - rockp->shortName;
2324         return CM_ERROR_STOPNOW;
2325 }
2326
2327 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2328         char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2329 {
2330         struct smb_ShortNameRock rock;
2331         char *lastNamep;
2332         cm_space_t *spacep;
2333         cm_scache_t *dscp;
2334         int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2335         long code = 0;
2336         osi_hyper_t thyper;
2337
2338         spacep = cm_GetSpace();
2339         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2340
2341         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
2342                      reqp, &dscp);
2343         cm_FreeSpace(spacep);
2344         if (code) return code;
2345
2346         if (!lastNamep) lastNamep = pathp;
2347         else lastNamep++;
2348         thyper.LowPart = 0;
2349         thyper.HighPart = 0;
2350         rock.shortName = shortName;
2351         rock.vnode = vnode;
2352         rock.maskp = lastNamep;
2353         code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp,
2354                         reqp, NULL);
2355
2356         cm_ReleaseSCache(dscp);
2357
2358         if (code == 0)
2359                 return CM_ERROR_NOSUCHFILE;
2360         if (code == CM_ERROR_STOPNOW) {
2361                 *shortNameLenp = rock.shortNameLen;
2362                 return 0;
2363         }
2364         return code;
2365 }
2366
2367 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2368 {
2369         smb_tran2Packet_t *outp;
2370     unsigned long dosTime;
2371         FILETIME ft;
2372     unsigned short infoLevel;
2373     int nbytesRequired;
2374     unsigned short attributes;
2375         unsigned long extAttributes;
2376         char shortName[13];
2377         unsigned int len;
2378     cm_user_t *userp;
2379         cm_space_t *spacep;
2380     cm_scache_t *scp, *dscp;
2381     long code = 0;
2382     char *op;
2383         char *tidPathp;
2384         char *lastComp;
2385         cm_req_t req;
2386
2387         cm_InitReq(&req);
2388
2389         infoLevel = p->parmsp[0];
2390     if (infoLevel == 6) nbytesRequired = 0;
2391     else if (infoLevel == 1) nbytesRequired = 22;
2392     else if (infoLevel == 2) nbytesRequired = 26;
2393         else if (infoLevel == 0x101) nbytesRequired = 40;
2394         else if (infoLevel == 0x102) nbytesRequired = 24;
2395         else if (infoLevel == 0x103) nbytesRequired = 4;
2396         else if (infoLevel == 0x108) nbytesRequired = 30;
2397     else {
2398                 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2399                   p->opcode, infoLevel);
2400                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2401         return 0;
2402     }
2403         osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2404              osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2405
2406     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2407
2408         if (infoLevel > 0x100)
2409                 outp->totalParms = 2;
2410         else
2411                 outp->totalParms = 0;
2412         outp->totalData = nbytesRequired;
2413         
2414     /* now, if we're at infoLevel 6, we're only being asked to check
2415      * the syntax, so we just OK things now.  In particular, we're *not*
2416      * being asked to verify anything about the state of any parent dirs.
2417      */
2418         if (infoLevel == 6) {
2419                 smb_SendTran2Packet(vcp, outp, opx);
2420         smb_FreeTran2Packet(outp);
2421                 return 0;
2422     }
2423         
2424     userp = smb_GetTran2User(vcp, p);
2425     if (!userp) {
2426         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2427         smb_FreeTran2Packet(outp);
2428         return CM_ERROR_BADSMB;
2429     }
2430
2431         tidPathp = smb_GetTIDPath(vcp, p->tid);
2432
2433         /*
2434          * XXX Strange hack XXX
2435          *
2436          * As of Patch 7 (13 January 98), we are having the following problem:
2437          * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2438          * requests to look up "desktop.ini" in all the subdirectories.
2439          * This can cause zillions of timeouts looking up non-existent cells
2440          * and volumes, especially in the top-level directory.
2441          *
2442          * We have not found any way to avoid this or work around it except
2443          * to explicitly ignore the requests for mount points that haven't
2444          * yet been evaluated and for directories that haven't yet been
2445          * fetched.
2446          */
2447         if (infoLevel == 0x101) {
2448                 spacep = cm_GetSpace();
2449                 smb_StripLastComponent(spacep->data, &lastComp,
2450                                         (char *)(&p->parmsp[3]));
2451                 /* Make sure that lastComp is not NULL */
2452                 if (lastComp) {
2453                     if (strcmp(lastComp, "\\desktop.ini") == 0) {
2454                 code = cm_NameI(cm_rootSCachep, spacep->data,
2455                                 CM_FLAG_CASEFOLD
2456                                 | CM_FLAG_DIRSEARCH
2457                                 | CM_FLAG_FOLLOW,
2458                                 userp, tidPathp, &req, &dscp);
2459                 if (code == 0) {
2460                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2461                          && !dscp->mountRootFidp)
2462                         code = CM_ERROR_NOSUCHFILE;
2463                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2464                         cm_buf_t *bp = buf_Find(dscp, &hzero);
2465                         if (bp)
2466                             buf_Release(bp);
2467                         else
2468                             code = CM_ERROR_NOSUCHFILE;
2469                     }
2470                     cm_ReleaseSCache(dscp);
2471                     if (code) {
2472                         cm_FreeSpace(spacep);
2473                         cm_ReleaseUser(userp);
2474                         smb_SendTran2Error(vcp, p, opx, code);
2475                         smb_FreeTran2Packet(outp);
2476                         return 0;
2477                     }
2478                 }
2479             }
2480         }
2481                 cm_FreeSpace(spacep);
2482         }
2483
2484         /* now do namei and stat, and copy out the info */
2485     code = cm_NameI(cm_rootSCachep, (char *)(&p->parmsp[3]),
2486                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2487
2488         if (code) {
2489                 cm_ReleaseUser(userp);
2490         smb_SendTran2Error(vcp, p, opx, code);
2491         smb_FreeTran2Packet(outp);
2492         return 0;
2493     }
2494
2495     lock_ObtainMutex(&scp->mx);
2496         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2497                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2498         if (code) goto done;
2499         
2500     /* now we have the status in the cache entry, and everything is locked.
2501          * Marshall the output data.
2502      */
2503         op = outp->datap;
2504         /* for info level 108, figure out short name */
2505         if (infoLevel == 0x108) {
2506                 code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2507                                 tidPathp, scp->fid.vnode, shortName,
2508                                 (size_t *) &len);
2509                 if (code) {
2510                         goto done;
2511                 }
2512
2513                 op = outp->datap;
2514                 *((u_long *)op) = len * 2; op += 4;
2515                 mbstowcs((unsigned short *)op, shortName, len);
2516                 op += (len * 2);
2517
2518                 goto done;
2519         }
2520         if (infoLevel == 1 || infoLevel == 2) {
2521                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2522         *((u_long *)op) = dosTime; op += 4;     /* creation time */
2523         *((u_long *)op) = dosTime; op += 4;     /* access time */
2524         *((u_long *)op) = dosTime; op += 4;     /* write time */
2525         *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2526         *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2527                 attributes = smb_Attributes(scp);
2528                 *((u_short *)op) = attributes; op += 2; /* attributes */
2529         }
2530         else if (infoLevel == 0x101) {
2531                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2532                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
2533                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
2534                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
2535                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
2536                 extAttributes = smb_ExtAttributes(scp);
2537                 *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2538                 *((u_long *)op) = 0; op += 4;   /* don't know what this is */
2539         }
2540         else if (infoLevel == 0x102) {
2541                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
2542                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
2543                 *((u_long *)op) = scp->linkCount; op += 4;
2544                 *op++ = 0;
2545                 *op++ = 0;
2546                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2547                 *op++ = 0;
2548         }
2549         else if (infoLevel == 0x103) {
2550                 memset(op, 0, 4); op += 4;      /* EA size */
2551         }
2552
2553         /* now, if we are being asked about extended attrs, return a 0 size */
2554         if (infoLevel == 2) {
2555                 *((u_long *)op) = 0; op += 4;
2556         }
2557         
2558
2559         /* send and free the packets */
2560   done:
2561         lock_ReleaseMutex(&scp->mx);
2562     cm_ReleaseSCache(scp);
2563     cm_ReleaseUser(userp);
2564         if (code == 0) 
2565         smb_SendTran2Packet(vcp, outp, opx);
2566     else 
2567         smb_SendTran2Error(vcp, p, opx, code);
2568     smb_FreeTran2Packet(outp);
2569
2570     return 0;
2571 }
2572
2573 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2574 {
2575     return CM_ERROR_BADOP;
2576 }
2577
2578 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2579 {
2580         smb_tran2Packet_t *outp;
2581         FILETIME ft;
2582         unsigned long attributes;
2583         unsigned short infoLevel;
2584         int nbytesRequired;
2585         unsigned short fid;
2586         cm_user_t *userp;
2587     smb_fid_t *fidp;
2588         cm_scache_t *scp;
2589         char *op;
2590         long code = 0;
2591         cm_req_t req;
2592
2593         cm_InitReq(&req);
2594
2595     fid = p->parmsp[0];
2596     fidp = smb_FindFID(vcp, fid, 0);
2597
2598         if (fidp == NULL) {
2599                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2600                 return 0;
2601         }
2602
2603         infoLevel = p->parmsp[1];
2604         if (infoLevel == 0x101) nbytesRequired = 40;
2605         else if (infoLevel == 0x102) nbytesRequired = 24;
2606         else if (infoLevel == 0x103) nbytesRequired = 4;
2607         else if (infoLevel == 0x104) nbytesRequired = 6;
2608         else {
2609                 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2610                  p->opcode, infoLevel);
2611                 smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2612         smb_ReleaseFID(fidp);
2613                 return 0;
2614         }
2615         osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2616
2617         outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2618
2619         if (infoLevel > 0x100)
2620                 outp->totalParms = 2;
2621         else
2622                 outp->totalParms = 0;
2623         outp->totalData = nbytesRequired;
2624
2625         userp = smb_GetTran2User(vcp, p);
2626     if (!userp) {
2627         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2628         code = CM_ERROR_BADSMB;
2629         goto done;
2630     }
2631
2632         scp = fidp->scp;
2633         lock_ObtainMutex(&scp->mx);
2634         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2635                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2636         if (code) goto done;
2637
2638         /* now we have the status in the cache entry, and everything is locked.
2639          * Marshall the output data.
2640          */
2641         op = outp->datap;
2642         if (infoLevel == 0x101) {
2643                 smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2644                 *((FILETIME *)op) = ft; op += 8;        /* creation time */
2645                 *((FILETIME *)op) = ft; op += 8;        /* last access time */
2646                 *((FILETIME *)op) = ft; op += 8;        /* last write time */
2647                 *((FILETIME *)op) = ft; op += 8;        /* last change time */
2648                 attributes = smb_ExtAttributes(scp);
2649                 *((u_long *)op) = attributes; op += 4;
2650                 *((u_long *)op) = 0; op += 4;
2651         }
2652         else if (infoLevel == 0x102) {
2653                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
2654                 *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
2655                 *((u_long *)op) = scp->linkCount; op += 4;
2656                 *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2657                 *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2658                 *op++ = 0;
2659                 *op++ = 0;
2660         }
2661         else if (infoLevel == 0x103) {
2662                 *((u_long *)op) = 0; op += 4;
2663         }
2664         else if (infoLevel == 0x104) {
2665                 unsigned long len;
2666                 char *name;
2667
2668                 if (fidp->NTopen_wholepathp)
2669                         name = fidp->NTopen_wholepathp;
2670                 else
2671                         name = "\\";    /* probably can't happen */
2672                 len = strlen(name);
2673                 outp->totalData = (len*2) + 4;  /* this is actually what we want to return */
2674                 *((u_long *)op) = len * 2; op += 4;
2675                 mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2676         }
2677
2678         /* send and free the packets */
2679   done:
2680         lock_ReleaseMutex(&scp->mx);
2681         cm_ReleaseUser(userp);
2682         smb_ReleaseFID(fidp);
2683         if (code == 0) smb_SendTran2Packet(vcp, outp, opx);
2684         else smb_SendTran2Error(vcp, p, opx, code);
2685         smb_FreeTran2Packet(outp);
2686
2687         return 0;
2688 }
2689
2690 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2691 {
2692         long code = 0;
2693         unsigned short fid;
2694         smb_fid_t *fidp;
2695         unsigned short infoLevel;
2696         smb_tran2Packet_t *outp;
2697         cm_user_t *userp;
2698         cm_scache_t *scp;
2699         cm_req_t req;
2700
2701         cm_InitReq(&req);
2702
2703     fid = p->parmsp[0];
2704         fidp = smb_FindFID(vcp, fid, 0);
2705
2706         if (fidp == NULL) {
2707                 smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2708                 return 0;
2709         }
2710
2711         infoLevel = p->parmsp[1];
2712         if (infoLevel > 0x104 || infoLevel < 0x101) {
2713                 osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2714                          p->opcode, infoLevel);
2715                 smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2716         smb_ReleaseFID(fidp);
2717                 return 0;
2718         }
2719
2720         if (infoLevel == 0x102 && !(fidp->flags & SMB_FID_OPENDELETE)) {
2721                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2722         smb_ReleaseFID(fidp);
2723                 return 0;
2724         }
2725         if ((infoLevel == 0x103 || infoLevel == 0x104)
2726             && !(fidp->flags & SMB_FID_OPENWRITE)) {
2727                 smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2728         smb_ReleaseFID(fidp);
2729                 return 0;
2730         }
2731
2732         osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2733
2734         outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2735
2736         outp->totalParms = 2;
2737         outp->totalData = 0;
2738
2739         userp = smb_GetTran2User(vcp, p);
2740     if (!userp) {
2741         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
2742         code = CM_ERROR_BADSMB;
2743         goto done;
2744     }
2745
2746         scp = fidp->scp;
2747
2748         if (infoLevel == 0x101) {
2749                 FILETIME lastMod;
2750                 unsigned int attribute;
2751                 cm_attr_t attr;
2752
2753                 /* lock the vnode with a callback; we need the current status
2754                  * to determine what the new status is, in some cases.
2755                  */
2756                 lock_ObtainMutex(&scp->mx);
2757                 code = cm_SyncOp(scp, NULL, userp, &req, 0,
2758                          CM_SCACHESYNC_GETSTATUS
2759                          | CM_SCACHESYNC_NEEDCALLBACK);
2760                 if (code) {
2761                         lock_ReleaseMutex(&scp->mx);
2762                         goto done;
2763                 }
2764
2765                 /* prepare for setattr call */
2766                 attr.mask = 0;
2767                 
2768                 lastMod = *((FILETIME *)(p->datap + 16));
2769                 /* when called as result of move a b, lastMod is (-1, -1). 
2770          * If the check for -1 is not present, timestamp
2771                  * of the resulting file will be 1969 (-1)
2772                  */
2773                 if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
2774             lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
2775                         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2776                         smb_UnixTimeFromLargeSearchTime(&attr.clientModTime,
2777                                                         &lastMod);
2778                         fidp->flags |= SMB_FID_MTIMESETDONE;
2779                 }
2780                 
2781                 attribute = *((u_long *)(p->datap + 32));
2782                 if (attribute != 0) {
2783                         if ((scp->unixModeBits & 0222)
2784                             && (attribute & 1) != 0) {
2785                                 /* make a writable file read-only */
2786                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2787                                 attr.unixModeBits = scp->unixModeBits & ~0222;
2788                         }
2789                         else if ((scp->unixModeBits & 0222) == 0
2790                                  && (attribute & 1) == 0) {
2791                                 /* make a read-only file writable */
2792                                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2793                                 attr.unixModeBits = scp->unixModeBits | 0222;
2794                         }
2795                 }
2796                 lock_ReleaseMutex(&scp->mx);
2797
2798                 /* call setattr */
2799                 if (attr.mask)
2800                         code = cm_SetAttr(scp, &attr, userp, &req);
2801                 else
2802                         code = 0;
2803         }
2804         else if (infoLevel == 0x103 || infoLevel == 0x104) {
2805                 LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
2806                 cm_attr_t attr;
2807
2808                 attr.mask = CM_ATTRMASK_LENGTH;
2809                 attr.length.LowPart = size.LowPart;
2810                 attr.length.HighPart = size.HighPart;
2811                 code = cm_SetAttr(scp, &attr, userp, &req);
2812         }
2813         else if (infoLevel == 0x102) {
2814                 if (*((char *)(p->datap))) {
2815                         code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
2816                                                 &req);
2817                         if (code == 0)
2818                                 fidp->flags |= SMB_FID_DELONCLOSE;
2819                 }
2820                 else {
2821                         code = 0;
2822                         fidp->flags &= ~SMB_FID_DELONCLOSE;
2823                 }
2824         }
2825   done:
2826         cm_ReleaseUser(userp);
2827         smb_ReleaseFID(fidp);
2828         if (code == 0) smb_SendTran2Packet(vcp, outp, op);
2829         else smb_SendTran2Error(vcp, p, op, code);
2830         smb_FreeTran2Packet(outp);
2831
2832         return 0;
2833 }
2834
2835 long smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2836 {
2837     return CM_ERROR_BADOP;
2838 }
2839
2840 long smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2841 {
2842     return CM_ERROR_BADOP;
2843 }
2844
2845 long smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2846 {
2847     return CM_ERROR_BADOP;
2848 }
2849
2850 long smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2851 {
2852     return CM_ERROR_BADOP;
2853 }
2854
2855 long smb_ReceiveTran2MKDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2856 {
2857     return CM_ERROR_BADOP;
2858 }
2859
2860 long smb_ApplyV3DirListPatches(cm_scache_t *dscp,
2861         smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
2862         cm_req_t *reqp)
2863 {
2864         long code = 0;
2865     cm_scache_t *scp;
2866     cm_scache_t *targetScp;                     /* target if scp is a symlink */
2867     char *dptr;
2868     long dosTime;
2869         FILETIME ft;
2870     int shortTemp;
2871     unsigned short attr;
2872         unsigned long lattr;
2873     smb_dirListPatch_t *patchp;
2874     smb_dirListPatch_t *npatchp;
2875         
2876     for(patchp = *dirPatchespp; patchp; patchp =
2877          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2878                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2879         if (code) continue;
2880         lock_ObtainMutex(&scp->mx);
2881         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2882                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2883                 if (code) { 
2884                         lock_ReleaseMutex(&scp->mx);
2885                         cm_ReleaseSCache(scp);
2886                         continue;
2887         }
2888                 
2889         /* now watch for a symlink */
2890         if (scp->fileType == CM_SCACHETYPE_SYMLINK) {
2891                         lock_ReleaseMutex(&scp->mx);
2892             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
2893             if (code == 0) {
2894                                 /* we have a more accurate file to use (the
2895                                  * target of the symbolic link).  Otherwise,
2896                                  * we'll just use the symlink anyway.
2897                  */
2898                                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2899                          scp, targetScp);
2900                                 cm_ReleaseSCache(scp);
2901                 scp = targetScp;
2902             }
2903             lock_ObtainMutex(&scp->mx);
2904         }
2905
2906                 dptr = patchp->dptr;
2907
2908                 if (infoLevel >= 0x101) {
2909                         /* get filetime */
2910                         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2911
2912                         /* copy to Creation Time */
2913                         *((FILETIME *)dptr) = ft;
2914                         dptr += 8;
2915
2916                         /* copy to Last Access Time */
2917                         *((FILETIME *)dptr) = ft;
2918                         dptr += 8;
2919
2920                         /* copy to Last Write Time */
2921                         *((FILETIME *)dptr) = ft;
2922                         dptr += 8;
2923
2924                         /* copy to Change Time */
2925                         *((FILETIME *)dptr) = ft;
2926                         dptr += 8;
2927
2928                         /* Use length for both file length and alloc length */
2929                         *((LARGE_INTEGER *)dptr) = scp->length;
2930                         dptr += 8;
2931                         *((LARGE_INTEGER *)dptr) = scp->length;
2932                         dptr += 8;
2933
2934                         /* Copy attributes */
2935                         lattr = smb_ExtAttributes(scp);
2936             /* merge in hidden (dot file) attribute */
2937                         if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2938                                 lattr |= SMB_ATTR_HIDDEN;
2939                         *((u_long *)dptr) = lattr;
2940                         dptr += 4;
2941                 }
2942                 else {
2943                         /* get dos time */
2944                         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2945
2946                         /* and copy out date */
2947                         shortTemp = (dosTime>>16) & 0xffff;
2948                         *((u_short *)dptr) = shortTemp;
2949                         dptr += 2;
2950
2951                         /* copy out creation time */
2952                         shortTemp = dosTime & 0xffff;
2953                         *((u_short *)dptr) = shortTemp;
2954                         dptr += 2;
2955
2956                         /* and copy out date */
2957                         shortTemp = (dosTime>>16) & 0xffff;
2958                         *((u_short *)dptr) = shortTemp;
2959                         dptr += 2;
2960                         
2961                         /* copy out access time */
2962                         shortTemp = dosTime & 0xffff;
2963                         *((u_short *)dptr) = shortTemp;
2964                         dptr += 2;
2965
2966                         /* and copy out date */
2967                         shortTemp = (dosTime>>16) & 0xffff;
2968                         *((u_short *)dptr) = shortTemp;
2969                         dptr += 2;
2970                         
2971                         /* copy out mod time */
2972                         shortTemp = dosTime & 0xffff;
2973                         *((u_short *)dptr) = shortTemp;
2974                         dptr += 2;
2975
2976                         /* copy out file length and alloc length,
2977                          * using the same for both
2978                          */
2979                         *((u_long *)dptr) = scp->length.LowPart;
2980                         dptr += 4;
2981                         *((u_long *)dptr) = scp->length.LowPart;
2982                         dptr += 4;
2983
2984                         /* finally copy out attributes as short */
2985                         attr = smb_Attributes(scp);
2986             /* merge in hidden (dot file) attribute */
2987             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2988                 attr |= SMB_ATTR_HIDDEN;
2989                         *dptr++ = attr & 0xff;
2990                         *dptr++ = (attr >> 8) & 0xff;
2991                 }
2992
2993         lock_ReleaseMutex(&scp->mx);
2994         cm_ReleaseSCache(scp);
2995         }
2996         
2997     /* now free the patches */
2998     for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
2999                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3000         free(patchp);
3001         }
3002         
3003     /* and mark the list as empty */
3004     *dirPatchespp = NULL;
3005
3006     return code;
3007 }
3008
3009 #ifndef USE_OLD_MATCHING
3010 // char table for case insensitive comparison
3011 char mapCaseTable[256];
3012
3013 VOID initUpperCaseTable(VOID) 
3014 {
3015     int i;
3016     for (i = 0; i < 256; ++i) 
3017        mapCaseTable[i] = toupper(i);
3018     // make '"' match '.' 
3019     mapCaseTable[(int)'"'] = toupper('.');
3020     // make '<' match '*' 
3021     mapCaseTable[(int)'<'] = toupper('*');
3022     // make '>' match '?' 
3023     mapCaseTable[(int)'>'] = toupper('?');    
3024 }
3025
3026 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3027 // name 'name'.
3028 // Note : this procedure works recursively calling itself.
3029 // Parameters
3030 // PSZ pattern    : string containing metacharacters.
3031 // PSZ name       : file name to be compared with 'pattern'.
3032 // Return value
3033 // BOOL : TRUE/FALSE (match/mistmatch)
3034
3035 BOOL szWildCardMatchFileName(PSZ pattern, PSZ name) {
3036    PSZ pename;         // points to the last 'name' character
3037    PSZ p;
3038    pename = name + strlen(name) - 1;
3039    while (*name) {
3040       switch (*pattern) {
3041          case '?':
3042          case '>':
3043             if (*(++pattern) != '<' || *(++pattern) != '*') {
3044                if (*name == '.') 
3045                    return FALSE;
3046                ++name;
3047                break;
3048             } /* endif */
3049          case '<':
3050          case '*':
3051             while ((*pattern == '<') || (*pattern == '*') || (*pattern == '?') || (*pattern == '>')) 
3052                 ++pattern;
3053             if (!*pattern) 
3054                 return TRUE;
3055             for (p = pename; p >= name; --p) {
3056                if ((mapCaseTable[*p] == mapCaseTable[*pattern]) &&
3057                    szWildCardMatchFileName(pattern + 1, p + 1))
3058                   return TRUE;
3059             } /* endfor */
3060             return FALSE;
3061          default:
3062             if (mapCaseTable[*name] != mapCaseTable[*pattern]) 
3063                 return FALSE;
3064             ++pattern, ++name;
3065             break;
3066       } /* endswitch */
3067    } /* endwhile */ 
3068    return !*pattern;
3069 }
3070
3071 /* do a case-folding search of the star name mask with the name in namep.
3072  * Return 1 if we match, otherwise 0.
3073  */
3074 int smb_V3MatchMask(char *namep, char *maskp, int flags) 
3075 {
3076         /* make sure we only match 8.3 names, if requested */
3077         if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
3078         return 0;
3079         
3080         return szWildCardMatchFileName(maskp, namep) ? 1:0;
3081 }
3082
3083 #else /* USE_OLD_MATCHING */
3084 /* do a case-folding search of the star name mask with the name in namep.
3085  * Return 1 if we match, otherwise 0.
3086  */
3087 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3088 {
3089         unsigned char tcp1, tcp2;       /* Pattern characters */
3090     unsigned char tcn1;         /* Name characters */
3091         int sawDot = 0, sawStar = 0, req8dot3 = 0;
3092         char *starNamep, *starMaskp;
3093         static char nullCharp[] = {0};
3094     int casefold = flags & CM_FLAG_CASEFOLD;
3095
3096         /* make sure we only match 8.3 names, if requested */
3097     req8dot3 = (flags & CM_FLAG_8DOT3);
3098         if (req8dot3 && !cm_Is8Dot3(namep)) 
3099         return 0;
3100
3101         /* loop */
3102         while (1) {
3103                 /* Next pattern character */
3104                 tcp1 = *maskp++;
3105
3106                 /* Next name character */
3107                 tcn1 = *namep;
3108
3109                 if (tcp1 == 0) {
3110                         /* 0 - end of pattern */
3111                         if (tcn1 == 0)
3112                                 return 1;
3113                         else
3114                                 return 0;
3115                 }
3116                 else if (tcp1 == '.' || tcp1 == '"') {
3117                         if (sawDot) {
3118                                 if (tcn1 == '.') {
3119                                         namep++;
3120                                         continue;
3121                                 } else
3122                                         return 0;
3123                         }
3124                         else {
3125                                 /*
3126                                  * first dot in pattern;
3127                                  * must match dot or end of name
3128                                  */
3129                                 sawDot = 1;
3130                                 if (tcn1 == 0)
3131                                         continue;
3132                                 else if (tcn1 == '.') {
3133                                         sawStar = 0;
3134                                         namep++;
3135                                         continue;
3136                                 }
3137                                 else
3138                                         return 0;
3139                         }
3140                 }
3141                 else if (tcp1 == '?') {
3142                         if (tcn1 == 0 || tcn1 == '.')
3143                                 return 0;
3144                         namep++;
3145                         continue;
3146                 }
3147                 else if (tcp1 == '>') {
3148                         if (tcn1 != 0 && tcn1 != '.')
3149                                 namep++;
3150                         continue;
3151                 }
3152                 else if (tcp1 == '*' || tcp1 == '<') {
3153                         tcp2 = *maskp++;
3154                         if (tcp2 == 0)
3155                                 return 1;
3156                         else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3157                                 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3158                                         tcn1 = *++namep;
3159                                 if (tcn1 == 0) {
3160                                         if (sawDot)
3161                                                 return 0;
3162                                         else
3163                                                 continue;
3164                                 }
3165                                 else {
3166                                         namep++;
3167                                         continue;
3168                                 }
3169                         }
3170                         else {
3171                                 /*
3172                                  * pattern character after '*' is not null or
3173                                  * period.  If it is '?' or '>', we are not
3174                                  * going to understand it.  If it is '*' or
3175                                  * '<', we are going to skip over it.  None of
3176                                  * these are likely, I hope.
3177                                  */
3178                                 /* skip over '*' and '<' */
3179                                 while (tcp2 == '*' || tcp2 == '<')
3180                                         tcp2 = *maskp++;
3181
3182                                 /* skip over characters that don't match tcp2 */
3183                                 while (req8dot3 && tcn1 != '.' && tcn1 != 0 && 
3184                        ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
3185                          (!casefold && tcn1 != tcp2)))
3186                                         tcn1 = *++namep;
3187
3188                                 /* No match */
3189                                 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3190                                         return 0;
3191
3192                                 /* Remember where we are */
3193                                 sawStar = 1;
3194                                 starMaskp = maskp;
3195                                 starNamep = namep;
3196
3197                                 namep++;
3198                                 continue;
3199                         }
3200                 }
3201                 else {
3202                         /* tcp1 is not a wildcard */
3203             if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
3204                 (!casefold && tcn1 == tcp1)) {
3205                                 /* they match */
3206                                 namep++;
3207                                 continue;
3208                         }
3209                         /* if trying to match a star pattern, go back */
3210                         if (sawStar) {
3211                                 maskp = starMaskp - 2;
3212                                 namep = starNamep + 1;
3213                                 sawStar = 0;
3214                                 continue;
3215                         }
3216                         /* that's all */
3217                         return 0;
3218                 }
3219         }
3220 }
3221 #endif /* USE_OLD_MATCHING */
3222
3223 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3224 {
3225         int attribute;
3226     long nextCookie;
3227     char *tp;
3228     long code = 0;
3229     char *pathp;
3230     cm_dirEntry_t *dep;
3231     int maxCount;
3232     smb_dirListPatch_t *dirListPatchesp;
3233     smb_dirListPatch_t *curPatchp;
3234     cm_buf_t *bufferp;
3235     long temp;
3236     long orbytes;                       /* # of bytes in this output record */
3237     long ohbytes;                       /* # of bytes, except file name */
3238     long onbytes;                       /* # of bytes in name, incl. term. null */
3239     osi_hyper_t dirLength;
3240     osi_hyper_t bufferOffset;
3241     osi_hyper_t curOffset;
3242     osi_hyper_t thyper;
3243     smb_dirSearch_t *dsp;
3244     cm_scache_t *scp;
3245     long entryInDir;
3246     long entryInBuffer;
3247         cm_pageHeader_t *pageHeaderp;
3248     cm_user_t *userp = NULL;
3249     int slotInPage;
3250     int returnedNames;
3251     long nextEntryCookie;
3252     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
3253     char *op;                   /* output data ptr */
3254         char *origOp;                   /* original value of op */
3255     cm_space_t *spacep;         /* for pathname buffer */
3256     long maxReturnData;         /* max # of return data */
3257     long maxReturnParms;                /* max # of return parms */
3258     long bytesInBuffer;         /* # data bytes in the output buffer */
3259     int starPattern;
3260     char *maskp;                        /* mask part of path */
3261     int infoLevel;
3262     int searchFlags;
3263     int eos;
3264     smb_tran2Packet_t *outp;    /* response packet */
3265         char *tidPathp;
3266         int align;
3267         char shortName[13];             /* 8.3 name if needed */
3268         int NeedShortName;
3269     int foundInexact;
3270         char *shortNameEnd;
3271     int fileType;
3272     cm_fid_t fid;
3273
3274     cm_req_t req;
3275
3276         cm_InitReq(&req);
3277
3278         eos = 0;
3279         if (p->opcode == 1) {
3280                 /* find first; obtain basic parameters from request */
3281         attribute = p->parmsp[0];
3282         maxCount = p->parmsp[1];
3283         infoLevel = p->parmsp[3];
3284         searchFlags = p->parmsp[2];
3285         dsp = smb_NewDirSearch(1);
3286         dsp->attribute = attribute;
3287         pathp = ((char *) p->parmsp) + 12;      /* points to path */
3288         nextCookie = 0;
3289         maskp = strrchr(pathp, '\\');
3290         if (maskp == NULL) maskp = pathp;
3291                 else maskp++;   /* skip over backslash */
3292         strcpy(dsp->mask, maskp);       /* and save mask */
3293                 /* track if this is likely to match a lot of entries */
3294         starPattern = smb_V3IsStarMask(maskp);
3295         }
3296     else {
3297                 osi_assert(p->opcode == 2);
3298         /* find next; obtain basic parameters from request or open dir file */
3299         dsp = smb_FindDirSearch(p->parmsp[0]);
3300         if (!dsp) return CM_ERROR_BADFD;
3301         attribute = dsp->attribute;
3302         maxCount = p->parmsp[1];
3303         infoLevel = p->parmsp[2];
3304         searchFlags = p->parmsp[5];
3305         pathp = NULL;
3306         nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3307         maskp = dsp->mask;
3308                 starPattern = 1;        /* assume, since required a Find Next */
3309     }
3310
3311         osi_Log4(smb_logp,
3312               "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3313               attribute, infoLevel, maxCount, searchFlags);
3314
3315         osi_Log2(smb_logp, "...T2 search op %d, nextCookie 0x%x",
3316               p->opcode, nextCookie);
3317
3318         if (infoLevel >= 0x101)
3319                 searchFlags &= ~4;      /* no resume keys */
3320
3321     dirListPatchesp = NULL;
3322
3323         maxReturnData = p->maxReturnData;
3324     if (p->opcode == 1) /* find first */
3325         maxReturnParms = 10;    /* bytes */
3326         else    
3327         maxReturnParms = 8;     /* bytes */
3328
3329 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3330     if (maxReturnData > 6000) 
3331         maxReturnData = 6000;
3332 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3333
3334         outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3335                                       maxReturnData);
3336
3337     osi_Log1(smb_logp, "T2 receive search dir %s",
3338              osi_LogSaveString(smb_logp, pathp));
3339         
3340     /* bail out if request looks bad */
3341     if (p->opcode == 1 && !pathp) {
3342         smb_ReleaseDirSearch(dsp);
3343         smb_FreeTran2Packet(outp);
3344         return CM_ERROR_BADSMB;
3345     }
3346         
3347         osi_Log2(smb_logp, "T2 dir search cookie 0x%x, connection %d",
3348              nextCookie, dsp->cookie);
3349
3350         userp = smb_GetTran2User(vcp, p);
3351     if (!userp) {
3352         osi_Log1(smb_logp, "T2 dir search unable to resolve user [%d]", p->uid);
3353         smb_ReleaseDirSearch(dsp);
3354         smb_FreeTran2Packet(outp);
3355         return CM_ERROR_BADSMB;
3356     }
3357
3358         /* try to get the vnode for the path name next */
3359         lock_ObtainMutex(&dsp->mx);
3360         if (dsp->scp) {
3361                 scp = dsp->scp;
3362         cm_HoldSCache(scp);
3363         code = 0;
3364     }
3365     else {
3366                 spacep = cm_GetSpace();
3367         smb_StripLastComponent(spacep->data, NULL, pathp);
3368         lock_ReleaseMutex(&dsp->mx);
3369
3370                 tidPathp = smb_GetTIDPath(vcp, p->tid);
3371         code = cm_NameI(cm_rootSCachep, spacep->data,
3372                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3373                         userp, tidPathp, &req, &scp);
3374         cm_FreeSpace(spacep);
3375
3376         lock_ObtainMutex(&dsp->mx);
3377                 if (code == 0) {
3378             if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3379                         dsp->scp = scp;
3380                         /* we need one hold for the entry we just stored into,
3381              * and one for our own processing.  When we're done
3382                          * with this function, we'll drop the one for our own
3383                          * processing.  We held it once from the namei call,
3384                          * and so we do another hold now.
3385              */
3386             cm_HoldSCache(scp);
3387                         lock_ObtainMutex(&scp->mx);
3388                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3389                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3390                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3391                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
3392                         }
3393                         lock_ReleaseMutex(&scp->mx);
3394         }
3395     }
3396         lock_ReleaseMutex(&dsp->mx);
3397     if (code) {
3398                 cm_ReleaseUser(userp);
3399         smb_FreeTran2Packet(outp);
3400                 smb_DeleteDirSearch(dsp);
3401                 smb_ReleaseDirSearch(dsp);
3402         return code;
3403         }
3404
3405     /* get the directory size */
3406         lock_ObtainMutex(&scp->mx);
3407     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3408                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3409         if (code) {
3410                 lock_ReleaseMutex(&scp->mx);
3411         cm_ReleaseSCache(scp);
3412         cm_ReleaseUser(userp);