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