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