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