windows-byte-range-locking-20060108
[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 = uidp->userID;
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     /* and the user */
2341     cm_HoldUser(userp);
2342     fidp->userp = userp;
2343         
2344     /* compute open mode */
2345     if (openMode != 1) fidp->flags |= SMB_FID_OPENREAD;
2346     if (openMode == 1 || openMode == 2)
2347         fidp->flags |= SMB_FID_OPENWRITE;
2348
2349     smb_ReleaseFID(fidp);
2350         
2351     cm_Open(scp, 0, userp);
2352
2353     /* copy out remainder of the parms */
2354     parmSlot = 0;
2355     outp->parmsp[parmSlot++] = fidp->fid;
2356     lock_ObtainMutex(&scp->mx);
2357     if (extraInfo) {
2358         outp->parmsp[parmSlot++] = smb_Attributes(scp);
2359         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2360         outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2361         outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2362         outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2363         outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2364         outp->parmsp[parmSlot++] = openMode;
2365         outp->parmsp[parmSlot++] = 0;   /* file type 0 ==> normal file or dir */
2366         outp->parmsp[parmSlot++] = 0;   /* IPC junk */
2367     }   
2368     /* and the final "always present" stuff */
2369     outp->parmsp[parmSlot++] = openAction;
2370     /* next write out the "unique" ID */
2371     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff); 
2372     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff); 
2373     outp->parmsp[parmSlot++] = 0; 
2374     if (returnEALength) {
2375         outp->parmsp[parmSlot++] = 0; 
2376         outp->parmsp[parmSlot++] = 0; 
2377     }   
2378     lock_ReleaseMutex(&scp->mx);
2379     outp->totalData = 0;                /* total # of data bytes */
2380     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
2381
2382     smb_SendTran2Packet(vcp, outp, op);
2383
2384     smb_FreeTran2Packet(outp);
2385
2386     cm_ReleaseUser(userp);
2387     /* leave scp held since we put it in fidp->scp */
2388     return 0;
2389 }   
2390
2391 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2392 {
2393     osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2394     return CM_ERROR_BADOP;
2395 }
2396
2397 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2398 {
2399     osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2400     return CM_ERROR_BADOP;
2401 }
2402
2403 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2404 {
2405     smb_tran2Packet_t *outp;
2406     smb_tran2QFSInfo_t qi;
2407     int responseSize;
2408     osi_hyper_t temp;
2409     static char FSname[6] = {'A', 0, 'F', 0, 'S', 0};
2410         
2411     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2412
2413     switch (p->parmsp[0]) {
2414     case 1: responseSize = sizeof(qi.u.allocInfo); break;
2415     case 2: responseSize = sizeof(qi.u.volumeInfo); break;
2416     case 0x102: responseSize = sizeof(qi.u.FSvolumeInfo); break;
2417     case 0x103: responseSize = sizeof(qi.u.FSsizeInfo); break;
2418     case 0x104: responseSize = sizeof(qi.u.FSdeviceInfo); break;
2419     case 0x105: responseSize = sizeof(qi.u.FSattributeInfo); break;
2420     case 0x200: /* CIFS Unix Info */
2421     case 0x301: /* Mac FS Info */
2422     default: return CM_ERROR_INVAL;
2423     }
2424
2425     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2426     switch (p->parmsp[0]) {
2427     case 1:
2428         /* alloc info */
2429         qi.u.allocInfo.FSID = 0;
2430         qi.u.allocInfo.sectorsPerAllocUnit = 1;
2431         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2432         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2433         qi.u.allocInfo.bytesPerSector = 1024;
2434         break;
2435
2436     case 2:
2437         /* volume info */
2438         qi.u.volumeInfo.vsn = 1234;
2439         qi.u.volumeInfo.vnCount = 4;
2440         /* we're supposed to pad it out with zeroes to the end */
2441         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2442         memcpy(qi.u.volumeInfo.label, "AFS", 4);
2443         break;
2444
2445     case 0x102:
2446         /* FS volume info */
2447         memset((char *)&qi.u.FSvolumeInfo.vct, 0, sizeof(FILETIME));
2448         qi.u.FSvolumeInfo.vsn = 1234;
2449         qi.u.FSvolumeInfo.vnCount = 8;
2450         memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0", 8);
2451         break;
2452
2453     case 0x103:
2454         /* FS size info */
2455         temp.HighPart = 0;
2456         temp.LowPart = 0x7fffffff;
2457         qi.u.FSsizeInfo.totalAllocUnits = temp;
2458         temp.LowPart = 0x3fffffff;
2459         qi.u.FSsizeInfo.availAllocUnits = temp;
2460         qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2461         qi.u.FSsizeInfo.bytesPerSector = 1024;
2462         break;
2463
2464     case 0x104:
2465         /* FS device info */
2466         qi.u.FSdeviceInfo.devType = 0;  /* don't have a number */
2467         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2468         break;
2469
2470         case 0x105:
2471         /* FS attribute info */
2472         /* attributes, defined in WINNT.H:
2473          *      FILE_CASE_SENSITIVE_SEARCH      0x1
2474          *      FILE_CASE_PRESERVED_NAMES       0x2
2475          *      <no name defined>               0x4000
2476          *         If bit 0x4000 is not set, Windows 95 thinks
2477          *         we can't handle long (non-8.3) names,
2478          *         despite our protestations to the contrary.
2479          */
2480         qi.u.FSattributeInfo.attributes = 0x4003;
2481         qi.u.FSattributeInfo.maxCompLength = 255;
2482         qi.u.FSattributeInfo.FSnameLength = 6;
2483         memcpy(qi.u.FSattributeInfo.FSname, FSname, 6);
2484         break;
2485     }   
2486         
2487     /* copy out return data, and set corresponding sizes */
2488     outp->totalParms = 0;
2489     outp->totalData = responseSize;
2490     memcpy(outp->datap, &qi, responseSize);
2491
2492     /* send and free the packets */
2493     smb_SendTran2Packet(vcp, outp, op);
2494     smb_FreeTran2Packet(outp);
2495
2496     return 0;
2497 }
2498
2499 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2500 {
2501     osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2502     return CM_ERROR_BADOP;
2503 }
2504
2505 struct smb_ShortNameRock {
2506     char *maskp;
2507     unsigned int vnode;
2508     char *shortName;
2509     size_t shortNameLen;
2510 };      
2511
2512 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2513                          osi_hyper_t *offp)
2514 {       
2515     struct smb_ShortNameRock *rockp;
2516     char *shortNameEnd;
2517
2518     rockp = vrockp;
2519     /* compare both names and vnodes, though probably just comparing vnodes
2520      * would be safe enough.
2521      */
2522     if (cm_stricmp(dep->name, rockp->maskp) != 0)
2523         return 0;
2524     if (ntohl(dep->fid.vnode) != rockp->vnode)
2525         return 0;
2526     /* This is the entry */
2527     cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2528     rockp->shortNameLen = shortNameEnd - rockp->shortName;
2529     return CM_ERROR_STOPNOW;
2530 }       
2531
2532 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2533         char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2534 {
2535     struct smb_ShortNameRock rock;
2536     char *lastNamep;
2537     cm_space_t *spacep;
2538     cm_scache_t *dscp;
2539     int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2540     long code = 0;
2541     osi_hyper_t thyper;
2542
2543     spacep = cm_GetSpace();
2544     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2545
2546     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2547                      reqp, &dscp);
2548     cm_FreeSpace(spacep);
2549     if (code) 
2550         return code;
2551
2552 #ifdef DFS_SUPPORT
2553     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2554         cm_ReleaseSCache(dscp);
2555         cm_ReleaseUser(userp);
2556         return CM_ERROR_PATH_NOT_COVERED;
2557     }
2558 #endif /* DFS_SUPPORT */
2559
2560     if (!lastNamep) lastNamep = pathp;
2561     else lastNamep++;
2562     thyper.LowPart = 0;
2563     thyper.HighPart = 0;
2564     rock.shortName = shortName;
2565     rock.vnode = vnode;
2566     rock.maskp = lastNamep;
2567     code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2568
2569     cm_ReleaseSCache(dscp);
2570
2571     if (code == 0)
2572         return CM_ERROR_NOSUCHFILE;
2573     if (code == CM_ERROR_STOPNOW) {
2574         *shortNameLenp = rock.shortNameLen;
2575         return 0;
2576     }
2577     return code;
2578 }
2579
2580 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2581 {
2582     smb_tran2Packet_t *outp;
2583     afs_uint32 dosTime;
2584     FILETIME ft;
2585     unsigned short infoLevel;
2586     int nbytesRequired;
2587     unsigned short attributes;
2588     unsigned long extAttributes;
2589     char shortName[13];
2590     unsigned int len;
2591     cm_user_t *userp;
2592     cm_space_t *spacep;
2593     cm_scache_t *scp, *dscp;
2594     long code = 0;
2595     char *op;
2596     char *tidPathp;
2597     char *lastComp;
2598     cm_req_t req;
2599
2600     cm_InitReq(&req);
2601
2602     infoLevel = p->parmsp[0];
2603     if (infoLevel == SMB_INFO_IS_NAME_VALID) 
2604         nbytesRequired = 0;
2605     else if (infoLevel == SMB_INFO_STANDARD) 
2606         nbytesRequired = 22;
2607     else if (infoLevel == SMB_INFO_QUERY_EA_SIZE) 
2608         nbytesRequired = 26;
2609     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) 
2610         nbytesRequired = 40;
2611     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) 
2612         nbytesRequired = 24;
2613     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) 
2614         nbytesRequired = 4;
2615     else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) 
2616         nbytesRequired = 30;
2617     else {
2618         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2619                   p->opcode, infoLevel);
2620         smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2621         return 0;
2622     }
2623     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2624               osi_LogSaveString(smb_logp, (char *)(&p->parmsp[3])));
2625
2626     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2627
2628     if (infoLevel > 0x100)
2629         outp->totalParms = 2;
2630     else
2631         outp->totalParms = 0;
2632     outp->totalData = nbytesRequired;
2633         
2634     /* now, if we're at infoLevel 6, we're only being asked to check
2635      * the syntax, so we just OK things now.  In particular, we're *not*
2636      * being asked to verify anything about the state of any parent dirs.
2637      */
2638     if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2639         smb_SendTran2Packet(vcp, outp, opx);
2640         smb_FreeTran2Packet(outp);
2641         return 0;
2642     }   
2643         
2644     userp = smb_GetTran2User(vcp, p);
2645     if (!userp) {
2646         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2647         smb_FreeTran2Packet(outp);
2648         return CM_ERROR_BADSMB;
2649     }
2650
2651     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2652     if(code) {
2653         cm_ReleaseUser(userp);
2654         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2655         smb_FreeTran2Packet(outp);
2656         return 0;
2657     }
2658
2659     /*
2660      * XXX Strange hack XXX
2661      *
2662      * As of Patch 7 (13 January 98), we are having the following problem:
2663      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2664      * requests to look up "desktop.ini" in all the subdirectories.
2665      * This can cause zillions of timeouts looking up non-existent cells
2666      * and volumes, especially in the top-level directory.
2667      *
2668      * We have not found any way to avoid this or work around it except
2669      * to explicitly ignore the requests for mount points that haven't
2670      * yet been evaluated and for directories that haven't yet been
2671      * fetched.
2672      */
2673     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2674         spacep = cm_GetSpace();
2675         smb_StripLastComponent(spacep->data, &lastComp,
2676                                 (char *)(&p->parmsp[3]));
2677 #ifndef SPECIAL_FOLDERS
2678         /* Make sure that lastComp is not NULL */
2679         if (lastComp) {
2680             if (stricmp(lastComp, "\\desktop.ini") == 0) {
2681                 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2682                                  CM_FLAG_CASEFOLD
2683                                  | CM_FLAG_DIRSEARCH
2684                                  | CM_FLAG_FOLLOW,
2685                                  userp, tidPathp, &req, &dscp);
2686                 if (code == 0) {
2687 #ifdef DFS_SUPPORT
2688                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2689                         if ( WANTS_DFS_PATHNAMES(p) )
2690                             code = CM_ERROR_PATH_NOT_COVERED;
2691                         else
2692                             code = CM_ERROR_BADSHARENAME;
2693                     } else
2694 #endif /* DFS_SUPPORT */
2695                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2696                         code = CM_ERROR_NOSUCHFILE;
2697                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2698                         cm_buf_t *bp = buf_Find(dscp, &hzero);
2699                         if (bp)
2700                             buf_Release(bp);
2701                         else
2702                             code = CM_ERROR_NOSUCHFILE;
2703                     }
2704                     cm_ReleaseSCache(dscp);
2705                     if (code) {
2706                         cm_FreeSpace(spacep);
2707                         cm_ReleaseUser(userp);
2708                         smb_SendTran2Error(vcp, p, opx, code);
2709                         smb_FreeTran2Packet(outp);
2710                         return 0;
2711                     }
2712                 }
2713             }
2714         }
2715 #endif /* SPECIAL_FOLDERS */
2716
2717         cm_FreeSpace(spacep);
2718     }
2719
2720     /* now do namei and stat, and copy out the info */
2721     code = cm_NameI(cm_data.rootSCachep, (char *)(&p->parmsp[3]),
2722                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2723
2724     if (code) {
2725         cm_ReleaseUser(userp);
2726         smb_SendTran2Error(vcp, p, opx, code);
2727         smb_FreeTran2Packet(outp);
2728         return 0;
2729     }
2730
2731 #ifdef DFS_SUPPORT
2732     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2733         cm_ReleaseSCache(scp);
2734         cm_ReleaseUser(userp);
2735         if ( WANTS_DFS_PATHNAMES(p) )
2736             code = CM_ERROR_PATH_NOT_COVERED;
2737         else
2738             code = CM_ERROR_BADSHARENAME;
2739         smb_SendTran2Error(vcp, p, opx, code);
2740         smb_FreeTran2Packet(outp);
2741         return 0;
2742     }
2743 #endif /* DFS_SUPPORT */
2744
2745     lock_ObtainMutex(&scp->mx);
2746     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2747                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2748     if (code) goto done;
2749         
2750     /* now we have the status in the cache entry, and everything is locked.
2751      * Marshall the output data.
2752      */
2753     op = outp->datap;
2754     /* for info level 108, figure out short name */
2755     if (infoLevel == 0x108) {
2756         code = cm_GetShortName((char *)(&p->parmsp[3]), userp, &req,
2757                                 tidPathp, scp->fid.vnode, shortName,
2758                                 (size_t *) &len);
2759         if (code) {
2760             goto done;
2761         }
2762
2763         op = outp->datap;
2764         *((u_long *)op) = len * 2; op += 4;
2765         mbstowcs((unsigned short *)op, shortName, len);
2766         op += (len * 2);
2767
2768         goto done;
2769     }
2770     if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2771         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2772         *((u_long *)op) = dosTime; op += 4;     /* creation time */
2773         *((u_long *)op) = dosTime; op += 4;     /* access time */
2774         *((u_long *)op) = dosTime; op += 4;     /* write time */
2775         *((u_long *)op) = scp->length.LowPart; op += 4; /* length */
2776         *((u_long *)op) = scp->length.LowPart; op += 4; /* alloc size */
2777         attributes = smb_Attributes(scp);
2778         *((u_short *)op) = attributes; op += 2; /* attributes */
2779     }
2780     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2781         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2782         *((FILETIME *)op) = ft; op += 8;        /* creation time */
2783         *((FILETIME *)op) = ft; op += 8;        /* last access time */
2784         *((FILETIME *)op) = ft; op += 8;        /* last write time */
2785         *((FILETIME *)op) = ft; op += 8;        /* last change time */
2786         extAttributes = smb_ExtAttributes(scp);
2787         *((u_long *)op) = extAttributes; op += 4; /* extended attribs */
2788         *((u_long *)op) = 0; op += 4;   /* don't know what this is */
2789     }
2790     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2791         *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
2792         *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
2793         *((u_long *)op) = scp->linkCount; op += 4;
2794         *op++ = 0;
2795         *op++ = 0;
2796         *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2797         *op++ = 0;
2798     }
2799     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2800         memset(op, 0, 4); op += 4;      /* EA size */
2801     }
2802
2803     /* now, if we are being asked about extended attrs, return a 0 size */
2804     if (infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2805         *((u_long *)op) = 0; op += 4;
2806     }
2807
2808
2809     /* send and free the packets */
2810   done:
2811     lock_ReleaseMutex(&scp->mx);
2812     cm_ReleaseSCache(scp);
2813     cm_ReleaseUser(userp);
2814     if (code == 0) 
2815         smb_SendTran2Packet(vcp, outp, opx);
2816     else 
2817         smb_SendTran2Error(vcp, p, opx, code);
2818     smb_FreeTran2Packet(outp);
2819
2820     return 0;
2821 }
2822
2823 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2824 {
2825     osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2826     return CM_ERROR_BADOP;
2827 }
2828
2829 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2830 {
2831     smb_tran2Packet_t *outp;
2832     FILETIME ft;
2833     unsigned long attributes;
2834     unsigned short infoLevel;
2835     int nbytesRequired;
2836     unsigned short fid;
2837     cm_user_t *userp;
2838     smb_fid_t *fidp;
2839     cm_scache_t *scp;
2840     char *op;
2841     long code = 0;
2842     cm_req_t req;
2843
2844     cm_InitReq(&req);
2845
2846     fid = p->parmsp[0];
2847     fidp = smb_FindFID(vcp, fid, 0);
2848
2849     if (fidp == NULL) {
2850         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
2851         return 0;
2852     }
2853
2854     infoLevel = p->parmsp[1];
2855     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) 
2856         nbytesRequired = 40;
2857     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) 
2858         nbytesRequired = 24;
2859     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2860         nbytesRequired = 4;
2861     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
2862         nbytesRequired = 6;
2863     else {
2864         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2865                   p->opcode, infoLevel);
2866         smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2867         smb_ReleaseFID(fidp);
2868         return 0;
2869     }
2870     osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
2871
2872     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, nbytesRequired);
2873
2874     if (infoLevel > 0x100)
2875         outp->totalParms = 2;
2876     else
2877         outp->totalParms = 0;
2878     outp->totalData = nbytesRequired;
2879
2880     userp = smb_GetTran2User(vcp, p);
2881     if (!userp) {
2882         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
2883         code = CM_ERROR_BADSMB;
2884         goto done;
2885     }   
2886
2887     scp = fidp->scp;
2888     lock_ObtainMutex(&scp->mx);
2889     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2890                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2891     if (code) 
2892         goto done;
2893
2894     /* now we have the status in the cache entry, and everything is locked.
2895      * Marshall the output data.
2896      */
2897     op = outp->datap;
2898     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2899         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2900         *((FILETIME *)op) = ft; op += 8;        /* creation time */
2901         *((FILETIME *)op) = ft; op += 8;        /* last access time */
2902         *((FILETIME *)op) = ft; op += 8;        /* last write time */
2903         *((FILETIME *)op) = ft; op += 8;        /* last change time */
2904         attributes = smb_ExtAttributes(scp);
2905         *((u_long *)op) = attributes; op += 4;
2906         *((u_long *)op) = 0; op += 4;
2907     }
2908     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2909         *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* alloc size */
2910         *((LARGE_INTEGER *)op) = scp->length; op += 8;  /* EOF */
2911         *((u_long *)op) = scp->linkCount; op += 4;
2912         *op++ = ((fidp->flags & SMB_FID_DELONCLOSE) ? 1 : 0);
2913         *op++ = (scp->fileType == CM_SCACHETYPE_DIRECTORY ? 1 : 0);
2914         *op++ = 0;
2915         *op++ = 0;
2916     }
2917     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2918         *((u_long *)op) = 0; op += 4;
2919     }
2920     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2921         unsigned long len;
2922         char *name;
2923
2924         if (fidp->NTopen_wholepathp)
2925             name = fidp->NTopen_wholepathp;
2926         else
2927             name = "\\";        /* probably can't happen */
2928         len = (unsigned long)strlen(name);
2929         outp->totalData = (len*2) + 4;  /* this is actually what we want to return */
2930         *((u_long *)op) = len * 2; op += 4;
2931         mbstowcs((unsigned short *)op, name, len); op += (len * 2);
2932     }
2933
2934     /* send and free the packets */
2935   done:
2936     lock_ReleaseMutex(&scp->mx);
2937     cm_ReleaseUser(userp);
2938     smb_ReleaseFID(fidp);
2939     if (code == 0) 
2940         smb_SendTran2Packet(vcp, outp, opx);
2941     else 
2942         smb_SendTran2Error(vcp, p, opx, code);
2943     smb_FreeTran2Packet(outp);
2944
2945     return 0;
2946 }       
2947
2948 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2949 {
2950     long code = 0;
2951     unsigned short fid;
2952     smb_fid_t *fidp;
2953     unsigned short infoLevel;
2954     smb_tran2Packet_t *outp;
2955     cm_user_t *userp;
2956     cm_scache_t *scp;
2957     cm_req_t req;
2958
2959     cm_InitReq(&req);
2960
2961     fid = p->parmsp[0];
2962     fidp = smb_FindFID(vcp, fid, 0);
2963
2964     if (fidp == NULL) {
2965         smb_SendTran2Error(vcp, p, op, CM_ERROR_BADFD);
2966         return 0;
2967     }
2968
2969     infoLevel = p->parmsp[1];
2970     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type=[%x] fid=[%x]", infoLevel, fid);
2971     if (infoLevel > 0x104 || infoLevel < 0x101) {
2972         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2973                   p->opcode, infoLevel);
2974         smb_SendTran2Error(vcp, p, op, CM_ERROR_INVAL);
2975         smb_ReleaseFID(fidp);
2976         return 0;
2977     }
2978
2979     if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
2980         smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2981         smb_ReleaseFID(fidp);
2982         return 0;
2983     }
2984     if ((infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO)
2985          && !(fidp->flags & SMB_FID_OPENWRITE)) {
2986         smb_SendTran2Error(vcp, p, op, CM_ERROR_NOACCESS);
2987         smb_ReleaseFID(fidp);
2988         return 0;
2989     }
2990
2991     osi_Log1(smb_logp, "T2 SFileInfo type 0x%x", infoLevel);
2992
2993     outp = smb_GetTran2ResponsePacket(vcp, p, op, 2, 0);
2994
2995     outp->totalParms = 2;
2996     outp->totalData = 0;
2997
2998     userp = smb_GetTran2User(vcp, p);
2999     if (!userp) {
3000         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3001         code = CM_ERROR_BADSMB;
3002         goto done;
3003     }   
3004
3005     scp = fidp->scp;
3006
3007     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3008         FILETIME lastMod;
3009         unsigned int attribute;
3010         cm_attr_t attr;
3011
3012         /* lock the vnode with a callback; we need the current status
3013          * to determine what the new status is, in some cases.
3014          */
3015         lock_ObtainMutex(&scp->mx);
3016         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3017                           CM_SCACHESYNC_GETSTATUS
3018                          | CM_SCACHESYNC_NEEDCALLBACK);
3019         if (code) {
3020             lock_ReleaseMutex(&scp->mx);
3021             goto done;
3022         }
3023
3024         /* prepare for setattr call */
3025         attr.mask = 0;
3026
3027         lastMod = *((FILETIME *)(p->datap + 16));
3028         /* when called as result of move a b, lastMod is (-1, -1). 
3029          * If the check for -1 is not present, timestamp
3030          * of the resulting file will be 1969 (-1)
3031          */
3032         if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
3033              lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3034             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3035             smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3036             fidp->flags |= SMB_FID_MTIMESETDONE;
3037         }
3038                 
3039         attribute = *((u_long *)(p->datap + 32));
3040         if (attribute != 0) {
3041             if ((scp->unixModeBits & 0222)
3042                  && (attribute & 1) != 0) {
3043                 /* make a writable file read-only */
3044                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3045                 attr.unixModeBits = scp->unixModeBits & ~0222;
3046             }
3047             else if ((scp->unixModeBits & 0222) == 0
3048                       && (attribute & 1) == 0) {
3049                 /* make a read-only file writable */
3050                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3051                 attr.unixModeBits = scp->unixModeBits | 0222;
3052             }
3053         }
3054         lock_ReleaseMutex(&scp->mx);
3055
3056         /* call setattr */
3057         if (attr.mask)
3058             code = cm_SetAttr(scp, &attr, userp, &req);
3059         else
3060             code = 0;
3061     }               
3062     else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3063         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3064         cm_attr_t attr;
3065
3066         attr.mask = CM_ATTRMASK_LENGTH;
3067         attr.length.LowPart = size.LowPart;
3068         attr.length.HighPart = size.HighPart;
3069         code = cm_SetAttr(scp, &attr, userp, &req);
3070     }       
3071     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3072         if (*((char *)(p->datap))) {
3073             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3074                                      &req);
3075             if (code == 0)          
3076                 fidp->flags |= SMB_FID_DELONCLOSE;
3077         }               
3078         else {  
3079             code = 0;
3080             fidp->flags &= ~SMB_FID_DELONCLOSE;
3081         }
3082     }       
3083
3084   done:
3085     cm_ReleaseUser(userp);
3086     smb_ReleaseFID(fidp);
3087     if (code == 0) 
3088         smb_SendTran2Packet(vcp, outp, op);
3089     else 
3090         smb_SendTran2Error(vcp, p, op, code);
3091     smb_FreeTran2Packet(outp);
3092
3093     return 0;
3094 }
3095
3096 long 
3097 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3098 {
3099     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3100     return CM_ERROR_BADOP;
3101 }
3102
3103 long 
3104 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3105 {
3106     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3107     return CM_ERROR_BADOP;
3108 }
3109
3110 long 
3111 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3112 {
3113     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3114     return CM_ERROR_BADOP;
3115 }
3116
3117 long 
3118 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3119 {
3120     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3121     return CM_ERROR_BADOP;
3122 }
3123
3124 long 
3125 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3126 {
3127     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3128     return CM_ERROR_BADOP;
3129 }
3130
3131 long 
3132 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3133 {
3134     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3135     return CM_ERROR_BADOP;
3136 }
3137
3138 struct smb_v2_referral {
3139     USHORT ServerType;
3140     USHORT ReferralFlags;
3141     ULONG  Proximity;
3142     ULONG  TimeToLive;
3143     USHORT DfsPathOffset;
3144     USHORT DfsAlternativePathOffset;
3145     USHORT NetworkAddressOffset;
3146 };
3147
3148 long 
3149 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3150 {
3151     /* This is a UNICODE only request (bit15 of Flags2) */
3152     /* The TID must be IPC$ */
3153
3154     /* The documentation for the Flags response field is contradictory */
3155
3156     /* Use Version 1 Referral Element Format */
3157     /* ServerType = 0; indicates the next server should be queried for the file */
3158     /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3159     /* Node = UnicodeString of UNC path of the next share name */
3160 #ifdef DFS_SUPPORT
3161     long code = 0;
3162     int maxReferralLevel = 0;
3163     char requestFileName[1024] = "";
3164     smb_tran2Packet_t *outp = 0;
3165     cm_user_t *userp = 0;
3166     cm_req_t req;
3167     CPINFO CodePageInfo;
3168     int i, nbnLen, reqLen;
3169     int idx;
3170
3171     cm_InitReq(&req);
3172
3173     maxReferralLevel = p->parmsp[0];
3174
3175     GetCPInfo(CP_ACP, &CodePageInfo);
3176     WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1, 
3177                         requestFileName, 1024, NULL, NULL);
3178
3179     osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]", 
3180              maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3181
3182     nbnLen = strlen(cm_NetbiosName);
3183     reqLen = strlen(requestFileName);
3184
3185     if (reqLen == nbnLen + 5 &&
3186         requestFileName[0] == '\\' &&
3187         !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3188         requestFileName[nbnLen+1] == '\\' &&
3189         !_strnicmp("all",&requestFileName[nbnLen+2],3)) 
3190     {
3191         USHORT * sp;
3192         struct smb_v2_referral * v2ref;
3193         outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3194
3195         sp = (USHORT *)outp->datap;
3196         idx = 0;
3197         sp[idx++] = reqLen;   /* path consumed */
3198         sp[idx++] = 1;        /* number of referrals */
3199         sp[idx++] = 0x03;     /* flags */
3200 #ifdef DFS_VERSION_1
3201         sp[idx++] = 1;        /* Version Number */
3202         sp[idx++] = reqLen + 4;  /* Referral Size */ 
3203         sp[idx++] = 1;        /* Type = SMB Server */
3204         sp[idx++] = 0;        /* Do not strip path consumed */
3205         for ( i=0;i<=reqLen; i++ )
3206             sp[i+idx] = requestFileName[i];
3207 #else /* DFS_VERSION_2 */
3208         sp[idx++] = 2;      /* Version Number */
3209         sp[idx++] = sizeof(struct smb_v2_referral);     /* Referral Size */
3210         idx += (sizeof(struct smb_v2_referral) / 2);
3211         v2ref = (struct smb_v2_referral *) &sp[5];
3212         v2ref->ServerType = 1;  /* SMB Server */
3213         v2ref->ReferralFlags = 0x03;
3214         v2ref->Proximity = 0;   /* closest */
3215         v2ref->TimeToLive = 3600; /* seconds */
3216         v2ref->DfsPathOffset = idx * 2;
3217         v2ref->DfsAlternativePathOffset = idx * 2;
3218         v2ref->NetworkAddressOffset = 0;
3219         for ( i=0;i<=reqLen; i++ )
3220             sp[i+idx] = requestFileName[i];
3221 #endif
3222     } else {
3223         userp = smb_GetTran2User(vcp, p);
3224         if (!userp) {
3225             osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3226             code = CM_ERROR_BADSMB;
3227             goto done;
3228         }   
3229
3230                 /* not done yet */
3231         code = CM_ERROR_NOSUCHPATH;
3232     }
3233
3234   done:
3235     if (userp)
3236         cm_ReleaseUser(userp);
3237     if (code == 0) 
3238         smb_SendTran2Packet(vcp, outp, op);
3239     else 
3240         smb_SendTran2Error(vcp, p, op, code);
3241     if (outp)
3242         smb_FreeTran2Packet(outp);
3243  
3244     return 0;
3245 #else /* DFS_SUPPORT */
3246     osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED"); 
3247     return CM_ERROR_BADOP;
3248 #endif /* DFS_SUPPORT */
3249 }
3250
3251 long 
3252 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3253 {
3254     /* This is a UNICODE only request (bit15 of Flags2) */
3255
3256     /* There is nothing we can do about this operation.  The client is going to
3257      * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3258      * Unfortunately, there is really nothing we can do about it other then log it 
3259      * somewhere.  Even then I don't think there is anything for us to do.
3260      * So let's return an error value.
3261      */
3262
3263     osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3264     return CM_ERROR_BADOP;
3265 }
3266
3267 long 
3268 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3269         smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3270         cm_req_t *reqp)
3271 {
3272     long code = 0;
3273     cm_scache_t *scp;
3274     cm_scache_t *targetScp;                     /* target if scp is a symlink */
3275     char *dptr;
3276     afs_uint32 dosTime;
3277     FILETIME ft;
3278     int shortTemp;
3279     unsigned short attr;
3280     unsigned long lattr;
3281     smb_dirListPatch_t *patchp;
3282     smb_dirListPatch_t *npatchp;
3283         
3284     for(patchp = *dirPatchespp; patchp; patchp =
3285          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3286                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3287         if (code) continue;
3288         lock_ObtainMutex(&scp->mx);
3289         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3290                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3291         if (code) { 
3292             lock_ReleaseMutex(&scp->mx);
3293             cm_ReleaseSCache(scp);
3294
3295             dptr = patchp->dptr;
3296
3297             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3298                errors in the client. */
3299             if (infoLevel >= 0x101) {
3300                 /* 1969-12-31 23:59:59 +00 */
3301                 ft.dwHighDateTime = 0x19DB200;
3302                 ft.dwLowDateTime = 0x5BB78980;
3303
3304                 /* copy to Creation Time */
3305                 *((FILETIME *)dptr) = ft;
3306                 dptr += 8;
3307
3308                 /* copy to Last Access Time */
3309                 *((FILETIME *)dptr) = ft;
3310                 dptr += 8;
3311
3312                 /* copy to Last Write Time */
3313                 *((FILETIME *)dptr) = ft;
3314                 dptr += 8;
3315
3316                 /* copy to Change Time */
3317                 *((FILETIME *)dptr) = ft;
3318                 dptr += 24;
3319
3320                 /* merge in hidden attribute */
3321                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3322                     *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3323                 }
3324                 dptr += 4;
3325             } else {
3326                 /* 1969-12-31 23:59:58 +00*/
3327                 dosTime = 0xEBBFBF7D;
3328
3329                 /* and copy out date */
3330                 shortTemp = (dosTime>>16) & 0xffff;
3331                 *((u_short *)dptr) = shortTemp;
3332                 dptr += 2;
3333
3334                 /* copy out creation time */
3335                 shortTemp = dosTime & 0xffff;
3336                 *((u_short *)dptr) = shortTemp;
3337                 dptr += 2;
3338
3339                 /* and copy out date */
3340                 shortTemp = (dosTime>>16) & 0xffff;
3341                 *((u_short *)dptr) = shortTemp;
3342                 dptr += 2;
3343                         
3344                 /* copy out access time */
3345                 shortTemp = dosTime & 0xffff;
3346                 *((u_short *)dptr) = shortTemp;
3347                 dptr += 2;
3348
3349                 /* and copy out date */
3350                 shortTemp = (dosTime>>16) & 0xffff;
3351                 *((u_short *)dptr) = shortTemp;
3352                 dptr += 2;
3353                         
3354                 /* copy out mod time */
3355                 shortTemp = dosTime & 0xffff;
3356                 *((u_short *)dptr) = shortTemp;
3357                 dptr += 10;
3358
3359                 /* merge in hidden (dot file) attribute */
3360                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3361                     attr = SMB_ATTR_HIDDEN;
3362                     *dptr++ = attr & 0xff;
3363                     *dptr++ = (attr >> 8) & 0xff;
3364                 }       
3365             }
3366             continue;
3367         }
3368                 
3369         /* now watch for a symlink */
3370         code = 0;
3371         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3372             lock_ReleaseMutex(&scp->mx);
3373             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3374             if (code == 0) {
3375                 /* we have a more accurate file to use (the
3376                  * target of the symbolic link).  Otherwise,
3377                  * we'll just use the symlink anyway.
3378                  */
3379                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3380                           scp, targetScp);
3381                 cm_ReleaseSCache(scp);
3382                 scp = targetScp;
3383             }
3384             lock_ObtainMutex(&scp->mx);
3385         }
3386
3387         dptr = patchp->dptr;
3388
3389         if (infoLevel >= 0x101) {
3390             /* get filetime */
3391             smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3392
3393             /* copy to Creation Time */
3394             *((FILETIME *)dptr) = ft;
3395             dptr += 8;
3396
3397             /* copy to Last Access Time */
3398             *((FILETIME *)dptr) = ft;
3399             dptr += 8;
3400
3401             /* copy to Last Write Time */
3402             *((FILETIME *)dptr) = ft;
3403             dptr += 8;
3404
3405             /* copy to Change Time */
3406             *((FILETIME *)dptr) = ft;
3407             dptr += 8;
3408
3409             /* Use length for both file length and alloc length */
3410             *((LARGE_INTEGER *)dptr) = scp->length;
3411             dptr += 8;
3412             *((LARGE_INTEGER *)dptr) = scp->length;
3413             dptr += 8;
3414
3415             /* Copy attributes */
3416             lattr = smb_ExtAttributes(scp);
3417             if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3418                 if (lattr == SMB_ATTR_NORMAL)
3419                     lattr = SMB_ATTR_DIRECTORY;
3420                 else
3421                     lattr |= SMB_ATTR_DIRECTORY;
3422             }
3423             /* merge in hidden (dot file) attribute */
3424             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3425                 if (lattr == SMB_ATTR_NORMAL)
3426                     lattr = SMB_ATTR_HIDDEN;
3427                 else
3428                     lattr |= SMB_ATTR_HIDDEN;
3429             }
3430             *((u_long *)dptr) = lattr;
3431             dptr += 4;
3432         } else {
3433             /* get dos time */
3434             smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3435
3436             /* and copy out date */
3437             shortTemp = (dosTime>>16) & 0xffff;
3438             *((u_short *)dptr) = shortTemp;
3439             dptr += 2;
3440
3441             /* copy out creation time */
3442             shortTemp = dosTime & 0xffff;
3443             *((u_short *)dptr) = shortTemp;
3444             dptr += 2;
3445
3446             /* and copy out date */
3447             shortTemp = (dosTime>>16) & 0xffff;
3448             *((u_short *)dptr) = shortTemp;
3449             dptr += 2;
3450
3451             /* copy out access time */
3452             shortTemp = dosTime & 0xffff;
3453             *((u_short *)dptr) = shortTemp;
3454             dptr += 2;
3455
3456             /* and copy out date */
3457             shortTemp = (dosTime>>16) & 0xffff;
3458             *((u_short *)dptr) = shortTemp;
3459             dptr += 2;
3460
3461             /* copy out mod time */
3462             shortTemp = dosTime & 0xffff;
3463             *((u_short *)dptr) = shortTemp;
3464             dptr += 2;
3465
3466             /* copy out file length and alloc length,
3467              * using the same for both
3468              */
3469             *((u_long *)dptr) = scp->length.LowPart;
3470             dptr += 4;
3471             *((u_long *)dptr) = scp->length.LowPart;
3472             dptr += 4;
3473
3474             /* finally copy out attributes as short */
3475             attr = smb_Attributes(scp);
3476             /* merge in hidden (dot file) attribute */
3477             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3478                 if (lattr == SMB_ATTR_NORMAL)
3479                     lattr = SMB_ATTR_HIDDEN;
3480                 else
3481                     lattr |= SMB_ATTR_HIDDEN;
3482             }
3483             *dptr++ = attr & 0xff;
3484             *dptr++ = (attr >> 8) & 0xff;
3485         }
3486
3487         lock_ReleaseMutex(&scp->mx);
3488         cm_ReleaseSCache(scp);
3489     }
3490         
3491     /* now free the patches */
3492     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3493         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3494         free(patchp);
3495     }
3496         
3497     /* and mark the list as empty */
3498     *dirPatchespp = NULL;
3499
3500     return code;
3501 }
3502
3503 #ifndef USE_OLD_MATCHING
3504 // char table for case insensitive comparison
3505 char mapCaseTable[256];
3506
3507 VOID initUpperCaseTable(VOID) 
3508 {
3509     int i;
3510     for (i = 0; i < 256; ++i) 
3511        mapCaseTable[i] = toupper(i);
3512     // make '"' match '.' 
3513     mapCaseTable[(int)'"'] = toupper('.');
3514     // make '<' match '*' 
3515     mapCaseTable[(int)'<'] = toupper('*');
3516     // make '>' match '?' 
3517     mapCaseTable[(int)'>'] = toupper('?');    
3518 }
3519
3520 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3521 // name 'name'.
3522 // Note : this procedure works recursively calling itself.
3523 // Parameters
3524 // PSZ pattern    : string containing metacharacters.
3525 // PSZ name       : file name to be compared with 'pattern'.
3526 // Return value
3527 // BOOL : TRUE/FALSE (match/mistmatch)
3528
3529 BOOL 
3530 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold) 
3531 {
3532     PSZ pename;         // points to the last 'name' character
3533     PSZ p;
3534     pename = name + strlen(name) - 1;
3535     while (*name) {
3536         switch (*pattern) {
3537         case '?':
3538             ++pattern;
3539             if (*name == '.')
3540                 continue;
3541             ++name;
3542             break;
3543          case '*':
3544             ++pattern;
3545             if (*pattern == '\0')
3546                 return TRUE;
3547             for (p = pename; p >= name; --p) {
3548                 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3549                      !casefold && (*p == *pattern)) &&
3550                      szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3551                     return TRUE;
3552             } /* endfor */
3553             return FALSE;
3554         default:
3555             if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3556                 (!casefold && *name != *pattern))
3557                 return FALSE;
3558             ++pattern, ++name;
3559             break;
3560         } /* endswitch */
3561     } /* endwhile */ 
3562
3563     /* if all we have left are wildcards, then we match */
3564     for (;*pattern; pattern++) {
3565         if (*pattern != '*' && *pattern != '?')
3566             return FALSE;
3567     }
3568     return TRUE;
3569 }
3570
3571 /* do a case-folding search of the star name mask with the name in namep.
3572  * Return 1 if we match, otherwise 0.
3573  */
3574 int smb_V3MatchMask(char *namep, char *maskp, int flags) 
3575 {
3576     char * newmask;
3577     int    i, j, star, qmark, casefold, retval;
3578
3579     /* make sure we only match 8.3 names, if requested */
3580     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
3581         return 0;
3582     
3583     casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3584
3585     /* optimize the pattern:
3586      * if there is a mixture of '?' and '*',
3587      * for example  the sequence "*?*?*?*"
3588      * must be turned into the form "*"
3589      */
3590     newmask = (char *)malloc(strlen(maskp)+1);
3591     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3592         switch ( maskp[i] ) {
3593         case '?':
3594         case '>':
3595             qmark++;
3596             break;
3597         case '<':
3598         case '*':
3599             star++;
3600             break;
3601         default:
3602             if ( star ) {
3603                 newmask[j++] = '*';
3604             } else if ( qmark ) {
3605                 while ( qmark-- )
3606                     newmask[j++] = '?';
3607             }
3608             newmask[j++] = maskp[i];
3609             star = 0;
3610             qmark = 0;
3611         }
3612     }
3613     if ( star ) {
3614         newmask[j++] = '*';
3615     } else if ( qmark ) {
3616         while ( qmark-- )
3617