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