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