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