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