522f58d48fcb524e4c6448f74c95aba3f380c12e
[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         code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
2826                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2827                          userp, tidPathp, &req, &dscp);
2828         cm_FreeSpace(spacep);
2829
2830         if (code) {
2831             cm_ReleaseUser(userp);
2832             smb_FreeTran2Packet(outp);
2833             return code;
2834         }
2835         
2836 #ifdef DFS_SUPPORT
2837         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2838             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2839                                                       (clientchar_t*) spacep->data);
2840             cm_ReleaseSCache(dscp);
2841             cm_ReleaseUser(userp);
2842             smb_FreeTran2Packet(outp);
2843             if ( WANTS_DFS_PATHNAMES(p) || pnc )
2844                 return CM_ERROR_PATH_NOT_COVERED;
2845             else
2846                 return CM_ERROR_NOSUCHPATH;
2847         }
2848 #endif /* DFS_SUPPORT */
2849
2850         /* otherwise, scp points to the parent directory.  Do a lookup,
2851          * and truncate the file if we find it, otherwise we create the
2852          * file.
2853          */
2854         if (!lastNamep) 
2855             lastNamep = pathp;
2856         else 
2857             lastNamep++;
2858         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2859                          &req, &scp);
2860         if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2861             cm_ReleaseSCache(dscp);
2862             cm_ReleaseUser(userp);
2863             smb_FreeTran2Packet(outp);
2864             return code;
2865         }
2866     } else {
2867         /* macintosh is expensive to program for it */
2868         cm_FreeSpace(spacep);
2869
2870 #ifdef DFS_SUPPORT
2871         if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2872             int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2873             cm_ReleaseSCache(scp);
2874             cm_ReleaseUser(userp);
2875             smb_FreeTran2Packet(outp);
2876             if ( WANTS_DFS_PATHNAMES(p) || pnc )
2877                 return CM_ERROR_PATH_NOT_COVERED;
2878             else
2879                 return CM_ERROR_NOSUCHPATH;
2880         }
2881 #endif /* DFS_SUPPORT */
2882     }
2883         
2884     /* if we get here, if code is 0, the file exists and is represented by
2885      * scp.  Otherwise, we have to create it.
2886      */
2887     if (code == 0) {
2888         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2889         if (code) {
2890             if (dscp) 
2891                 cm_ReleaseSCache(dscp);
2892             cm_ReleaseSCache(scp);
2893             cm_ReleaseUser(userp);
2894             smb_FreeTran2Packet(outp);
2895             return code;
2896         }
2897
2898         if (excl) {
2899             /* oops, file shouldn't be there */
2900             if (dscp) 
2901                 cm_ReleaseSCache(dscp);
2902             cm_ReleaseSCache(scp);
2903             cm_ReleaseUser(userp);
2904             smb_FreeTran2Packet(outp);
2905             return CM_ERROR_EXISTS;
2906         }
2907
2908         if (trunc) {
2909             setAttr.mask = CM_ATTRMASK_LENGTH;
2910             setAttr.length.LowPart = 0;
2911             setAttr.length.HighPart = 0;
2912             code = cm_SetAttr(scp, &setAttr, userp, &req);
2913             openAction = 3;     /* truncated existing file */
2914         }   
2915         else 
2916             openAction = 1;     /* found existing file */
2917     }
2918     else if (!(openFun & 0x10)) {
2919         /* don't create if not found */
2920         if (dscp) 
2921             cm_ReleaseSCache(dscp);
2922         osi_assertx(scp == NULL, "null cm_scache_t");
2923         cm_ReleaseUser(userp);
2924         smb_FreeTran2Packet(outp);
2925         return CM_ERROR_NOSUCHFILE;
2926     }
2927     else {
2928         osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2929         openAction = 2; /* created file */
2930         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2931         cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2932         smb_SetInitialModeBitsForFile(attributes, &setAttr);
2933
2934         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2935                           &req);
2936         if (code == 0) {
2937             created = 1;
2938             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2939                 smb_NotifyChange(FILE_ACTION_ADDED,
2940                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,  
2941                                   dscp, lastNamep, NULL, TRUE);
2942         } else if (!excl && code == CM_ERROR_EXISTS) {
2943             /* not an exclusive create, and someone else tried
2944              * creating it already, then we open it anyway.  We
2945              * don't bother retrying after this, since if this next
2946              * fails, that means that the file was deleted after we
2947              * started this call.
2948              */
2949             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2950                               userp, &req, &scp);
2951             if (code == 0) {
2952                 if (trunc) {
2953                     setAttr.mask = CM_ATTRMASK_LENGTH;
2954                     setAttr.length.LowPart = 0;
2955                     setAttr.length.HighPart = 0;
2956                     code = cm_SetAttr(scp, &setAttr, userp,
2957                                        &req);
2958                 }   
2959             }   /* lookup succeeded */
2960         }
2961     }
2962         
2963     /* we don't need this any longer */
2964     if (dscp) 
2965         cm_ReleaseSCache(dscp);
2966
2967     if (code) {
2968         /* something went wrong creating or truncating the file */
2969         if (scp) 
2970             cm_ReleaseSCache(scp);
2971         cm_ReleaseUser(userp);
2972         smb_FreeTran2Packet(outp);
2973         return code;
2974     }
2975         
2976     /* make sure we're about to open a file */
2977     if (scp->fileType != CM_SCACHETYPE_FILE) {
2978         code = 0;
2979         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2980             cm_scache_t * targetScp = 0;
2981             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2982             if (code == 0) {
2983                 /* we have a more accurate file to use (the
2984                  * target of the symbolic link).  Otherwise,
2985                  * we'll just use the symlink anyway.
2986                  */
2987                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2988                           scp, targetScp);
2989                 cm_ReleaseSCache(scp);
2990                 scp = targetScp;
2991             }
2992         }
2993         if (scp->fileType != CM_SCACHETYPE_FILE) {
2994             cm_ReleaseSCache(scp);
2995             cm_ReleaseUser(userp);
2996             smb_FreeTran2Packet(outp);
2997             return CM_ERROR_ISDIR;
2998         }
2999     }
3000
3001     /* now all we have to do is open the file itself */
3002     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3003     osi_assertx(fidp, "null smb_fid_t");
3004         
3005     cm_HoldUser(userp);
3006     lock_ObtainMutex(&fidp->mx);
3007     /* save a pointer to the vnode */
3008     osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
3009     fidp->scp = scp;
3010     lock_ObtainWrite(&scp->rw);
3011     scp->flags |= CM_SCACHEFLAG_SMB_FID;
3012     lock_ReleaseWrite(&scp->rw);
3013     
3014     /* and the user */
3015     fidp->userp = userp;
3016         
3017     /* compute open mode */
3018     if (openMode != 1) 
3019         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
3020     if (openMode == 1 || openMode == 2)
3021         fidp->flags |= SMB_FID_OPENWRITE;
3022
3023     /* remember that the file was newly created */
3024     if (created)
3025         fidp->flags |= SMB_FID_CREATED;
3026
3027     lock_ReleaseMutex(&fidp->mx);
3028
3029     smb_ReleaseFID(fidp);
3030         
3031     cm_Open(scp, 0, userp);
3032
3033     /* copy out remainder of the parms */
3034     parmSlot = 0;
3035     outp->parmsp[parmSlot++] = fidp->fid;
3036     lock_ObtainRead(&scp->rw);
3037     if (extraInfo) {
3038         outp->parmsp[parmSlot++] = smb_Attributes(scp);
3039         cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3040         outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
3041         outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
3042         outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
3043         outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
3044         outp->parmsp[parmSlot++] = openMode;
3045         outp->parmsp[parmSlot++] = 0;   /* file type 0 ==> normal file or dir */
3046         outp->parmsp[parmSlot++] = 0;   /* IPC junk */
3047     }   
3048     /* and the final "always present" stuff */
3049     outp->parmsp[parmSlot++] = openAction;
3050     /* next write out the "unique" ID */
3051     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff); 
3052     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff); 
3053     outp->parmsp[parmSlot++] = 0; 
3054     if (returnEALength) {
3055         outp->parmsp[parmSlot++] = 0; 
3056         outp->parmsp[parmSlot++] = 0; 
3057     }   
3058     lock_ReleaseRead(&scp->rw);
3059     outp->totalData = 0;                /* total # of data bytes */
3060     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
3061
3062     smb_SendTran2Packet(vcp, outp, op);
3063
3064     smb_FreeTran2Packet(outp);
3065
3066     cm_ReleaseUser(userp);
3067     /* leave scp held since we put it in fidp->scp */
3068     return 0;
3069 }   
3070
3071 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3072 {
3073     unsigned short fid;
3074     unsigned short infolevel;
3075
3076     infolevel = p->parmsp[0];
3077     fid = p->parmsp[1];
3078     osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
3079     
3080     return CM_ERROR_BAD_LEVEL;
3081 }
3082
3083 /* TRANS2_QUERY_FS_INFORMATION */
3084 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3085 {
3086     smb_tran2Packet_t *outp;
3087     smb_tran2QFSInfo_t qi;
3088     int responseSize;
3089     size_t sz = 0;
3090         
3091     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
3092
3093     switch (p->parmsp[0]) {
3094     case SMB_INFO_ALLOCATION: 
3095         /* alloc info */
3096         responseSize = sizeof(qi.u.allocInfo); 
3097
3098         qi.u.allocInfo.FSID = 0;
3099         qi.u.allocInfo.sectorsPerAllocUnit = 1;
3100         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
3101         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
3102         qi.u.allocInfo.bytesPerSector = 1024;
3103         break;
3104
3105     case SMB_INFO_VOLUME: 
3106         /* volume info */
3107         qi.u.volumeInfo.vsn = 1234;  /* Volume serial number */
3108         qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
3109
3110         /* we're supposed to pad it out with zeroes to the end */
3111         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
3112         smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
3113
3114         responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
3115         break;
3116
3117     case SMB_QUERY_FS_VOLUME_INFO: 
3118         /* FS volume info */
3119         responseSize = sizeof(qi.u.FSvolumeInfo);
3120
3121         {
3122             FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
3123             memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
3124         }
3125
3126         qi.u.FSvolumeInfo.vsn = 1234;
3127         qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
3128         memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
3129         memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
3130         break;
3131
3132     case SMB_QUERY_FS_SIZE_INFO: 
3133         /* FS size info */
3134         responseSize = sizeof(qi.u.FSsizeInfo); 
3135
3136         qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
3137         qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
3138         qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
3139         qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
3140         qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
3141         qi.u.FSsizeInfo.bytesPerSector = 1024;
3142         break;
3143
3144     case SMB_QUERY_FS_DEVICE_INFO: 
3145         /* FS device info */
3146         responseSize = sizeof(qi.u.FSdeviceInfo); 
3147
3148         qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
3149         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
3150         break;
3151
3152     case SMB_QUERY_FS_ATTRIBUTE_INFO: 
3153         /* FS attribute info */
3154
3155         /* attributes, defined in WINNT.H:
3156          *      FILE_CASE_SENSITIVE_SEARCH      0x1
3157          *      FILE_CASE_PRESERVED_NAMES       0x2
3158          *      FILE_UNICODE_ON_DISK            0x4
3159          *      FILE_VOLUME_QUOTAS              0x10
3160          *      <no name defined>               0x4000
3161          *         If bit 0x4000 is not set, Windows 95 thinks
3162          *         we can't handle long (non-8.3) names,
3163          *         despite our protestations to the contrary.
3164          */
3165         qi.u.FSattributeInfo.attributes = 0x4003;
3166         /* The maxCompLength is supposed to be in bytes */
3167 #ifdef SMB_UNICODE
3168         qi.u.FSattributeInfo.attributes |= 0x04;
3169 #endif
3170         qi.u.FSattributeInfo.maxCompLength = 255;
3171         smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
3172         qi.u.FSattributeInfo.FSnameLength = sz;
3173
3174         responseSize =
3175             sizeof(qi.u.FSattributeInfo.attributes) +
3176             sizeof(qi.u.FSattributeInfo.maxCompLength) +
3177             sizeof(qi.u.FSattributeInfo.FSnameLength) +
3178             sz;
3179
3180         break;
3181
3182     case SMB_INFO_UNIX:         /* CIFS Unix Info */
3183     case SMB_INFO_MACOS:        /* Mac FS Info */
3184     default: 
3185         return CM_ERROR_BADOP;
3186     }   
3187         
3188     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3189         
3190     /* copy out return data, and set corresponding sizes */
3191     outp->totalParms = 0;
3192     outp->totalData = responseSize;
3193     memcpy(outp->datap, &qi, responseSize);
3194
3195     /* send and free the packets */
3196     smb_SendTran2Packet(vcp, outp, op);
3197     smb_FreeTran2Packet(outp);
3198
3199     return 0;
3200 }
3201
3202 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3203 {
3204     osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3205     return CM_ERROR_BADOP;
3206 }
3207
3208 struct smb_ShortNameRock {
3209     clientchar_t *maskp;
3210     unsigned int vnode;
3211     clientchar_t *shortName;
3212     size_t shortNameLen;
3213 };      
3214
3215 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3216                          osi_hyper_t *offp)
3217 {       
3218     struct smb_ShortNameRock *rockp;
3219     normchar_t normName[MAX_PATH];
3220     clientchar_t *shortNameEnd;
3221
3222     rockp = vrockp;
3223
3224     if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3225         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3226                  osi_LogSaveString(smb_logp, dep->name));
3227         return 0;
3228     }
3229
3230     /* compare both names and vnodes, though probably just comparing vnodes
3231      * would be safe enough.
3232      */
3233     if (cm_NormStrCmpI(normName,  rockp->maskp) != 0)
3234         return 0;
3235     if (ntohl(dep->fid.vnode) != rockp->vnode)
3236         return 0;
3237
3238     /* This is the entry */
3239     cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3240     rockp->shortNameLen = shortNameEnd - rockp->shortName;
3241
3242     return CM_ERROR_STOPNOW;
3243 }
3244
3245 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3246         clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3247 {
3248     struct smb_ShortNameRock rock;
3249     clientchar_t *lastNamep;
3250     cm_space_t *spacep;
3251     cm_scache_t *dscp;
3252     int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3253     long code = 0;
3254     osi_hyper_t thyper;
3255
3256     spacep = cm_GetSpace();
3257     /* smb_StripLastComponent will strip "::$DATA" if present */
3258     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3259
3260     code = cm_NameI(cm_RootSCachep(userp, reqp), spacep->wdata,
3261                     caseFold, userp, tidPathp,
3262                     reqp, &dscp);
3263     cm_FreeSpace(spacep);
3264     if (code) 
3265         return code;
3266
3267 #ifdef DFS_SUPPORT
3268     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3269         cm_ReleaseSCache(dscp);
3270         cm_ReleaseUser(userp);
3271 #ifdef DEBUG
3272         DebugBreak();
3273 #endif
3274         return CM_ERROR_PATH_NOT_COVERED;
3275     }
3276 #endif /* DFS_SUPPORT */
3277
3278     if (!lastNamep) lastNamep = pathp;
3279     else lastNamep++;
3280     thyper.LowPart = 0;
3281     thyper.HighPart = 0;
3282     rock.shortName = shortName;
3283     rock.vnode = vnode;
3284     rock.maskp = lastNamep;
3285     code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3286
3287     cm_ReleaseSCache(dscp);
3288
3289     if (code == 0)
3290         return CM_ERROR_NOSUCHFILE;
3291     if (code == CM_ERROR_STOPNOW) {
3292         *shortNameLenp = rock.shortNameLen;
3293         return 0;
3294     }
3295     return code;
3296 }
3297
3298 /* TRANS2_QUERY_PATH_INFORMATION */
3299 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3300 {
3301     smb_tran2Packet_t *outp;
3302     afs_uint32 dosTime;
3303     FILETIME ft;
3304     unsigned short infoLevel;
3305     smb_tran2QPathInfo_t qpi;
3306     int responseSize;
3307     unsigned short attributes;
3308     unsigned long extAttributes;
3309     clientchar_t shortName[13];
3310     size_t len;
3311     cm_user_t *userp;
3312     cm_space_t *spacep;
3313     cm_scache_t *scp, *dscp;
3314     int scp_rw_held = 0;
3315     int delonclose = 0;
3316     long code = 0;
3317     clientchar_t *pathp;
3318     clientchar_t *tidPathp;
3319     clientchar_t *lastComp;
3320     cm_req_t req;
3321
3322     smb_InitReq(&req);
3323
3324     infoLevel = p->parmsp[0];
3325     if (infoLevel == SMB_INFO_IS_NAME_VALID) 
3326         responseSize = 0;
3327     else if (infoLevel == SMB_INFO_STANDARD) 
3328         responseSize = sizeof(qpi.u.QPstandardInfo);
3329     else if (infoLevel == SMB_INFO_QUERY_EA_SIZE) 
3330         responseSize = sizeof(qpi.u.QPeaSizeInfo);
3331     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3332         responseSize = sizeof(qpi.u.QPfileBasicInfo);
3333     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3334         responseSize = sizeof(qpi.u.QPfileStandardInfo);
3335     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3336         responseSize = sizeof(qpi.u.QPfileEaInfo);
3337     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
3338         responseSize = sizeof(qpi.u.QPfileNameInfo);
3339     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) 
3340         responseSize = sizeof(qpi.u.QPfileAllInfo);
3341     else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) 
3342         responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3343     else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3344         responseSize = sizeof(qpi.u.QPfileStreamInfo);
3345     else {
3346         osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
3347                   p->opcode, infoLevel);
3348         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3349         return 0;
3350     }
3351     memset(&qpi, 0, sizeof(qpi));
3352
3353     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3354     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
3355               osi_LogSaveClientString(smb_logp, pathp));
3356
3357     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3358
3359     if (infoLevel > 0x100)
3360         outp->totalParms = 2;
3361     else
3362         outp->totalParms = 0;
3363         
3364     /* now, if we're at infoLevel 6, we're only being asked to check
3365      * the syntax, so we just OK things now.  In particular, we're *not*
3366      * being asked to verify anything about the state of any parent dirs.
3367      */
3368     if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3369         smb_SendTran2Packet(vcp, outp, opx);
3370         smb_FreeTran2Packet(outp);
3371         return 0;
3372     }   
3373         
3374     userp = smb_GetTran2User(vcp, p);
3375     if (!userp) {
3376         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3377         smb_FreeTran2Packet(outp);
3378         return CM_ERROR_BADSMB;
3379     }
3380
3381     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3382     if(code) {
3383         osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
3384         cm_ReleaseUser(userp);
3385         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3386         smb_FreeTran2Packet(outp);
3387         return 0;
3388     }
3389
3390     osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
3391               osi_LogSaveClientString(smb_logp, tidPathp));
3392
3393     /*
3394      * XXX Strange hack XXX
3395      *
3396      * As of Patch 7 (13 January 98), we are having the following problem:
3397      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3398      * requests to look up "desktop.ini" in all the subdirectories.
3399      * This can cause zillions of timeouts looking up non-existent cells
3400      * and volumes, especially in the top-level directory.
3401      *
3402      * We have not found any way to avoid this or work around it except
3403      * to explicitly ignore the requests for mount points that haven't
3404      * yet been evaluated and for directories that haven't yet been
3405      * fetched.
3406      */
3407     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3408         spacep = cm_GetSpace();
3409         /* smb_StripLastComponent will strip "::$DATA" if present */
3410         smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3411 #ifndef SPECIAL_FOLDERS
3412         /* Make sure that lastComp is not NULL */
3413         if (lastComp) {
3414             if (cm_ClientStrCmpIA(lastComp,  _C("\\desktop.ini")) == 0) {
3415                 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3416                                  CM_FLAG_CASEFOLD
3417                                  | CM_FLAG_DIRSEARCH
3418                                  | CM_FLAG_FOLLOW,
3419                                  userp, tidPathp, &req, &dscp);
3420                 if (code == 0) {
3421 #ifdef DFS_SUPPORT
3422                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3423                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3424                                                                   spacep->wdata);
3425                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3426                             code = CM_ERROR_PATH_NOT_COVERED;
3427                         else
3428                             code = CM_ERROR_NOSUCHPATH;
3429                     } else
3430 #endif /* DFS_SUPPORT */
3431                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3432                         code = CM_ERROR_NOSUCHFILE;
3433                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3434                         cm_buf_t *bp = buf_Find(dscp, &hzero);
3435                         if (bp) {
3436                             buf_Release(bp);
3437                             bp = NULL;
3438                         }
3439                         else
3440                             code = CM_ERROR_NOSUCHFILE;
3441                     }
3442                     cm_ReleaseSCache(dscp);
3443                     if (code) {
3444                         cm_FreeSpace(spacep);
3445                         cm_ReleaseUser(userp);
3446                         smb_SendTran2Error(vcp, p, opx, code);
3447                         smb_FreeTran2Packet(outp);
3448                         return 0;
3449                     }
3450                 }
3451             }
3452         }
3453 #endif /* SPECIAL_FOLDERS */
3454
3455         cm_FreeSpace(spacep);
3456     }
3457
3458     /* now do namei and stat, and copy out the info */
3459     code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3460                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3461
3462     if (code) {
3463         cm_ReleaseUser(userp);
3464         smb_SendTran2Error(vcp, p, opx, code);
3465         smb_FreeTran2Packet(outp);
3466         return 0;
3467     }
3468
3469 #ifdef DFS_SUPPORT
3470     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3471         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3472         cm_ReleaseSCache(scp);
3473         cm_ReleaseUser(userp);
3474         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3475             code = CM_ERROR_PATH_NOT_COVERED;
3476         else
3477             code = CM_ERROR_NOSUCHPATH;
3478         smb_SendTran2Error(vcp, p, opx, code);
3479         smb_FreeTran2Packet(outp);
3480         return 0;
3481     }
3482 #endif /* DFS_SUPPORT */
3483
3484     lock_ObtainWrite(&scp->rw);
3485     scp_rw_held = 2;
3486     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3487                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3488     if (code)
3489         goto done;
3490
3491     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3492         
3493     lock_ConvertWToR(&scp->rw);
3494     scp_rw_held = 1;
3495
3496     len = 0;
3497
3498     /* now we have the status in the cache entry, and everything is locked.
3499      * Marshall the output data.
3500      */
3501     /* for info level 108, figure out short name */
3502     if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3503         code = cm_GetShortName(pathp, userp, &req,
3504                                 tidPathp, scp->fid.vnode, shortName,
3505                                &len);
3506         if (code) {
3507             goto done;
3508         }
3509
3510         smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3511         qpi.u.QPfileAltNameInfo.fileNameLength = len;
3512         responseSize = sizeof(unsigned long) + len;
3513     }
3514     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3515         smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3516         qpi.u.QPfileNameInfo.fileNameLength = len;
3517         responseSize = sizeof(unsigned long) + len;
3518     }
3519     else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3520         cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3521         qpi.u.QPstandardInfo.creationDateTime = dosTime;
3522         qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3523         qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3524         qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3525         qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3526         attributes = smb_Attributes(scp);
3527         qpi.u.QPstandardInfo.attributes = attributes;
3528         qpi.u.QPstandardInfo.eaSize = 0;
3529     }
3530     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3531         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3532         qpi.u.QPfileBasicInfo.creationTime = ft;
3533         qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3534         qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3535         qpi.u.QPfileBasicInfo.changeTime = ft;
3536         extAttributes = smb_ExtAttributes(scp);
3537         qpi.u.QPfileBasicInfo.attributes = extAttributes;
3538         qpi.u.QPfileBasicInfo.reserved = 0;
3539     }
3540     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3541         smb_fid_t * fidp;
3542             
3543         lock_ReleaseRead(&scp->rw);
3544         scp_rw_held = 0;
3545         fidp = smb_FindFIDByScache(vcp, scp);
3546
3547         qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3548         qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3549         qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3550         qpi.u.QPfileStandardInfo.directory = 
3551             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3552               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3553               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3554         qpi.u.QPfileStandardInfo.reserved = 0;
3555
3556         if (fidp) {
3557             lock_ObtainMutex(&fidp->mx);
3558             delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3559             lock_ReleaseMutex(&fidp->mx);
3560             smb_ReleaseFID(fidp);
3561         }
3562         qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3563     }
3564     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3565         qpi.u.QPfileEaInfo.eaSize = 0;
3566     }
3567     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3568         smb_fid_t * fidp;
3569
3570         lock_ReleaseRead(&scp->rw);
3571         scp_rw_held = 0;
3572         fidp = smb_FindFIDByScache(vcp, scp);
3573
3574         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3575         qpi.u.QPfileAllInfo.creationTime = ft;
3576         qpi.u.QPfileAllInfo.lastAccessTime = ft;
3577         qpi.u.QPfileAllInfo.lastWriteTime = ft;
3578         qpi.u.QPfileAllInfo.changeTime = ft;
3579         extAttributes = smb_ExtAttributes(scp);
3580         qpi.u.QPfileAllInfo.attributes = extAttributes;
3581         qpi.u.QPfileAllInfo.allocationSize = scp->length;
3582         qpi.u.QPfileAllInfo.endOfFile = scp->length;
3583         qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3584         qpi.u.QPfileAllInfo.deletePending = 0;
3585         qpi.u.QPfileAllInfo.directory = 
3586             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3587               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3588               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3589         qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
3590         qpi.u.QPfileAllInfo.indexNumber.LowPart  = scp->fid.unique;
3591         qpi.u.QPfileAllInfo.eaSize = 0;
3592         qpi.u.QPfileAllInfo.accessFlags = 0;
3593         if (fidp) {
3594             lock_ObtainMutex(&fidp->mx);
3595             if (fidp->flags & SMB_FID_OPENDELETE)
3596                 qpi.u.QPfileAllInfo.accessFlags |= DELETE;
3597             if (fidp->flags & SMB_FID_OPENREAD_LISTDIR)
3598                 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_READ|AFS_ACCESS_EXECUTE;
3599             if (fidp->flags & SMB_FID_OPENWRITE)
3600                 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_WRITE;
3601             if (fidp->flags & SMB_FID_DELONCLOSE)
3602                 qpi.u.QPfileAllInfo.deletePending = 1;
3603             lock_ReleaseMutex(&fidp->mx);
3604             smb_ReleaseFID(fidp);
3605         }
3606         qpi.u.QPfileAllInfo.indexNumber2.HighPart&nbs