7c453f3e1f5cec6dd71e143d4ad696fb1958d0d5
[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             if (usernIsSID)
1091                 unp->flags |= SMB_USERNAMEFLAG_SID;
1092         }
1093     if (usernIsSID)
1094         unp->flags |= SMB_USERNAMEFLAG_SID;
1095         lock_ReleaseMutex(&unp->mx);
1096
1097         /* Create a new UID and cm_user_t structure */
1098         userp = unp->userp;
1099         if (!userp)
1100             userp = cm_NewUser();
1101         cm_HoldUserVCRef(userp);
1102         lock_ObtainMutex(&vcp->mx);
1103         if (!vcp->uidCounter)
1104             vcp->uidCounter++; /* handle unlikely wraparounds */
1105         newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
1106         lock_ReleaseMutex(&vcp->mx);
1107
1108         /* Create a new smb_user_t structure and connect them up */
1109         lock_ObtainMutex(&unp->mx);
1110         unp->userp = userp;
1111         lock_ReleaseMutex(&unp->mx);
1112
1113         uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
1114         if (uidp) {
1115             lock_ObtainMutex(&uidp->mx);
1116             uidp->unp = unp;
1117             osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
1118             lock_ReleaseMutex(&uidp->mx);
1119             smb_ReleaseUID(uidp);
1120         }
1121     }
1122
1123     /* Return UID to the client */
1124     ((smb_t *)outp)->uid = newUid;
1125     /* Also to the next chained message */
1126     ((smb_t *)inp)->uid = newUid;
1127
1128     osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
1129              osi_LogSaveClientString(smb_logp, usern), newUid,
1130              osi_LogSaveClientString(smb_logp, s1));
1131
1132     smb_SetSMBParm(outp, 2, 0);
1133
1134     if (vcp->flags & SMB_VCFLAG_USENT) {
1135         if (smb_authType == SMB_AUTH_EXTENDED) {
1136             size_t cb_data = 0;
1137
1138             smb_SetSMBParm(outp, 3, secBlobOutLength);
1139
1140             tp = smb_GetSMBData(outp, NULL);
1141             if (secBlobOutLength) {
1142                 memcpy(tp, secBlobOut, secBlobOutLength);
1143                 free(secBlobOut);
1144                 tp += secBlobOutLength;
1145                 cb_data +=  secBlobOutLength;
1146             }
1147
1148             tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1149             tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1150             tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1151
1152             smb_SetSMBDataLength(outp, cb_data);
1153         } else {
1154             smb_SetSMBDataLength(outp, 0);
1155         }
1156     } else {
1157         if (smb_authType == SMB_AUTH_EXTENDED) {
1158             size_t cb_data = 0;
1159
1160             tp = smb_GetSMBData(outp, NULL);
1161
1162             tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
1163             tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
1164             tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
1165
1166             smb_SetSMBDataLength(outp, cb_data);
1167         } else {
1168             smb_SetSMBDataLength(outp, 0);
1169         }
1170     }
1171
1172     if (secSidString)
1173         LocalFree(secSidString);
1174     return 0;
1175 }
1176
1177 /* SMB_COM_LOGOFF_ANDX */
1178 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1179 {
1180     smb_user_t *uidp;
1181
1182     /* find the tree and free it */
1183     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1184     if (uidp) {
1185         smb_username_t * unp;
1186
1187         osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1188                  osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1189
1190         lock_ObtainMutex(&uidp->mx);
1191         uidp->flags |= SMB_USERFLAG_DELETE;
1192         /*
1193          * it doesn't get deleted right away
1194          * because the vcp points to it
1195          */
1196         unp = uidp->unp;
1197         lock_ReleaseMutex(&uidp->mx);
1198
1199 #ifdef COMMENT
1200         /* we can't do this.  we get logoff messages prior to a session
1201          * disconnect even though it doesn't mean the user is logging out.
1202          * we need to create a new pioctl and EventLogoff handler to set
1203          * SMB_USERNAMEFLAG_LOGOFF.
1204          */
1205         if (unp && smb_LogoffTokenTransfer) {
1206             lock_ObtainMutex(&unp->mx);
1207             unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1208             unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1209             lock_ReleaseMutex(&unp->mx);
1210         }
1211 #endif
1212
1213         smb_ReleaseUID(uidp);
1214     }
1215     else
1216         osi_Log0(smb_logp, "SMB3 user logoffX");
1217
1218     smb_SetSMBDataLength(outp, 0);
1219     return 0;
1220 }
1221
1222 #define SMB_SUPPORT_SEARCH_BITS        0x0001
1223 #define SMB_SHARE_IS_IN_DFS            0x0002
1224
1225 /* SMB_COM_TREE_CONNECT_ANDX */
1226 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1227 {
1228     smb_tid_t *tidp;
1229     smb_user_t *uidp = NULL;
1230     unsigned short newTid;
1231     clientchar_t shareName[AFSPATHMAX];
1232     clientchar_t *sharePath;
1233     int shareFound;
1234     char *tp;
1235     clientchar_t *slashp;
1236     clientchar_t *pathp;
1237     clientchar_t *passwordp;
1238     clientchar_t *servicep;
1239     cm_user_t *userp = NULL;
1240     int ipc = 0;
1241
1242     osi_Log0(smb_logp, "SMB3 receive tree connect");
1243
1244     /* parse input parameters */
1245     tp = smb_GetSMBData(inp, NULL);
1246     passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1247     pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1248     servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1249
1250     slashp = cm_ClientStrRChr(pathp, '\\');
1251     if (!slashp) {
1252         return CM_ERROR_BADSMB;
1253     }
1254     cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1255
1256     osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1257              osi_LogSaveClientString(smb_logp, pathp),
1258              osi_LogSaveClientString(smb_logp, shareName),
1259              osi_LogSaveClientString(smb_logp, servicep));
1260
1261     if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1262         cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1263 #ifndef NO_IPC
1264         osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1265         ipc = 1;
1266 #else
1267         return CM_ERROR_NOIPC;
1268 #endif
1269     }
1270
1271     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1272     if (uidp)
1273         userp = smb_GetUserFromUID(uidp);
1274
1275     lock_ObtainMutex(&vcp->mx);
1276     newTid = vcp->tidCounter++;
1277     lock_ReleaseMutex(&vcp->mx);
1278
1279     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1280
1281     if (!ipc) {
1282         if (!cm_ClientStrCmp(shareName, _C("*.")))
1283             cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1284         shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1285         if (!shareFound) {
1286             if (uidp)
1287                 smb_ReleaseUID(uidp);
1288             smb_ReleaseTID(tidp, FALSE);
1289             return CM_ERROR_BADSHARENAME;
1290         }
1291
1292         if (vcp->flags & SMB_VCFLAG_USENT)
1293         {
1294             int policy = smb_FindShareCSCPolicy(shareName);
1295             HKEY parmKey;
1296             DWORD code;
1297             DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1298
1299             code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1300                                  0, KEY_QUERY_VALUE, &parmKey);
1301             if (code == ERROR_SUCCESS) {
1302                 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1303                                        (BYTE *)&dwAdvertiseDFS, &dwSize);
1304                 if (code != ERROR_SUCCESS)
1305                     dwAdvertiseDFS = 0;
1306                 RegCloseKey (parmKey);
1307             }
1308             smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS |
1309                            (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1310                            (policy << 2));
1311         }
1312     } else {
1313         smb_SetSMBParm(outp, 2, 0);
1314         sharePath = NULL;
1315     }
1316     if (uidp)
1317         smb_ReleaseUID(uidp);
1318
1319     lock_ObtainMutex(&tidp->mx);
1320     tidp->userp = userp;
1321     tidp->pathname = sharePath;
1322     if (ipc)
1323         tidp->flags |= SMB_TIDFLAG_IPC;
1324     lock_ReleaseMutex(&tidp->mx);
1325     smb_ReleaseTID(tidp, FALSE);
1326
1327     ((smb_t *)outp)->tid = newTid;
1328     ((smb_t *)inp)->tid = newTid;
1329     tp = smb_GetSMBData(outp, NULL);
1330     if (!ipc) {
1331         size_t cb_data = 0;
1332
1333         tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1334         tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1335         smb_SetSMBDataLength(outp, cb_data);
1336     } else {
1337         size_t cb_data = 0;
1338
1339         tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1340         smb_SetSMBDataLength(outp, cb_data);
1341     }
1342
1343     osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1344     return 0;
1345 }
1346
1347 /* must be called with global tran lock held */
1348 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1349 {
1350     smb_tran2Packet_t *tp;
1351     smb_t *smbp;
1352
1353     smbp = (smb_t *) inp->data;
1354     for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1355         if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1356             return tp;
1357     }
1358     return NULL;
1359 }
1360
1361 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1362                                       int totalParms, int totalData)
1363 {
1364     smb_tran2Packet_t *tp;
1365     smb_t *smbp;
1366
1367     smbp = (smb_t *) inp->data;
1368     tp = malloc(sizeof(*tp));
1369     memset(tp, 0, sizeof(*tp));
1370     tp->vcp = vcp;
1371     smb_HoldVC(vcp);
1372     tp->curData = tp->curParms = 0;
1373     tp->totalData = totalData;
1374     tp->totalParms = totalParms;
1375     tp->tid = smbp->tid;
1376     tp->mid = smbp->mid;
1377     tp->uid = smbp->uid;
1378     tp->pid = smbp->pid;
1379     tp->res[0] = smbp->res[0];
1380     osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1381     if (totalParms != 0)
1382         tp->parmsp = malloc(totalParms);
1383     if (totalData != 0)
1384         tp->datap = malloc(totalData);
1385     if (smbp->com == 0x25 || smbp->com == 0x26)
1386         tp->com = 0x25;
1387     else {
1388         tp->opcode = smb_GetSMBParm(inp, 14);
1389         tp->com = 0x32;
1390     }
1391     tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1392 #ifdef SMB_UNICODE
1393     if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1394         tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1395 #endif
1396     return tp;
1397 }
1398
1399 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1400                                               smb_tran2Packet_t *inp, smb_packet_t *outp,
1401                                               int totalParms, int totalData)
1402 {
1403     smb_tran2Packet_t *tp;
1404     unsigned short parmOffset;
1405     unsigned short dataOffset;
1406     unsigned short dataAlign;
1407
1408     tp = malloc(sizeof(*tp));
1409     memset(tp, 0, sizeof(*tp));
1410     smb_HoldVC(vcp);
1411     tp->vcp = vcp;
1412     tp->curData = tp->curParms = 0;
1413     tp->totalData = totalData;
1414     tp->totalParms = totalParms;
1415     tp->oldTotalParms = totalParms;
1416     tp->tid = inp->tid;
1417     tp->mid = inp->mid;
1418     tp->uid = inp->uid;
1419     tp->pid = inp->pid;
1420     tp->res[0] = inp->res[0];
1421     tp->opcode = inp->opcode;
1422     tp->com = inp->com;
1423
1424     /*
1425      * We calculate where the parameters and data will start.
1426      * This calculation must parallel the calculation in
1427      * smb_SendTran2Packet.
1428      */
1429
1430     parmOffset = 10*2 + 35;
1431     parmOffset++;                       /* round to even */
1432     tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1433
1434     dataOffset = parmOffset + totalParms;
1435     dataAlign = dataOffset & 2; /* quad-align */
1436     dataOffset += dataAlign;
1437     tp->datap = outp->data + dataOffset;
1438
1439     return tp;
1440 }
1441
1442 /* free a tran2 packet */
1443 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1444 {
1445     if (t2p->vcp) {
1446         smb_ReleaseVC(t2p->vcp);
1447         t2p->vcp = NULL;
1448     }
1449     if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1450         if (t2p->parmsp)
1451             free(t2p->parmsp);
1452         if (t2p->datap)
1453             free(t2p->datap);
1454     }
1455     if (t2p->name) {
1456         free(t2p->name);
1457         t2p->name = NULL;
1458     }
1459     while (t2p->stringsp) {
1460         cm_space_t * ns;
1461
1462         ns = t2p->stringsp;
1463         t2p->stringsp = ns->nextp;
1464         cm_FreeSpace(ns);
1465     }
1466     free(t2p);
1467 }
1468
1469 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1470                                     char ** chainpp, int flags)
1471 {
1472     size_t cb;
1473
1474 #ifdef SMB_UNICODE
1475     if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1476         flags |= SMB_STRF_FORCEASCII;
1477 #endif
1478
1479     cb = p->totalParms - (inp - (char *)p->parmsp);
1480     if (inp < (char *) p->parmsp ||
1481         inp >= ((char *) p->parmsp) + p->totalParms) {
1482 #ifdef DEBUG_UNICODE
1483         DebugBreak();
1484 #endif
1485         cb = p->totalParms;
1486     }
1487
1488     return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1489                               inp, &cb, chainpp, flags);
1490 }
1491
1492 /* called with a VC, an input packet to respond to, and an error code.
1493  * sends an error response.
1494  */
1495 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1496                         smb_packet_t *tp, long code)
1497 {
1498     smb_t *smbp;
1499     unsigned short errCode;
1500     unsigned char errClass;
1501     unsigned long NTStatus;
1502
1503     if (vcp->flags & SMB_VCFLAG_STATUS32)
1504         smb_MapNTError(code, &NTStatus, FALSE);
1505     else
1506         smb_MapCoreError(code, vcp, &errCode, &errClass);
1507
1508     smb_FormatResponsePacket(vcp, NULL, tp);
1509     smbp = (smb_t *) tp;
1510
1511     /* We can handle long names */
1512     if (vcp->flags & SMB_VCFLAG_USENT)
1513         smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1514
1515     /* now copy important fields from the tran 2 packet */
1516     smbp->com = t2p->com;
1517     smbp->tid = t2p->tid;
1518     smbp->mid = t2p->mid;
1519     smbp->pid = t2p->pid;
1520     smbp->uid = t2p->uid;
1521     smbp->res[0] = t2p->res[0];
1522     if (vcp->flags & SMB_VCFLAG_STATUS32) {
1523         smbp->rcls = (unsigned char) (NTStatus & 0xff);
1524         smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1525         smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1526         smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1527         smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1528     }
1529     else {
1530         smbp->rcls = errClass;
1531         smbp->errLow = (unsigned char) (errCode & 0xff);
1532         smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1533     }
1534
1535     /* send packet */
1536     smb_SendPacket(vcp, tp);
1537 }
1538
1539 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1540 {
1541     smb_t *smbp;
1542     unsigned short parmOffset;
1543     unsigned short dataOffset;
1544     unsigned short totalLength;
1545     unsigned short dataAlign;
1546     char *datap;
1547
1548     smb_FormatResponsePacket(vcp, NULL, tp);
1549     smbp = (smb_t *) tp;
1550
1551     /* We can handle long names */
1552     if (vcp->flags & SMB_VCFLAG_USENT)
1553         smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1554
1555     /* now copy important fields from the tran 2 packet */
1556     smbp->com = t2p->com;
1557     smbp->tid = t2p->tid;
1558     smbp->mid = t2p->mid;
1559     smbp->pid = t2p->pid;
1560     smbp->uid = t2p->uid;
1561     smbp->res[0] = t2p->res[0];
1562
1563     if (t2p->error_code) {
1564         if (vcp->flags & SMB_VCFLAG_STATUS32) {
1565             unsigned long NTStatus;
1566
1567             smb_MapNTError(t2p->error_code, &NTStatus, FALSE);
1568
1569             smbp->rcls = (unsigned char) (NTStatus & 0xff);
1570             smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1571             smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1572             smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1573             smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1574         }
1575         else {
1576             unsigned short errCode;
1577             unsigned char errClass;
1578
1579             smb_MapCoreError(t2p->error_code, vcp, &errCode, &errClass);
1580
1581             smbp->rcls = errClass;
1582             smbp->errLow = (unsigned char) (errCode & 0xff);
1583             smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1584         }
1585     }
1586
1587     totalLength = 1 + t2p->totalData + t2p->totalParms;
1588
1589     /* now add the core parameters (tran2 info) to the packet */
1590     smb_SetSMBParm(tp, 0, t2p->totalParms);     /* parm bytes */
1591     smb_SetSMBParm(tp, 1, t2p->totalData);      /* data bytes */
1592     smb_SetSMBParm(tp, 2, 0);           /* reserved */
1593     smb_SetSMBParm(tp, 3, t2p->totalParms);     /* parm bytes in this packet */
1594     parmOffset = 10*2 + 35;                     /* parm offset in packet */
1595     parmOffset++;                               /* round to even */
1596     smb_SetSMBParm(tp, 4, parmOffset);  /* 11 parm words plus *
1597     * hdr, bcc and wct */
1598     smb_SetSMBParm(tp, 5, 0);           /* parm displacement */
1599     smb_SetSMBParm(tp, 6, t2p->totalData);      /* data in this packet */
1600     dataOffset = parmOffset + t2p->oldTotalParms;
1601     dataAlign = dataOffset & 2;         /* quad-align */
1602     dataOffset += dataAlign;
1603     smb_SetSMBParm(tp, 7, dataOffset);  /* offset of data */
1604     smb_SetSMBParm(tp, 8, 0);           /* data displacement */
1605     smb_SetSMBParm(tp, 9, 0);           /* low: setup word count *
1606                                          * high: resvd */
1607
1608     datap = smb_GetSMBData(tp, NULL);
1609     *datap++ = 0;                               /* we rounded to even */
1610
1611     totalLength += dataAlign;
1612     smb_SetSMBDataLength(tp, totalLength);
1613
1614     /* next, send the datagram */
1615     smb_SendPacket(vcp, tp);
1616 }
1617
1618 /* TRANS_SET_NMPIPE_STATE */
1619 long smb_nmpipeSetState(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1620 {
1621     smb_fid_t *fidp;
1622     int fd;
1623     int pipeState = 0x0100;     /* default */
1624     smb_tran2Packet_t *outp = NULL;
1625
1626     fd = p->pipeParam;
1627     if (p->totalParms > 0)
1628         pipeState = p->parmsp[0];
1629
1630     osi_Log2(smb_logp, "smb_nmpipeSetState for fd[%d] with state[0x%x]", fd, pipeState);
1631
1632     fidp = smb_FindFID(vcp, fd, 0);
1633     if (!fidp) {
1634         osi_Log2(smb_logp, "smb_nmpipeSetState Unknown SMB Fid vcp 0x%p fid %d",
1635                  vcp, fd);
1636         return CM_ERROR_BADFD;
1637     }
1638     lock_ObtainMutex(&fidp->mx);
1639     if (pipeState & 0x8000)
1640         fidp->flags |= SMB_FID_BLOCKINGPIPE;
1641     if (pipeState & 0x0100)
1642         fidp->flags |= SMB_FID_MESSAGEMODEPIPE;
1643     lock_ReleaseMutex(&fidp->mx);
1644
1645     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 0);
1646     smb_SendTran2Packet(vcp, outp, op);
1647     smb_FreeTran2Packet(outp);
1648
1649     smb_ReleaseFID(fidp);
1650
1651     return 0;
1652 }
1653
1654 long smb_nmpipeTransact(smb_vc_t * vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1655 {
1656     smb_fid_t *fidp;
1657     int fd;
1658     int is_rpc = 0;
1659
1660     long code = 0;
1661
1662     fd = p->pipeParam;
1663
1664     osi_Log3(smb_logp, "smb_nmpipeTransact for fd[%d] %d bytes in, %d max bytes out",
1665              fd, p->totalData, p->maxReturnData);
1666
1667     fidp = smb_FindFID(vcp, fd, 0);
1668     if (!fidp) {
1669         osi_Log2(smb_logp, "smb_nmpipeTransact Unknown SMB Fid vcp 0x%p fid %d",
1670                  vcp, fd);
1671         return CM_ERROR_BADFD;
1672     }
1673     lock_ObtainMutex(&fidp->mx);
1674     if (fidp->flags & SMB_FID_RPC) {
1675         is_rpc = 1;
1676     }
1677     lock_ReleaseMutex(&fidp->mx);
1678
1679     if (is_rpc) {
1680         code = smb_RPCNmpipeTransact(fidp, vcp, p, op);
1681         smb_ReleaseFID(fidp);
1682     } else {
1683         /* We only deal with RPC pipes */
1684         osi_Log2(smb_logp, "smb_nmpipeTransact Not a RPC vcp 0x%p fid %d",
1685                  vcp, fd);
1686         code = CM_ERROR_BADFD;
1687     }
1688
1689     return code;
1690 }
1691
1692
1693 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1694 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1695 {
1696     smb_tran2Packet_t *asp;
1697     int totalParms;
1698     int totalData;
1699     int parmDisp;
1700     int dataDisp;
1701     int parmOffset;
1702     int dataOffset;
1703     int parmCount;
1704     int dataCount;
1705     int firstPacket;
1706     int rapOp;
1707     long code = 0;
1708
1709     /* We sometimes see 0 word count.  What to do? */
1710     if (*inp->wctp == 0) {
1711         osi_Log0(smb_logp, "Transaction2 word count = 0");
1712         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1713
1714         smb_SetSMBDataLength(outp, 0);
1715         smb_SendPacket(vcp, outp);
1716         return 0;
1717     }
1718
1719     totalParms = smb_GetSMBParm(inp, 0);
1720     totalData = smb_GetSMBParm(inp, 1);
1721
1722     firstPacket = (inp->inCom == 0x25);
1723
1724     /* find the packet we're reassembling */
1725     lock_ObtainWrite(&smb_globalLock);
1726     asp = smb_FindTran2Packet(vcp, inp);
1727     if (!asp) {
1728         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1729     }
1730     lock_ReleaseWrite(&smb_globalLock);
1731
1732     /* now merge in this latest packet; start by looking up offsets */
1733     if (firstPacket) {
1734         parmDisp = dataDisp = 0;
1735         parmOffset = smb_GetSMBParm(inp, 10);
1736         dataOffset = smb_GetSMBParm(inp, 12);
1737         parmCount = smb_GetSMBParm(inp, 9);
1738         dataCount = smb_GetSMBParm(inp, 11);
1739         asp->setupCount = smb_GetSMBParmByte(inp, 13);
1740         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1741         asp->maxReturnData = smb_GetSMBParm(inp, 3);
1742
1743         osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1744                   totalData, dataCount, asp->maxReturnData);
1745
1746         if (asp->setupCount == 2) {
1747             clientchar_t * pname;
1748
1749             asp->pipeCommand = smb_GetSMBParm(inp, 14);
1750             asp->pipeParam = smb_GetSMBParm(inp, 15);
1751             pname = smb_ParseString(inp, inp->wctp + 35, NULL, 0);
1752             if (pname) {
1753                 asp->name = cm_ClientStrDup(pname);
1754             }
1755
1756             osi_Log2(smb_logp, "  Named Pipe command id [%d] with name [%S]",
1757                      asp->pipeCommand, osi_LogSaveClientString(smb_logp, asp->name));
1758         }
1759     }
1760     else {
1761         parmDisp = smb_GetSMBParm(inp, 4);
1762         parmOffset = smb_GetSMBParm(inp, 3);
1763         dataDisp = smb_GetSMBParm(inp, 7);
1764         dataOffset = smb_GetSMBParm(inp, 6);
1765         parmCount = smb_GetSMBParm(inp, 2);
1766         dataCount = smb_GetSMBParm(inp, 5);
1767
1768         osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1769                  parmCount, dataCount);
1770     }
1771
1772     /* now copy the parms and data */
1773     if ( asp->totalParms > 0 && parmCount != 0 )
1774     {
1775         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1776     }
1777     if ( asp->totalData > 0 && dataCount != 0 ) {
1778         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1779     }
1780
1781     /* account for new bytes */
1782     asp->curData += dataCount;
1783     asp->curParms += parmCount;
1784
1785     /* finally, if we're done, remove the packet from the queue and dispatch it */
1786     if (((asp->totalParms > 0 && asp->curParms > 0)
1787          || asp->setupCount == 2) &&
1788         asp->totalData <= asp->curData &&
1789         asp->totalParms <= asp->curParms) {
1790
1791         /* we've received it all */
1792         lock_ObtainWrite(&smb_globalLock);
1793         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1794         lock_ReleaseWrite(&smb_globalLock);
1795
1796         switch(asp->setupCount) {
1797         case 0:
1798             {                   /* RAP */
1799                 rapOp = asp->parmsp[0];
1800
1801                 if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES &&
1802                      smb_rapDispatchTable[rapOp].procp) {
1803
1804                     osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",
1805                              myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1806
1807                     code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1808
1809                     osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return  code 0x%x vcp[%x] lana[%d] lsn[%d]",
1810                              code,vcp,vcp->lana,vcp->lsn);
1811                 }
1812                 else {
1813                     osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]",
1814                              rapOp, vcp, vcp->lana, vcp->lsn);
1815
1816                     code = CM_ERROR_BADOP;
1817                 }
1818             }
1819             break;
1820
1821         case 2:
1822             {                   /* Named pipe operation */
1823                 osi_Log2(smb_logp, "Named Pipe: %s with name [%S]",
1824                          myCrt_NmpipeDispatch(asp->pipeCommand),
1825                          osi_LogSaveClientString(smb_logp, asp->name));
1826
1827                 code = CM_ERROR_BADOP;
1828
1829                 switch (asp->pipeCommand) {
1830                 case SMB_TRANS_SET_NMPIPE_STATE:
1831                     code = smb_nmpipeSetState(vcp, asp, outp);
1832                     break;
1833
1834                 case SMB_TRANS_RAW_READ_NMPIPE:
1835                     break;
1836
1837                 case SMB_TRANS_QUERY_NMPIPE_STATE:
1838                     break;
1839
1840                 case SMB_TRANS_QUERY_NMPIPE_INFO:
1841                     break;
1842
1843                 case SMB_TRANS_PEEK_NMPIPE:
1844                     break;
1845
1846                 case SMB_TRANS_TRANSACT_NMPIPE:
1847                     code = smb_nmpipeTransact(vcp, asp, outp);
1848                     break;
1849
1850                 case SMB_TRANS_RAW_WRITE_NMPIPE:
1851                     break;
1852
1853                 case SMB_TRANS_READ_NMPIPE:
1854                     break;
1855
1856                 case SMB_TRANS_WRITE_NMPIPE:
1857                     break;
1858
1859                 case SMB_TRANS_WAIT_NMPIPE:
1860                     break;
1861
1862                 case SMB_TRANS_CALL_NMPIPE:
1863                     break;
1864                 }
1865             }
1866             break;
1867
1868         default:
1869             code = CM_ERROR_BADOP;
1870         }
1871
1872         /* if an error is returned, we're supposed to send an error packet,
1873          * otherwise the dispatched function already did the data sending.
1874          * We give dispatched proc the responsibility since it knows how much
1875          * space to allocate.
1876          */
1877         if (code != 0) {
1878             smb_SendTran2Error(vcp, asp, outp, code);
1879         }
1880
1881         /* free the input tran 2 packet */
1882         smb_FreeTran2Packet(asp);
1883     }
1884     else if (firstPacket) {
1885         /* the first packet in a multi-packet request, we need to send an
1886          * ack to get more data.
1887          */
1888         smb_SetSMBDataLength(outp, 0);
1889         smb_SendPacket(vcp, outp);
1890     }
1891
1892     return 0;
1893 }
1894
1895 /* ANSI versions. */
1896
1897 #pragma pack(push, 1)
1898
1899 typedef struct smb_rap_share_info_0 {
1900     BYTE                shi0_netname[13];
1901 } smb_rap_share_info_0_t;
1902
1903 typedef struct smb_rap_share_info_1 {
1904     BYTE                shi1_netname[13];
1905     BYTE                shi1_pad;
1906     WORD                        shi1_type;
1907     DWORD                       shi1_remark; /* char *shi1_remark; data offset */
1908 } smb_rap_share_info_1_t;
1909
1910 typedef struct smb_rap_share_info_2 {
1911     BYTE                shi2_netname[13];
1912     BYTE                shi2_pad;
1913     WORD                shi2_type;
1914     DWORD                       shi2_remark; /* char *shi2_remark; data offset */
1915     WORD                shi2_permissions;
1916     WORD                shi2_max_uses;
1917     WORD                shi2_current_uses;
1918     DWORD                       shi2_path;  /* char *shi2_path; data offset */
1919     WORD                shi2_passwd[9];
1920     WORD                shi2_pad2;
1921 } smb_rap_share_info_2_t;
1922
1923 #define SMB_RAP_MAX_SHARES 512
1924
1925 typedef struct smb_rap_share_list {
1926     int cShare;
1927     int maxShares;
1928     smb_rap_share_info_0_t * shares;
1929 } smb_rap_share_list_t;
1930
1931 #pragma pack(pop)
1932
1933 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1934     smb_rap_share_list_t * sp;
1935
1936     if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1937         return 0; /* skip over '.' and '..' */
1938
1939     sp = (smb_rap_share_list_t *) vrockp;
1940
1941     strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1942     sp->shares[sp->cShare].shi0_netname[12] = 0;
1943
1944     sp->cShare++;
1945
1946     if (sp->cShare >= sp->maxShares)
1947         return CM_ERROR_STOPNOW;
1948     else
1949         return 0;
1950 }
1951
1952 /* RAP NetShareEnumRequest */
1953 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1954 {
1955     smb_tran2Packet_t *outp;
1956     unsigned short * tp;
1957     int len;
1958     int infoLevel;
1959     int bufsize;
1960     int outParmsTotal;  /* total parameter bytes */
1961     int outDataTotal;   /* total data bytes */
1962     int code = 0;
1963     DWORD rv;
1964     DWORD allSubmount = 0;
1965     USHORT nShares = 0;
1966     DWORD nRegShares = 0;
1967     DWORD nSharesRet = 0;
1968     HKEY hkParam;
1969     HKEY hkSubmount = NULL;
1970     smb_rap_share_info_1_t * shares;
1971     USHORT cshare = 0;
1972     char * cstrp;
1973     clientchar_t thisShare[AFSPATHMAX];
1974     int i,j;
1975     DWORD dw;
1976     int nonrootShares;
1977     smb_rap_share_list_t rootShares;
1978     cm_req_t req;
1979     cm_user_t * userp;
1980     osi_hyper_t thyper;
1981     cm_scache_t *rootScp;
1982
1983     tp = p->parmsp + 1; /* skip over function number (always 0) */
1984
1985     {
1986         clientchar_t * cdescp;
1987
1988         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1989         if (cm_ClientStrCmp(cdescp,  _C("WrLeh")))
1990             return CM_ERROR_INVAL;
1991         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1992         if (cm_ClientStrCmp(cdescp,  _C("B13BWz")))
1993             return CM_ERROR_INVAL;
1994     }
1995
1996     infoLevel = tp[0];
1997     bufsize = tp[1];
1998
1999     if (infoLevel != 1) {
2000         return CM_ERROR_INVAL;
2001     }
2002
2003     /* We are supposed to use the same ASCII data structure even if
2004        Unicode is negotiated, which ultimately means that the share
2005        names that we return must be at most 13 characters in length,
2006        including the NULL terminator.
2007
2008        The RAP specification states that shares with names longer than
2009        12 characters should not be included in the enumeration.
2010        However, since we support prefix cell references and since many
2011        cell names are going to exceed 12 characters, we lie and send
2012        the first 12 characters.
2013     */
2014
2015     /* first figure out how many shares there are */
2016     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2017                       KEY_QUERY_VALUE, &hkParam);
2018     if (rv == ERROR_SUCCESS) {
2019         len = sizeof(allSubmount);
2020         rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2021                              (BYTE *) &allSubmount, &len);
2022         if (rv != ERROR_SUCCESS || allSubmount != 0) {
2023             allSubmount = 1;
2024         }
2025         RegCloseKey (hkParam);
2026     }
2027
2028     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
2029                       0, KEY_QUERY_VALUE, &hkSubmount);
2030     if (rv == ERROR_SUCCESS) {
2031         rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
2032                              NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
2033         if (rv != ERROR_SUCCESS)
2034             nRegShares = 0;
2035     } else {
2036         hkSubmount = NULL;
2037     }
2038
2039     /* fetch the root shares */
2040     rootShares.maxShares = SMB_RAP_MAX_SHARES;
2041     rootShares.cShare = 0;
2042     rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
2043
2044     smb_InitReq(&req);
2045
2046     userp = smb_GetTran2User(vcp,p);
2047
2048     thyper.HighPart = 0;
2049     thyper.LowPart = 0;
2050
2051     rootScp = cm_RootSCachep(userp, &req);
2052     cm_HoldSCache(rootScp);
2053     cm_ApplyDir(rootScp, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
2054     cm_ReleaseSCache(rootScp);
2055
2056     cm_ReleaseUser(userp);
2057
2058     nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
2059
2060 #define REMARK_LEN 1
2061     outParmsTotal = 8; /* 4 dwords */
2062     outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
2063     if(outDataTotal > bufsize) {
2064         nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
2065         outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
2066     }
2067     else {
2068         nSharesRet = nShares;
2069     }
2070
2071     outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
2072
2073     /* now for the submounts */
2074     shares = (smb_rap_share_info_1_t *) outp->datap;
2075     cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
2076
2077     memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
2078
2079     if (allSubmount) {
2080         StringCchCopyA(shares[cshare].shi1_netname,
2081                        lengthof(shares[cshare].shi1_netname), "all" );
2082         shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2083         /* type and pad are zero already */
2084         cshare++;
2085         cstrp+=REMARK_LEN;
2086     }
2087
2088     if (hkSubmount) {
2089         for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
2090             len = sizeof(thisShare);
2091             rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
2092             if (rv == ERROR_SUCCESS &&
2093                 cm_ClientStrLen(thisShare) &&
2094                 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
2095                 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
2096                                       lengthof( shares[cshare].shi1_netname ));
2097                 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
2098                 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2099                 cshare++;
2100                 cstrp+=REMARK_LEN;
2101             }
2102             else
2103                 nShares--; /* uncount key */
2104         }
2105
2106         RegCloseKey(hkSubmount);
2107     }
2108
2109     nonrootShares = cshare;
2110
2111     for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
2112         /* in case there are collisions with submounts, submounts have
2113            higher priority */
2114         for (j=0; j < nonrootShares; j++)
2115             if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
2116                 break;
2117
2118         if (j < nonrootShares) {
2119             nShares--; /* uncount */
2120             continue;
2121         }
2122
2123         StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
2124                        rootShares.shares[i].shi0_netname);
2125         shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
2126         cshare++;
2127         cstrp+=REMARK_LEN;
2128     }
2129
2130     outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
2131     outp->parmsp[1] = 0;
2132     outp->parmsp[2] = cshare;
2133     outp->parmsp[3] = nShares;
2134
2135     outp->totalData = (int)(cstrp - outp->datap);
2136     outp->totalParms = outParmsTotal;
2137
2138     smb_SendTran2Packet(vcp, outp, op);
2139     smb_FreeTran2Packet(outp);
2140
2141     free(rootShares.shares);
2142
2143     return code;
2144 }
2145
2146 /* RAP NetShareGetInfo */
2147 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2148 {
2149     smb_tran2Packet_t *outp;
2150     unsigned short * tp;
2151     clientchar_t * shareName;
2152     BOOL shareFound = FALSE;
2153     unsigned short infoLevel;
2154     unsigned short bufsize;
2155     int totalData;
2156     int totalParam;
2157     DWORD len;
2158     HKEY hkParam;
2159     HKEY hkSubmount;
2160     DWORD allSubmount;
2161     LONG rv;
2162     long code = 0;
2163     cm_scache_t *scp = NULL;
2164     cm_user_t   *userp;
2165     cm_req_t    req;
2166
2167     smb_InitReq(&req);
2168
2169     tp = p->parmsp + 1; /* skip over function number (always 1) */
2170
2171     {
2172         clientchar_t * cdescp;
2173
2174         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2175         if (cm_ClientStrCmp(cdescp,  _C("zWrLh")))
2176
2177             return CM_ERROR_INVAL;
2178
2179         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2180         if (cm_ClientStrCmp(cdescp,  _C("B13")) &&
2181             cm_ClientStrCmp(cdescp,  _C("B13BWz")) &&
2182             cm_ClientStrCmp(cdescp,  _C("B13BWzWWWzB9B")))
2183
2184             return CM_ERROR_INVAL;
2185     }
2186     shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
2187
2188     infoLevel = *tp++;
2189     bufsize = *tp++;
2190
2191     totalParam = 6;
2192
2193     if (infoLevel == 0)
2194         totalData = sizeof(smb_rap_share_info_0_t);
2195     else if(infoLevel == SMB_INFO_STANDARD)
2196         totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
2197     else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
2198         totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
2199     else
2200         return CM_ERROR_INVAL;
2201
2202     if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
2203         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
2204                           KEY_QUERY_VALUE, &hkParam);
2205         if (rv == ERROR_SUCCESS) {
2206             len = sizeof(allSubmount);
2207             rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
2208                                   (BYTE *) &allSubmount, &len);
2209             if (rv != ERROR_SUCCESS || allSubmount != 0) {
2210                 allSubmount = 1;
2211             }
2212             RegCloseKey (hkParam);
2213         }
2214
2215         if (allSubmount)
2216             shareFound = TRUE;
2217
2218     } else {
2219         userp = smb_GetTran2User(vcp, p);
2220         if (!userp) {
2221             osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
2222             return CM_ERROR_BADSMB;
2223         }
2224         code = cm_NameI(cm_RootSCachep(userp, &req), shareName,
2225                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
2226                          userp, NULL, &req, &scp);
2227         if (code == 0) {
2228             cm_ReleaseSCache(scp);
2229             shareFound = TRUE;
2230         } else {
2231             rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
2232                               KEY_QUERY_VALUE, &hkSubmount);
2233             if (rv == ERROR_SUCCESS) {
2234                 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
2235                 if (rv == ERROR_SUCCESS) {
2236                     shareFound = TRUE;
2237                 }
2238                 RegCloseKey(hkSubmount);
2239             }
2240         }
2241     }
2242
2243     if (!shareFound)
2244         return CM_ERROR_BADSHARENAME;
2245
2246     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
2247     memset(outp->datap, 0, totalData);
2248
2249     outp->parmsp[0] = 0;
2250     outp->parmsp[1] = 0;
2251     outp->parmsp[2] = totalData;
2252
2253     if (infoLevel == 0) {
2254         smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
2255         cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
2256                               lengthof(info->shi0_netname));
2257     } else if(infoLevel == SMB_INFO_STANDARD) {
2258         smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
2259         cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
2260         info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
2261         info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2262         /* type and pad are already zero */
2263     } else { /* infoLevel==2 */
2264         smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
2265         cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
2266         info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
2267         info->shi2_permissions = ACCESS_ALL;
2268         info->shi2_max_uses = (unsigned short) -1;
2269         info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
2270     }
2271
2272     outp->totalData = totalData;
2273     outp->totalParms = totalParam;
2274
2275     smb_SendTran2Packet(vcp, outp, op);
2276     smb_FreeTran2Packet(outp);
2277
2278     return code;
2279 }
2280
2281 #pragma pack(push, 1)
2282
2283 typedef struct smb_rap_wksta_info_10 {
2284     DWORD       wki10_computername;     /*char *wki10_computername;*/
2285     DWORD       wki10_username; /* char *wki10_username; */
2286     DWORD       wki10_langroup; /* char *wki10_langroup;*/
2287     BYTE        wki10_ver_major;
2288     BYTE        wki10_ver_minor;
2289     DWORD       wki10_logon_domain;     /*char *wki10_logon_domain;*/
2290     DWORD       wki10_oth_domains; /* char *wki10_oth_domains;*/
2291 } smb_rap_wksta_info_10_t;
2292
2293 #pragma pack(pop)
2294
2295 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2296 {
2297     smb_tran2Packet_t *outp;
2298     long code = 0;
2299     int infoLevel;
2300     int bufsize;
2301     unsigned short * tp;
2302     int totalData;
2303     int totalParams;
2304     smb_rap_wksta_info_10_t * info;
2305     char * cstrp;
2306     smb_user_t *uidp;
2307
2308     tp = p->parmsp + 1; /* Skip over function number */
2309
2310     {
2311         clientchar_t * cdescp;
2312
2313         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2314                                        SMB_STRF_FORCEASCII);
2315         if (cm_ClientStrCmp(cdescp,  _C("WrLh")))
2316             return CM_ERROR_INVAL;
2317
2318         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2319                                        SMB_STRF_FORCEASCII);
2320         if (cm_ClientStrCmp(cdescp,  _C("zzzBBzz")))
2321             return CM_ERROR_INVAL;
2322     }
2323
2324     infoLevel = *tp++;
2325     bufsize = *tp++;
2326
2327     if (infoLevel != 10) {
2328         return CM_ERROR_INVAL;
2329     }
2330
2331     totalParams = 6;
2332
2333     /* infolevel 10 */
2334     totalData = sizeof(*info) +         /* info */
2335         MAX_COMPUTERNAME_LENGTH +       /* wki10_computername */
2336         SMB_MAX_USERNAME_LENGTH +       /* wki10_username */
2337         MAX_COMPUTERNAME_LENGTH +       /* wki10_langroup */
2338         MAX_COMPUTERNAME_LENGTH +       /* wki10_logon_domain */
2339         1;                              /* wki10_oth_domains (null)*/
2340
2341     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2342
2343     memset(outp->parmsp,0,totalParams);
2344     memset(outp->datap,0,totalData);
2345
2346     info = (smb_rap_wksta_info_10_t *) outp->datap;
2347     cstrp = (char *) (info + 1);
2348
2349     info->wki10_computername = (DWORD) (cstrp - outp->datap);
2350     StringCbCopyA(cstrp, totalData, smb_localNamep);
2351     cstrp += strlen(cstrp) + 1;
2352
2353     info->wki10_username = (DWORD) (cstrp - outp->datap);
2354     uidp = smb_FindUID(vcp, p->uid, 0);
2355     if (uidp) {
2356         lock_ObtainMutex(&uidp->mx);
2357         if(uidp->unp && uidp->unp->name)
2358             cm_ClientStringToUtf8(uidp->unp->name, -1,
2359                                   cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2360         lock_ReleaseMutex(&uidp->mx);
2361         smb_ReleaseUID(uidp);
2362     }
2363     cstrp += strlen(cstrp) + 1;
2364
2365     info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2366     StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2367     cstrp += strlen(cstrp) + 1;
2368
2369     /* TODO: Not sure what values these should take, but these work */
2370     info->wki10_ver_major = 5;
2371     info->wki10_ver_minor = 1;
2372
2373     info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2374     cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2375                           cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2376     cstrp += strlen(cstrp) + 1;
2377
2378     info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2379     cstrp ++; /* no other domains */
2380
2381     outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2382     outp->parmsp[2] = outp->totalData;
2383     outp->totalParms = totalParams;
2384
2385     smb_SendTran2Packet(vcp,outp,op);
2386     smb_FreeTran2Packet(outp);
2387
2388     return code;
2389 }
2390
2391 #pragma pack(push, 1)
2392
2393 typedef struct smb_rap_server_info_0 {
2394     BYTE    sv0_name[16];
2395 } smb_rap_server_info_0_t;
2396
2397 typedef struct smb_rap_server_info_1 {
2398     BYTE            sv1_name[16];
2399     BYTE            sv1_version_major;
2400     BYTE            sv1_version_minor;
2401     DWORD           sv1_type;
2402     DWORD           sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2403 } smb_rap_server_info_1_t;
2404
2405 #pragma pack(pop)
2406
2407 char smb_ServerComment[] = "OpenAFS Client";
2408 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2409
2410 #define SMB_SV_TYPE_SERVER              0x00000002L
2411 #define SMB_SV_TYPE_NT              0x00001000L
2412 #define SMB_SV_TYPE_SERVER_NT       0x00008000L
2413
2414 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2415 {
2416     smb_tran2Packet_t *outp;
2417     long code = 0;
2418     int infoLevel;
2419     int bufsize;
2420     unsigned short * tp;
2421     int totalData;
2422     int totalParams;
2423     smb_rap_server_info_0_t * info0;
2424     smb_rap_server_info_1_t * info1;
2425     char * cstrp;
2426
2427     tp = p->parmsp + 1; /* Skip over function number */
2428
2429     {
2430         clientchar_t * cdescp;
2431
2432         cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2433                                        SMB_STRF_FORCEASCII);
2434         if (cm_ClientStrCmp(cdescp,  _C("WrLh")))
2435             return CM_ERROR_INVAL;
2436         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2437                                        SMB_STRF_FORCEASCII);
2438         if (cm_ClientStrCmp(cdescp,  _C("B16")) ||
2439             cm_ClientStrCmp(cdescp,  _C("B16BBDz")))
2440             return CM_ERROR_INVAL;
2441     }
2442
2443     infoLevel = *tp++;
2444     bufsize = *tp++;
2445
2446     if (infoLevel != 0 && infoLevel != 1) {
2447         return CM_ERROR_INVAL;
2448     }
2449
2450     totalParams = 6;
2451
2452     totalData =
2453         (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2454         : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2455
2456     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2457
2458     memset(outp->parmsp,0,totalParams);
2459     memset(outp->datap,0,totalData);
2460
2461     if (infoLevel == 0) {
2462         info0 = (smb_rap_server_info_0_t *) outp->datap;
2463         cstrp = (char *) (info0 + 1);
2464         StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2465     } else { /* infoLevel == SMB_INFO_STANDARD */
2466         info1 = (smb_rap_server_info_1_t *) outp->datap;
2467         cstrp = (char *) (info1 + 1);
2468         StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2469
2470         info1->sv1_type =
2471             SMB_SV_TYPE_SERVER |
2472             SMB_SV_TYPE_NT |
2473             SMB_SV_TYPE_SERVER_NT;
2474
2475         info1->sv1_version_major = 5;
2476         info1->sv1_version_minor = 1;
2477         info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2478
2479         StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2480
2481         cstrp += smb_ServerCommentLen / sizeof(char);
2482     }
2483
2484     totalData = (DWORD)(cstrp - outp->datap);
2485     outp->totalData = min(bufsize,totalData); /* actual data size */
2486     outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2487     outp->parmsp[2] = totalData;
2488     outp->totalParms = totalParams;
2489
2490     smb_SendTran2Packet(vcp,outp,op);
2491     smb_FreeTran2Packet(outp);
2492
2493     return code;
2494 }
2495
2496 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2497 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2498 {
2499     smb_tran2Packet_t *asp;
2500     int totalParms;
2501     int totalData;
2502     int parmDisp;
2503     int dataDisp;
2504     int parmOffset;
2505     int dataOffset;
2506     int parmCount;
2507     int dataCount;
2508     int firstPacket;
2509     long code = 0;
2510     DWORD oldTime, newTime;
2511
2512     /* We sometimes see 0 word count.  What to do? */
2513     if (*inp->wctp == 0) {
2514         osi_Log0(smb_logp, "Transaction2 word count = 0");
2515         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2516
2517         smb_SetSMBDataLength(outp, 0);
2518         smb_SendPacket(vcp, outp);
2519         return 0;
2520     }
2521
2522     totalParms = smb_GetSMBParm(inp, 0);
2523     totalData = smb_GetSMBParm(inp, 1);
2524
2525     firstPacket = (inp->inCom == 0x32);
2526
2527     /* find the packet we're reassembling */
2528     lock_ObtainWrite(&smb_globalLock);
2529     asp = smb_FindTran2Packet(vcp, inp);
2530     if (!asp) {
2531         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2532     }
2533     lock_ReleaseWrite(&smb_globalLock);
2534
2535     /* now merge in this latest packet; start by looking up offsets */
2536     if (firstPacket) {
2537         parmDisp = dataDisp = 0;
2538         parmOffset = smb_GetSMBParm(inp, 10);
2539         dataOffset = smb_GetSMBParm(inp, 12);
2540         parmCount = smb_GetSMBParm(inp, 9);
2541         dataCount = smb_GetSMBParm(inp, 11);
2542         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2543         asp->maxReturnData = smb_GetSMBParm(inp, 3);
2544
2545         osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2546                  totalData, dataCount, asp->maxReturnData);
2547     }
2548     else {
2549         parmDisp = smb_GetSMBParm(inp, 4);
2550         parmOffset = smb_GetSMBParm(inp, 3);
2551         dataDisp = smb_GetSMBParm(inp, 7);
2552         dataOffset = smb_GetSMBParm(inp, 6);
2553         parmCount = smb_GetSMBParm(inp, 2);
2554         dataCount = smb_GetSMBParm(inp, 5);
2555
2556         osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2557                  parmCount, dataCount);
2558     }
2559
2560     /* now copy the parms and data */
2561     if ( asp->totalParms > 0 && parmCount != 0 )
2562     {
2563         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2564     }
2565     if ( asp->totalData > 0 && dataCount != 0 ) {
2566         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2567     }
2568
2569     /* account for new bytes */
2570     asp->curData += dataCount;
2571     asp->curParms += parmCount;
2572
2573     /* finally, if we're done, remove the packet from the queue and dispatch it */
2574     if (asp->totalParms > 0 &&
2575         asp->curParms > 0 &&
2576         asp->totalData <= asp->curData &&
2577         asp->totalParms <= asp->curParms) {
2578         /* we've received it all */
2579         lock_ObtainWrite(&smb_globalLock);
2580         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2581         lock_ReleaseWrite(&smb_globalLock);
2582
2583         oldTime = GetTickCount();
2584
2585         /* now dispatch it */
2586         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2587             osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2588             code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2589         }
2590         else {
2591             osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2592             code = CM_ERROR_BADOP;
2593         }
2594
2595         /* if an error is returned, we're supposed to send an error packet,
2596          * otherwise the dispatched function already did the data sending.
2597          * We give dispatched proc the responsibility since it knows how much
2598          * space to allocate.
2599          */
2600         if (code != 0) {
2601             smb_SendTran2Error(vcp, asp, outp, code);
2602         }
2603
2604         newTime = GetTickCount();
2605         if (newTime - oldTime > 45000) {
2606             smb_user_t *uidp;
2607             smb_fid_t *fidp;
2608             clientchar_t *treepath = NULL;  /* do not free */
2609             clientchar_t *pathname = NULL;
2610             cm_fid_t afid = {0,0,0,0,0};
2611
2612             uidp = smb_FindUID(vcp, asp->uid, 0);
2613             smb_LookupTIDPath(vcp, asp->tid, &treepath);
2614             fidp = smb_FindFID(vcp, inp->fid, 0);
2615
2616             if (fidp) {
2617                 lock_ObtainMutex(&fidp->mx);
2618                 if (fidp->NTopen_pathp)
2619                     pathname = fidp->NTopen_pathp;
2620                 if (fidp->scp)
2621                     afid = fidp->scp->fid;
2622             } else {
2623                 if (inp->stringsp->wdata)
2624                     pathname = inp->stringsp->wdata;
2625             }
2626
2627             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)",
2628                       myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2629                       asp->uid, uidp ? uidp->unp->name : NULL,
2630                       asp->pid, asp->mid, asp->tid,
2631                       treepath,
2632                       pathname,
2633                       afid.cell, afid.volume, afid.vnode, afid.unique);
2634
2635             if (fidp)
2636                 lock_ReleaseMutex(&fidp->mx);
2637
2638             if (uidp)
2639                 smb_ReleaseUID(uidp);
2640             if (fidp)
2641                 smb_ReleaseFID(fidp);
2642         }
2643
2644         /* free the input tran 2 packet */
2645         smb_FreeTran2Packet(asp);
2646     }
2647     else if (firstPacket) {
2648         /* the first packet in a multi-packet request, we need to send an
2649          * ack to get more data.
2650          */
2651         smb_SetSMBDataLength(outp, 0);
2652         smb_SendPacket(vcp, outp);
2653     }
2654
2655     return 0;
2656 }
2657
2658 /* TRANS2_OPEN2 */
2659 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2660 {
2661     clientchar_t *pathp;
2662     smb_tran2Packet_t *outp;
2663     long code = 0;
2664     cm_space_t *spacep;
2665     int excl;
2666     cm_user_t *userp;
2667     cm_scache_t *dscp;          /* dir we're dealing with */
2668     cm_scache_t *scp;           /* file we're creating */
2669     cm_attr_t setAttr;
2670     smb_fid_t *fidp;
2671     int attributes;
2672     clientchar_t *lastNamep;
2673     afs_uint32 dosTime;
2674     int openFun;
2675     int trunc;
2676     int openMode;
2677     int extraInfo;
2678     int openAction;
2679     int parmSlot;                       /* which parm we're dealing with */
2680     long returnEALength;
2681     clientchar_t *tidPathp;
2682     cm_req_t req;
2683     int created = 0;
2684     BOOL is_rpc = FALSE;
2685     BOOL is_ipc = FALSE;
2686
2687     smb_InitReq(&req);
2688
2689     scp = NULL;
2690
2691     extraInfo = (p->parmsp[0] & 1);     /* return extra info */
2692     returnEALength = (p->parmsp[0] & 8);        /* return extended attr length */
2693
2694     openFun = p->parmsp[6];             /* open function */
2695     excl = ((openFun & 3) == 0);
2696     trunc = ((openFun & 3) == 2);       /* truncate it */
2697     openMode = (p->parmsp[1] & 0x7);
2698     openAction = 0;                     /* tracks what we did */
2699
2700     attributes = p->parmsp[3];
2701     dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2702
2703     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2704                                   SMB_STRF_ANSIPATH);
2705
2706     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2707
2708     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2709     if (code == CM_ERROR_TIDIPC) {
2710         is_ipc = TRUE;
2711         osi_Log0(smb_logp, "Tran2Open received IPC TID");
2712     }
2713
2714     spacep = cm_GetSpace();
2715     /* smb_StripLastComponent will strip "::$DATA" if present */
2716     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2717
2718     if (lastNamep &&
2719
2720         /* special case magic file name for receiving IOCTL requests
2721          * (since IOCTL calls themselves aren't getting through).
2722          */
2723         (cm_ClientStrCmpI(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
2724
2725          /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional)*/
2726          (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
2727
2728         unsigned short file_type = 0;
2729         unsigned short device_state = 0;
2730
2731         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2732
2733         if (is_rpc) {
2734             code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2735             osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2736                      fidp->fid, code);
2737             if (code) {
2738                 smb_ReleaseFID(fidp);
2739                 smb_FreeTran2Packet(outp);
2740                 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
2741                 return code;
2742             }
2743         } else {
2744             smb_SetupIoctlFid(fidp, spacep);
2745             osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2746         }
2747
2748         /* copy out remainder of the parms */
2749         parmSlot = 0;
2750         outp->parmsp[parmSlot++] = fidp->fid;
2751         if (extraInfo) {
2752             outp->parmsp[parmSlot++] = 0;       /* attrs */
2753             outp->parmsp[parmSlot++] = 0;       /* mod time */
2754             outp->parmsp[parmSlot++] = 0;
2755             outp->parmsp[parmSlot++] = 0;       /* len */
2756             outp->parmsp[parmSlot++] = 0x7fff;
2757             outp->parmsp[parmSlot++] = openMode;
2758             outp->parmsp[parmSlot++] = file_type;
2759             outp->parmsp[parmSlot++] = device_state;
2760         }
2761         /* and the final "always present" stuff */
2762         outp->parmsp[parmSlot++] = 1;           /* openAction found existing file */
2763         /* next write out the "unique" ID */
2764         outp->parmsp[parmSlot++] = 0x1234;
2765         outp->parmsp[parmSlot++] = 0x5678;
2766         outp->parmsp[parmSlot++] = 0;
2767         if (returnEALength) {
2768             outp->parmsp[parmSlot++] = 0;
2769             outp->parmsp[parmSlot++] = 0;
2770         }
2771
2772         outp->totalData = 0;
2773         outp->totalParms = parmSlot * 2;
2774
2775         smb_SendTran2Packet(vcp, outp, op);
2776
2777         smb_FreeTran2Packet(outp);
2778
2779         /* and clean up fid reference */
2780         smb_ReleaseFID(fidp);
2781         return 0;
2782     }
2783
2784 #ifndef DFS_SUPPORT
2785     if (is_ipc) {
2786         osi_Log1(smb_logp, "Tran2Open rejecting IPC TID vcp %p", vcp);
2787         smb_FreeTran2Packet(outp);
2788         return CM_ERROR_BADFD;
2789     }
2790 #endif
2791
2792     if (!cm_IsValidClientString(pathp)) {
2793 #ifdef DEBUG
2794         clientchar_t * hexp;
2795
2796         hexp = cm_GetRawCharsAlloc(pathp, -1);
2797         osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2798                  osi_LogSaveClientString(smb_logp, hexp));
2799         if (hexp)
2800             free(hexp);
2801 #else
2802         osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2803 #endif
2804         smb_FreeTran2Packet(outp);
2805         return CM_ERROR_BADNTFILENAME;
2806     }
2807
2808 #ifdef DEBUG_VERBOSE
2809     {
2810         char *hexp, *asciip;
2811         asciip = (lastNamep ? lastNamep : pathp);
2812         hexp = osi_HexifyString( asciip );
2813         DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2814         free(hexp);
2815     }
2816 #endif
2817
2818     userp = smb_GetTran2User(vcp, p);
2819     /* In the off chance that userp is NULL, we log and abandon */
2820     if (!userp) {
2821         osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2822         smb_FreeTran2Packet(outp);
2823         return CM_ERROR_BADSMB;
2824     }
2825
2826     dscp = NULL;
2827     code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
2828                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2829                      userp, tidPathp, &req, &scp);
2830     if (code != 0) {
2831         if (code == CM_ERROR_NOSUCHFILE ||
2832             code == CM_ERROR_NOSUCHPATH ||
2833             code == CM_ERROR_BPLUS_NOMATCH)
2834             code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
2835                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2836                             userp, tidPathp, &req, &dscp);
2837         cm_FreeSpace(spacep);
2838
2839         if (code) {
2840             cm_ReleaseUser(userp);
2841             smb_FreeTran2Packet(outp);
2842             return code;
2843         }
2844
2845 #ifdef DFS_SUPPORT
2846         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2847             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2848                                                       (clientchar_t*) spacep->data);
2849             cm_ReleaseSCache(dscp);
2850             cm_ReleaseUser(userp);
2851             smb_FreeTran2Packet(outp);
2852             if ( WANTS_DFS_PATHNAMES(p) || pnc )
2853                 return CM_ERROR_PATH_NOT_COVERED;
2854             else
2855                 return CM_ERROR_NOSUCHPATH;
2856         }
2857 #endif /* DFS_SUPPORT */
2858
2859         /* otherwise, scp points to the parent directory.  Do a lookup,
2860          * and truncate the file if we find it, otherwise we create the
2861          * file.
2862          */
2863         if (!lastNamep)
2864             lastNamep = pathp;
2865         else
2866             lastNamep++;
2867         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2868                          &req, &scp);
2869         if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2870             cm_ReleaseSCache(dscp);
2871             cm_ReleaseUser(userp);
2872             smb_FreeTran2Packet(outp);
2873             return code;
2874         }
2875     } else {
2876         /* macintosh is expensive to program for it */
2877         cm_FreeSpace(spacep);
2878
2879 #ifdef DFS_SUPPORT
2880         if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2881             int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2882             cm_ReleaseSCache(scp);
2883             cm_ReleaseUser(userp);
2884             smb_FreeTran2Packet(outp);
2885             if ( WANTS_DFS_PATHNAMES(p) || pnc )
2886                 return CM_ERROR_PATH_NOT_COVERED;
2887             else
2888                 return CM_ERROR_NOSUCHPATH;
2889         }
2890 #endif /* DFS_SUPPORT */
2891     }
2892
2893     /* if we get here, if code is 0, the file exists and is represented by
2894      * scp.  Otherwise, we have to create it.
2895      */
2896     if (code == 0) {
2897         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2898         if (code) {
2899             if (dscp)
2900                 cm_ReleaseSCache(dscp);
2901             cm_ReleaseSCache(scp);
2902             cm_ReleaseUser(userp);
2903             smb_FreeTran2Packet(outp);
2904             return code;
2905         }
2906
2907         if (excl) {
2908             /* oops, file shouldn't be there */
2909             if (dscp)
2910                 cm_ReleaseSCache(dscp);
2911             cm_ReleaseSCache(scp);
2912             cm_ReleaseUser(userp);
2913             smb_FreeTran2Packet(outp);
2914             return CM_ERROR_EXISTS;
2915         }
2916
2917         if (trunc) {
2918             setAttr.mask = CM_ATTRMASK_LENGTH;
2919             setAttr.length.LowPart = 0;
2920             setAttr.length.HighPart = 0;
2921             code = cm_SetAttr(scp, &setAttr, userp, &req);
2922             openAction = 3;     /* truncated existing file */
2923         }
2924         else
2925             openAction = 1;     /* found existing file */
2926     }
2927     else if (!(openFun & 0x10)) {
2928         /* don't create if not found */
2929         if (dscp)
2930             cm_ReleaseSCache(dscp);
2931         osi_assertx(scp == NULL, "null cm_scache_t");
2932         cm_ReleaseUser(userp);
2933         smb_FreeTran2Packet(outp);
2934         return CM_ERROR_NOSUCHFILE;
2935     }
2936     else {
2937         osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2938         openAction = 2; /* created file */
2939         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2940         cm_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2941         smb_SetInitialModeBitsForFile(attributes, &setAttr);
2942
2943         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2944                           &req);
2945         if (code == 0) {
2946             created = 1;
2947             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2948                 smb_NotifyChange(FILE_ACTION_ADDED,
2949                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
2950                                   dscp, lastNamep, NULL, TRUE);
2951         } else if (!excl && code == CM_ERROR_EXISTS) {
2952             /* not an exclusive create, and someone else tried
2953              * creating it already, then we open it anyway.  We
2954              * don't bother retrying after this, since if this next
2955              * fails, that means that the file was deleted after we
2956              * started this call.
2957              */
2958             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2959                               userp, &req, &scp);
2960             if (code == 0) {
2961                 if (trunc) {
2962                     setAttr.mask = CM_ATTRMASK_LENGTH;
2963                     setAttr.length.LowPart = 0;
2964                     setAttr.length.HighPart = 0;
2965                     code = cm_SetAttr(scp, &setAttr, userp,
2966                                        &req);
2967                 }
2968             }   /* lookup succeeded */
2969         }
2970     }
2971
2972     /* we don't need this any longer */
2973     if (dscp)
2974         cm_ReleaseSCache(dscp);
2975
2976     if (code) {
2977         /* something went wrong creating or truncating the file */
2978         if (scp)
2979             cm_ReleaseSCache(scp);
2980         cm_ReleaseUser(userp);
2981         smb_FreeTran2Packet(outp);
2982         return code;
2983     }
2984
2985     /* make sure we're about to open a file */
2986     if (scp->fileType != CM_SCACHETYPE_FILE) {
2987         code = 0;
2988         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2989             cm_scache_t * targetScp = 0;
2990             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2991             if (code == 0) {
2992                 /* we have a more accurate file to use (the
2993                  * target of the symbolic link).  Otherwise,
2994                  * we'll just use the symlink anyway.
2995                  */
2996                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2997                           scp, targetScp);
2998                 cm_ReleaseSCache(scp);
2999                 scp = targetScp;
3000             }
3001         }
3002         if (scp->fileType != CM_SCACHETYPE_FILE) {
3003             cm_ReleaseSCache(scp);
3004             cm_ReleaseUser(userp);
3005             smb_FreeTran2Packet(outp);
3006             return CM_ERROR_ISDIR;
3007         }
3008     }
3009
3010     /* now all we have to do is open the file itself */
3011     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3012     osi_assertx(fidp, "null smb_fid_t");
3013
3014     cm_HoldUser(userp);
3015     lock_ObtainMutex(&fidp->mx);
3016     /* save a pointer to the vnode */
3017     osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
3018     fidp->scp = scp;
3019     lock_ObtainWrite(&scp->rw);
3020     scp->flags |= CM_SCACHEFLAG_SMB_FID;
3021     lock_ReleaseWrite(&scp->rw);
3022
3023     /* and the user */
3024     fidp->userp = userp;
3025
3026     /* compute open mode */
3027     if (openMode != 1)
3028         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
3029     if (openMode == 1 || openMode == 2)
3030         fidp->flags |= SMB_FID_OPENWRITE;
3031
3032     /* remember that the file was newly created */
3033     if (created)
3034         fidp->flags |= SMB_FID_CREATED;
3035
3036     lock_ReleaseMutex(&fidp->mx);
3037
3038     smb_ReleaseFID(fidp);
3039
3040     cm_Open(scp, 0, userp);
3041
3042     /* copy out remainder of the parms */
3043     parmSlot = 0;
3044     outp->parmsp[parmSlot++] = fidp->fid;
3045     lock_ObtainRead(&scp->rw);
3046     if (extraInfo) {
3047         outp->parmsp[parmSlot++] = smb_Attributes(scp);
3048         cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3049         outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
3050         outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
3051         outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
3052         outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
3053         outp->parmsp[parmSlot++] = openMode;
3054         outp->parmsp[parmSlot++] = 0;   /* file type 0 ==> normal file or dir */
3055         outp->parmsp[parmSlot++] = 0;   /* IPC junk */
3056     }
3057     /* and the final "always present" stuff */
3058     outp->parmsp[parmSlot++] = openAction;
3059     /* next write out the "unique" ID */
3060     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff);
3061     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff);
3062     outp->parmsp[parmSlot++] = 0;
3063     if (returnEALength) {
3064         outp->parmsp[parmSlot++] = 0;
3065         outp->parmsp[parmSlot++] = 0;
3066     }
3067     lock_ReleaseRead(&scp->rw);
3068     outp->totalData = 0;                /* total # of data bytes */
3069     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
3070
3071     smb_SendTran2Packet(vcp, outp, op);
3072
3073     smb_FreeTran2Packet(outp);
3074
3075     cm_ReleaseUser(userp);
3076     /* leave scp held since we put it in fidp->scp */
3077     return 0;
3078 }
3079
3080 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3081 {
3082     unsigned short fid;
3083     unsigned short infolevel;
3084
3085     infolevel = p->parmsp[0];
3086     fid = p->parmsp[1];
3087     osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
3088
3089     return CM_ERROR_BAD_LEVEL;
3090 }
3091
3092 /* TRANS2_QUERY_FS_INFORMATION */
3093 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3094 {
3095     smb_tran2Packet_t *outp;
3096     smb_tran2QFSInfo_t qi;
3097     int responseSize;
3098     size_t sz = 0;
3099
3100     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
3101
3102     switch (p->parmsp[0]) {
3103     case SMB_INFO_ALLOCATION:
3104         /* alloc info */
3105         responseSize = sizeof(qi.u.allocInfo);
3106
3107         qi.u.allocInfo.FSID = 0;
3108         qi.u.allocInfo.sectorsPerAllocUnit = 1;
3109         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
3110         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
3111         qi.u.allocInfo.bytesPerSector = 1024;
3112         break;
3113
3114     case SMB_INFO_VOLUME:
3115         /* volume info */
3116         qi.u.volumeInfo.vsn = 1234;  /* Volume serial number */
3117         qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
3118
3119         /* we're supposed to pad it out with zeroes to the end */
3120         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
3121         smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
3122
3123         responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
3124         break;
3125
3126     case SMB_QUERY_FS_VOLUME_INFO:
3127         /* FS volume info */
3128         responseSize = sizeof(qi.u.FSvolumeInfo);
3129
3130         {
3131             FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
3132             memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
3133         }
3134
3135         qi.u.FSvolumeInfo.vsn = 1234;
3136         qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
3137         memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
3138         memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
3139         break;
3140
3141     case SMB_QUERY_FS_SIZE_INFO:
3142         /* FS size info */
3143         responseSize = sizeof(qi.u.FSsizeInfo);
3144
3145         qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
3146         qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
3147         qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
3148         qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
3149         qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
3150         qi.u.FSsizeInfo.bytesPerSector = 1024;
3151         break;
3152
3153     case SMB_QUERY_FS_DEVICE_INFO:
3154         /* FS device info */
3155         responseSize = sizeof(qi.u.FSdeviceInfo);
3156
3157         qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
3158         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
3159         break;
3160
3161     case SMB_QUERY_FS_ATTRIBUTE_INFO:
3162         /* FS attribute info */
3163
3164         /* attributes, defined in WINNT.H:
3165          *      FILE_CASE_SENSITIVE_SEARCH      0x1
3166          *      FILE_CASE_PRESERVED_NAMES       0x2
3167          *      FILE_UNICODE_ON_DISK            0x4
3168          *      FILE_VOLUME_QUOTAS              0x10
3169          *      <no name defined>               0x4000
3170          *         If bit 0x4000 is not set, Windows 95 thinks
3171          *         we can't handle long (non-8.3) names,
3172          *         despite our protestations to the contrary.
3173          */
3174         qi.u.FSattributeInfo.attributes = 0x4003;
3175         /* The maxCompLength is supposed to be in bytes */
3176 #ifdef SMB_UNICODE
3177         qi.u.FSattributeInfo.attributes |= 0x04;
3178 #endif
3179         qi.u.FSattributeInfo.maxCompLength = 255;
3180         smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
3181         qi.u.FSattributeInfo.FSnameLength = sz;
3182
3183         responseSize =
3184             sizeof(qi.u.FSattributeInfo.attributes) +
3185             sizeof(qi.u.FSattributeInfo.maxCompLength) +
3186             sizeof(qi.u.FSattributeInfo.FSnameLength) +
3187             sz;
3188
3189         break;
3190
3191     case SMB_INFO_UNIX:         /* CIFS Unix Info */
3192     case SMB_INFO_MACOS:        /* Mac FS Info */
3193     default:
3194         return CM_ERROR_BADOP;
3195     }
3196
3197     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
3198
3199     /* copy out return data, and set corresponding sizes */
3200     outp->totalParms = 0;
3201     outp->totalData = responseSize;
3202     memcpy(outp->datap, &qi, responseSize);
3203
3204     /* send and free the packets */
3205     smb_SendTran2Packet(vcp, outp, op);
3206     smb_FreeTran2Packet(outp);
3207
3208     return 0;
3209 }
3210
3211 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3212 {
3213     osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3214     return CM_ERROR_BADOP;
3215 }
3216
3217 struct smb_ShortNameRock {
3218     clientchar_t *maskp;
3219     unsigned int vnode;
3220     clientchar_t *shortName;
3221     size_t shortNameLen;
3222 };
3223
3224 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3225                          osi_hyper_t *offp)
3226 {
3227     struct smb_ShortNameRock *rockp;
3228     normchar_t normName[MAX_PATH];
3229     clientchar_t *shortNameEnd;
3230
3231     rockp = vrockp;
3232
3233     if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3234         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3235                  osi_LogSaveString(smb_logp, dep->name));
3236         return 0;
3237     }
3238
3239     /* compare both names and vnodes, though probably just comparing vnodes
3240      * would be safe enough.
3241      */
3242     if (cm_NormStrCmpI(normName,  rockp->maskp) != 0)
3243         return 0;
3244     if (ntohl(dep->fid.vnode) != rockp->vnode)
3245         return 0;
3246
3247     /* This is the entry */
3248     cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3249     rockp->shortNameLen = shortNameEnd - rockp->shortName;
3250
3251     return CM_ERROR_STOPNOW;
3252 }
3253
3254 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3255         clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3256 {
3257     struct smb_ShortNameRock rock;
3258     clientchar_t *lastNamep;
3259     cm_space_t *spacep;
3260     cm_scache_t *dscp;
3261     int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3262     long code = 0;
3263     osi_hyper_t thyper;
3264
3265     spacep = cm_GetSpace();
3266     /* smb_StripLastComponent will strip "::$DATA" if present */
3267     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3268
3269     code = cm_NameI(cm_RootSCachep(userp, reqp), spacep->wdata,
3270                     caseFold, userp, tidPathp,
3271                     reqp, &dscp);
3272     cm_FreeSpace(spacep);
3273     if (code)
3274         return code;
3275
3276 #ifdef DFS_SUPPORT
3277     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3278         cm_ReleaseSCache(dscp);
3279         cm_ReleaseUser(userp);
3280 #ifdef DEBUG
3281         DebugBreak();
3282 #endif
3283         return CM_ERROR_PATH_NOT_COVERED;
3284     }
3285 #endif /* DFS_SUPPORT */
3286
3287     if (!lastNamep) lastNamep = pathp;
3288     else lastNamep++;
3289     thyper.LowPart = 0;
3290     thyper.HighPart = 0;
3291     rock.shortName = shortName;
3292     rock.vnode = vnode;
3293     rock.maskp = lastNamep;
3294     code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3295
3296     cm_ReleaseSCache(dscp);
3297
3298     if (code == 0)
3299         return CM_ERROR_NOSUCHFILE;
3300     if (code == CM_ERROR_STOPNOW) {
3301         *shortNameLenp = rock.shortNameLen;
3302         return 0;
3303     }
3304     return code;
3305 }
3306
3307 /* TRANS2_QUERY_PATH_INFORMATION */
3308 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3309 {
3310     smb_tran2Packet_t *outp;
3311     afs_uint32 dosTime;
3312     FILETIME ft;
3313     unsigned short infoLevel;
3314     smb_tran2QPathInfo_t qpi;
3315     int responseSize;
3316     unsigned short attributes;
3317     unsigned long extAttributes;
3318     clientchar_t shortName[13];
3319     size_t len;
3320     cm_user_t *userp;
3321     cm_space_t *spacep;
3322     cm_scache_t *scp, *dscp;
3323     int scp_rw_held = 0;
3324     int delonclose = 0;
3325     long code = 0;
3326     clientchar_t *pathp;
3327     clientchar_t *tidPathp;
3328     clientchar_t *lastComp;
3329     cm_req_t req;
3330
3331     smb_InitReq(&req);
3332
3333     infoLevel = p->parmsp[0];
3334     if (infoLevel == SMB_INFO_IS_NAME_VALID)
3335         responseSize = 0;
3336     else if (infoLevel == SMB_INFO_STANDARD)
3337         responseSize = sizeof(qpi.u.QPstandardInfo);
3338     else if (infoLevel == SMB_INFO_QUERY_EA_SIZE)
3339         responseSize = sizeof(qpi.u.QPeaSizeInfo);
3340     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3341         responseSize = sizeof(qpi.u.QPfileBasicInfo);
3342     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3343         responseSize = sizeof(qpi.u.QPfileStandardInfo);
3344     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3345         responseSize = sizeof(qpi.u.QPfileEaInfo);
3346     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3347         responseSize = sizeof(qpi.u.QPfileNameInfo);
3348     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO)
3349         responseSize = sizeof(qpi.u.QPfileAllInfo);
3350     else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO)
3351         responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3352     else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3353         responseSize = sizeof(qpi.u.QPfileStreamInfo);
3354     else {
3355         osi_Log2(smb_logp, "Bad Tran2QPathInfo op 0x%x infolevel 0x%x",
3356                   p->opcode, infoLevel);
3357         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3358         return 0;
3359     }
3360     memset(&qpi, 0, sizeof(qpi));
3361
3362     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3363     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path \"%S\"", infoLevel,
3364               osi_LogSaveClientString(smb_logp, pathp));
3365
3366     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3367
3368     if (infoLevel > 0x100)
3369         outp->totalParms = 2;
3370     else
3371         outp->totalParms = 0;
3372
3373     /* now, if we're at infoLevel 6, we're only being asked to check
3374      * the syntax, so we just OK things now.  In particular, we're *not*
3375      * being asked to verify anything about the state of any parent dirs.
3376      */
3377     if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3378         smb_SendTran2Packet(vcp, outp, opx);
3379         smb_FreeTran2Packet(outp);
3380         return 0;
3381     }
3382
3383     userp = smb_GetTran2User(vcp, p);
3384     if (!userp) {
3385         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3386         smb_FreeTran2Packet(outp);
3387         return CM_ERROR_BADSMB;
3388     }
3389
3390     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3391     if(code) {
3392         osi_Log1(smb_logp, "ReceiveTran2QPathInfo tid path lookup failure 0x%x", code);
3393         cm_ReleaseUser(userp);
3394         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3395         smb_FreeTran2Packet(outp);
3396         return 0;
3397     }
3398
3399     osi_Log1(smb_logp, "T2 QPathInfo tidPathp \"%S\"",
3400               osi_LogSaveClientString(smb_logp, tidPathp));
3401
3402     /*
3403      * XXX Strange hack XXX
3404      *
3405      * As of Patch 7 (13 January 98), we are having the following problem:
3406      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3407      * requests to look up "desktop.ini" in all the subdirectories.
3408      * This can cause zillions of timeouts looking up non-existent cells
3409      * and volumes, especially in the top-level directory.
3410      *
3411      * We have not found any way to avoid this or work around it except
3412      * to explicitly ignore the requests for mount points that haven't
3413      * yet been evaluated and for directories that haven't yet been
3414      * fetched.
3415      */
3416     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3417         spacep = cm_GetSpace();
3418         /* smb_StripLastComponent will strip "::$DATA" if present */
3419         smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3420 #ifndef SPECIAL_FOLDERS
3421         /* Make sure that lastComp is not NULL */
3422         if (lastComp) {
3423             if (cm_ClientStrCmpIA(lastComp,  _C("\\desktop.ini")) == 0) {
3424                 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3425                                  CM_FLAG_CASEFOLD
3426                                  | CM_FLAG_DIRSEARCH
3427                                  | CM_FLAG_FOLLOW,
3428                                  userp, tidPathp, &req, &dscp);
3429                 if (code == 0) {
3430 #ifdef DFS_SUPPORT
3431                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3432                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3433                                                                   spacep->wdata);
3434                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3435                             code = CM_ERROR_PATH_NOT_COVERED;
3436                         else
3437                             code = CM_ERROR_NOSUCHPATH;
3438                     } else
3439 #endif /* DFS_SUPPORT */
3440                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3441                         code = CM_ERROR_NOSUCHFILE;
3442                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3443                         cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
3444                         if (bp) {
3445                             buf_Release(bp);
3446                             bp = NULL;
3447                         }
3448                         else
3449                             code = CM_ERROR_NOSUCHFILE;
3450                     }
3451                     cm_ReleaseSCache(dscp);
3452                     if (code) {
3453                         cm_FreeSpace(spacep);
3454                         cm_ReleaseUser(userp);
3455                         smb_SendTran2Error(vcp, p, opx, code);
3456                         smb_FreeTran2Packet(outp);
3457                         return 0;
3458                     }
3459                 }
3460             }
3461         }
3462 #endif /* SPECIAL_FOLDERS */
3463
3464         cm_FreeSpace(spacep);
3465     }
3466
3467     if (code == 0 ||
3468         code == CM_ERROR_NOSUCHFILE ||
3469         code == CM_ERROR_NOSUCHPATH ||
3470         code == CM_ERROR_BPLUS_NOMATCH) {
3471         /* now do namei and stat, and copy out the info */
3472         code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3473                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3474     }
3475
3476     if (code) {
3477         cm_ReleaseUser(userp);
3478         smb_SendTran2Error(vcp, p, opx, code);
3479         smb_FreeTran2Packet(outp);
3480         return 0;
3481     }
3482
3483 #ifdef DFS_SUPPORT
3484     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3485         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3486         cm_ReleaseSCache(scp);
3487         cm_ReleaseUser(userp);
3488         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3489             code = CM_ERROR_PATH_NOT_COVERED;
3490         else
3491             code = CM_ERROR_NOSUCHPATH;
3492         smb_SendTran2Error(vcp, p, opx, code);
3493         smb_FreeTran2Packet(outp);
3494         return 0;
3495     }
3496 #endif /* DFS_SUPPORT */
3497
3498     lock_ObtainWrite(&scp->rw);
3499     scp_rw_held = 2;
3500     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3501                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3502     if (code)
3503         goto done;
3504
3505     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3506
3507     lock_ConvertWToR(&scp->rw);
3508     scp_rw_held = 1;
3509
3510     len = 0;
3511
3512     /* now we have the status in the cache entry, and everything is locked.
3513      * Marshall the output data.
3514      */
3515     /* for info level 108, figure out short name */
3516     if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3517         code = cm_GetShortName(pathp, userp, &req,
3518                                 tidPathp, scp->fid.vnode, shortName,
3519                                &len);
3520         if (code) {
3521             goto done;
3522         }
3523
3524         smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3525         qpi.u.QPfileAltNameInfo.fileNameLength = len;
3526         responseSize = sizeof(unsigned long) + len;
3527     }
3528     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3529         smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3530         qpi.u.QPfileNameInfo.fileNameLength = len;
3531         responseSize = sizeof(unsigned long) + len;
3532     }
3533     else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3534         cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3535         qpi.u.QPstandardInfo.creationDateTime = dosTime;
3536         qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3537         qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3538         qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3539         qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3540         attributes = smb_Attributes(scp);
3541         qpi.u.QPstandardInfo.attributes = attributes;
3542         qpi.u.QPstandardInfo.eaSize = 0;
3543     }
3544     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3545         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3546         qpi.u.QPfileBasicInfo.creationTime = ft;
3547         qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3548         qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3549         qpi.u.QPfileBasicInfo.changeTime = ft;
3550         extAttributes = smb_ExtAttributes(scp);
3551         qpi.u.QPfileBasicInfo.attributes = extAttributes;
3552         qpi.u.QPfileBasicInfo.reserved = 0;
3553     }
3554     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3555         smb_fid_t * fidp;
3556
3557         lock_ReleaseRead(&scp->rw);
3558         scp_rw_held = 0;
3559         fidp = smb_FindFIDByScache(vcp, scp);
3560
3561         qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3562         qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3563         qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3564         qpi.u.QPfileStandardInfo.directory =
3565             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3566               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3567               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3568         qpi.u.QPfileStandardInfo.reserved = 0;
3569
3570         if (fidp) {
3571             lock_ObtainMutex(&fidp->mx);
3572             delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3573             lock_ReleaseMutex(&fidp->mx);
3574             smb_ReleaseFID(fidp);
3575         }
3576         qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3577     }
3578     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3579         qpi.u.QPfileEaInfo.eaSize = 0;
3580     }
3581     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3582         smb_fid_t * fidp;
3583
3584         lock_ReleaseRead(&scp->rw);
3585         scp_rw_held = 0;
3586         fidp = smb_FindFIDByScache(vcp, scp);
3587
3588         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3589         qpi.u.QPfileAllInfo.creationTime = ft;
3590         qpi.u.QPfileAllInfo.lastAccessTime = ft;
3591         qpi.u.QPfileAllInfo.lastWriteTime = ft;
3592         qpi.u.QPfileAllInfo.changeTime = ft;
3593         extAttributes = smb_ExtAttributes(scp);
3594         qpi.u.QPfileAllInfo.attributes = extAttributes;
3595         qpi.u.QPfileAllInfo.allocationSize = scp->length;
3596         qpi.u.QPfileAllInfo.endOfFile = scp->length;
3597         qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3598         qpi.u.QPfileAllInfo.deletePending = 0;
3599         qpi.u.QPfileAllInfo.directory =
3600             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3601               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3602               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3603         qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.vnode;
3604         qpi.u.QPfileAllInfo.indexNumber.LowPart  = scp->fid.unique;
3605         qpi.u.QPfileAllInfo.eaSize = 0;
3606         qpi.u.QPfileAllInfo.accessFlags = 0;
3607         if (fidp) {
3608             lock_ObtainMutex(&fidp->mx);
3609             if (fidp->flags & SMB_FID_OPENDELETE)
3610                 qpi.u.QPfileAllInfo.accessFlags |= DELETE;
3611             if (fidp->flags & SMB_FID_OPENREAD_LISTDIR)
3612                 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_READ|AFS_ACCESS_EXECUTE;
3613             if (fidp->flags & SMB_FID_OPENWRITE)
3614                 qpi.u.QPfileAllInfo.accessFlags |= AFS_ACCESS_WRITE;
3615             if (fidp->flags & SMB_FID_DELONCLOSE)
3616                 qpi.u.QPfileAllInfo.deletePending = 1;
3617             lock_ReleaseMutex(&fidp->mx);
3618             smb_ReleaseFID(fidp);
3619         }
3620         qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.cell;
3621         qpi.u.QPfileAllInfo.indexNumber2.LowPart  = scp->fid.volume;
3622         qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3623         qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3624         qpi.u.QPfileAllInfo.mode = 0;
3625         qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3626
3627         smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3628         qpi.u.QPfileAllInfo.fileNameLength = len;
3629         responseSize -= (sizeof(qpi.u.QPfileAllInfo.fileName) - len);
3630     }
3631     else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
3632         size_t len = 0;
3633         /* For now we have no streams */
3634         qpi.u.QPfileStreamInfo.nextEntryOffset = 0;
3635         if (scp->fileType == CM_SCACHETYPE_FILE) {
3636             qpi.u.QPfileStreamInfo.streamSize = scp->length;
3637             qpi.u.QPfileStreamInfo.streamAllocationSize = scp->length;
3638             smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
3639             qpi.u.QPfileStreamInfo.streamNameLength = len;
3640             responseSize -= (sizeof(qpi.u.QPfileStreamInfo.fileName) - len);
3641         } else {
3642             qpi.u.QPfileStreamInfo.streamSize.QuadPart = 0;
3643             qpi.u.QPfileStreamInfo.streamAllocationSize.QuadPart = 0;
3644             smb_UnparseString(opx, qpi.u.QPfileStreamInfo.fileName, L"", &len, SMB_STRF_IGNORENUL);
3645             qpi.u.QPfileStreamInfo.streamNameLength = 0;
3646             responseSize = 0;
3647         }
3648     }
3649     outp->totalData = responseSize;
3650
3651     /* send and free the packets */
3652   done:
3653     switch (scp_rw_held) {
3654     case 1:
3655         lock_ReleaseRead(&scp->rw);
3656         break;
3657     case 2:
3658         lock_ReleaseWrite(&scp->rw);
3659         break;
3660     }
3661     scp_rw_held = 0;
3662     cm_ReleaseSCache(scp);
3663     cm_ReleaseUser(userp);
3664     if (code == 0) {
3665         memcpy(outp->datap, &qpi, responseSize);
3666         smb_SendTran2Packet(vcp, outp, opx);
3667     } else {
3668         smb_SendTran2Error(vcp, p, opx, code);
3669     }
3670     smb_FreeTran2Packet(outp);
3671
3672     return 0;
3673 }
3674
3675 /* TRANS2_SET_PATH_INFORMATION */
3676 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3677 {
3678 #if 0
3679     osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3680     return CM_ERROR_BADOP;
3681 #else
3682     long code = 0;
3683     unsigned short infoLevel;
3684     clientchar_t * pathp;
3685     smb_tran2Packet_t *outp;
3686     smb_tran2QPathInfo_t *spi;
3687     cm_user_t *userp;
3688     cm_scache_t *scp, *dscp;
3689     cm_req_t req;
3690     cm_space_t *spacep;
3691     clientchar_t *tidPathp;
3692     clientchar_t *lastComp;
3693
3694     smb_InitReq(&req);
3695
3696     infoLevel = p->parmsp[0];
3697     osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3698     if (infoLevel != SMB_INFO_STANDARD &&
3699         infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3700         infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3701         osi_Log2(smb_logp, "Bad Tran2SetPathInfo op 0x%x infolevel 0x%x",
3702                   p->opcode, infoLevel);
3703         smb_SendTran2Error(vcp, p, opx,
3704                            infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3705         return 0;
3706     }
3707
3708     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3709
3710     osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3711               osi_LogSaveClientString(smb_logp, pathp));
3712
3713     userp = smb_GetTran2User(vcp, p);
3714     if (!userp) {
3715         osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3716         code = CM_ERROR_BADSMB;
3717         goto done;
3718     }
3719
3720     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3721     if (code == CM_ERROR_TIDIPC) {
3722         /* Attempt to use a TID allocated for IPC.  The client
3723          * is probably looking for DCE RPC end points which we
3724          * don't support OR it could be looking to make a DFS
3725          * referral request.
3726          */
3727         osi_Log0(smb_logp, "Tran2Open received IPC TID");
3728         cm_ReleaseUser(userp);
3729         return CM_ERROR_NOSUCHPATH;
3730     }
3731
3732     /*
3733     * XXX Strange hack XXX
3734     *
3735     * As of Patch 7 (13 January 98), we are having the following problem:
3736     * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3737     * requests to look up "desktop.ini" in all the subdirectories.
3738     * This can cause zillions of timeouts looking up non-existent cells
3739     * and volumes, especially in the top-level directory.
3740     *
3741     * We have not found any way to avoid this or work around it except
3742     * to explicitly ignore the requests for mount points that haven't
3743     * yet been evaluated and for directories that haven't yet been
3744     * fetched.
3745     */
3746     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3747         spacep = cm_GetSpace();
3748         /* smb_StripLastComponent will strip "::$DATA" if present */
3749         smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3750 #ifndef SPECIAL_FOLDERS
3751         /* Make sure that lastComp is not NULL */
3752         if (lastComp) {
3753             if (cm_ClientStrCmpI(lastComp,  _C("\\desktop.ini")) == 0) {
3754                 code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
3755                                  CM_FLAG_CASEFOLD
3756                                  | CM_FLAG_DIRSEARCH
3757                                  | CM_FLAG_FOLLOW,
3758                                  userp, tidPathp, &req, &dscp);
3759                 if (code == 0) {
3760 #ifdef DFS_SUPPORT
3761                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3762                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3763                                                                   spacep->wdata);
3764                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3765                             code = CM_ERROR_PATH_NOT_COVERED;
3766                         else
3767                             code = CM_ERROR_NOSUCHPATH;
3768                     } else
3769 #endif /* DFS_SUPPORT */
3770                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3771                         code = CM_ERROR_NOSUCHFILE;
3772                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3773                         cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
3774                         if (bp) {
3775                             buf_Release(bp);
3776                             bp = NULL;
3777                         }
3778                         else
3779                             code = CM_ERROR_NOSUCHFILE;
3780                     }
3781                     cm_ReleaseSCache(dscp);
3782                     if (code) {
3783                         cm_FreeSpace(spacep);
3784                         cm_ReleaseUser(userp);
3785                         smb_SendTran2Error(vcp, p, opx, code);
3786                         return 0;
3787                     }
3788                 }
3789             }
3790         }
3791 #endif /* SPECIAL_FOLDERS */
3792
3793         cm_FreeSpace(spacep);
3794     }
3795
3796     if (code == 0 ||
3797         code == CM_ERROR_NOSUCHFILE ||
3798         code == CM_ERROR_NOSUCHPATH ||
3799         code == CM_ERROR_BPLUS_NOMATCH) {
3800         /* now do namei and stat, and copy out the info */
3801         code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
3802                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3803     }
3804
3805     if (code) {
3806         cm_ReleaseUser(userp);
3807         smb_SendTran2Error(vcp, p, opx, code);
3808         return 0;
3809     }
3810
3811     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3812
3813     outp->totalParms = 2;
3814     outp->totalData = 0;
3815
3816     spi = (smb_tran2QPathInfo_t *)p->datap;
3817     if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3818         cm_attr_t attr;
3819
3820         /* lock the vnode with a callback; we need the current status
3821          * to determine what the new status is, in some cases.
3822          */
3823         lock_ObtainWrite(&scp->rw);
3824         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3825                           CM_SCACHESYNC_GETSTATUS
3826                          | CM_SCACHESYNC_NEEDCALLBACK);
3827         if (code) {
3828             lock_ReleaseWrite(&scp->rw);
3829             goto done;
3830         }
3831         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3832
3833         /* prepare for setattr call */
3834         attr.mask = CM_ATTRMASK_LENGTH;
3835         attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3836         attr.length.HighPart = 0;
3837
3838         if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3839             cm_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3840             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3841         }
3842
3843         if (spi->u.QPstandardInfo.attributes != 0) {
3844             if ((scp->unixModeBits & 0200)
3845                  && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3846                 /* make a writable file read-only */
3847                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3848                 attr.unixModeBits = scp->unixModeBits & ~0222;
3849             }
3850             else if ((scp->unixModeBits & 0200) == 0
3851                       && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3852                 /* make a read-only file writable */
3853                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3854                 attr.unixModeBits = scp->unixModeBits | 0222;
3855             }
3856         }
3857         lock_ReleaseRead(&scp->rw);
3858
3859         /* call setattr */
3860         if (attr.mask)
3861             code = cm_SetAttr(scp, &attr, userp, &req);
3862         else
3863             code = 0;
3864     }
3865     else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3866         /* we don't support EAs */
3867         code = CM_ERROR_EAS_NOT_SUPPORTED;
3868     }
3869
3870   done:
3871     cm_ReleaseSCache(scp);
3872     cm_ReleaseUser(userp);
3873     if (code == 0)
3874         smb_SendTran2Packet(vcp, outp, opx);
3875     else
3876         smb_SendTran2Error(vcp, p, opx, code);
3877     smb_FreeTran2Packet(outp);
3878
3879     return 0;
3880 #endif
3881 }
3882
3883 /* TRANS2_QUERY_FILE_INFORMATION */
3884 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3885 {
3886     smb_tran2Packet_t *outp;
3887     FILETIME ft;
3888     unsigned long attributes;
3889     unsigned short infoLevel;
3890     int responseSize;
3891     unsigned short fid;
3892     int delonclose = 0;
3893     cm_user_t *userp;
3894     smb_fid_t *fidp;
3895     cm_scache_t *scp;
3896     smb_tran2QFileInfo_t qfi;
3897     long code = 0;
3898     int  readlock = 0;
3899     cm_req_t req;
3900
3901     smb_InitReq(&req);
3902
3903     fid = p->parmsp[0];
3904     fidp = smb_FindFID(vcp, fid, 0);
3905
3906     if (fidp == NULL) {
3907         osi_Log2(smb_logp, "Tran2QFileInfo Unknown SMB Fid vcp 0x%p fid %d",
3908                  vcp, fid);
3909         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3910         return 0;
3911     }
3912
3913     lock_ObtainMutex(&fidp->mx);
3914     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3915         lock_ReleaseMutex(&fidp->mx);
3916         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3917         smb_CloseFID(vcp, fidp, NULL, 0);
3918         smb_ReleaseFID(fidp);
3919         return 0;
3920     }
3921     lock_ReleaseMutex(&fidp->mx);
3922
3923     infoLevel = p->parmsp[1];
3924     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3925         responseSize = sizeof(qfi.u.QFbasicInfo);
3926     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3927         responseSize = sizeof(qfi.u.QFstandardInfo);
3928     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3929         responseSize = sizeof(qfi.u.QFeaInfo);
3930     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
3931         responseSize = sizeof(qfi.u.QFfileNameInfo);
3932     else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO)
3933         responseSize = sizeof(qfi.u.QFfileStreamInfo);
3934     else {
3935         osi_Log2(smb_logp, "Bad Tran2QFileInfo op 0x%x infolevel 0x%x",
3936                   p->opcode, infoLevel);
3937         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3938         smb_ReleaseFID(fidp);
3939         return 0;
3940     }
3941     osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3942     memset(&qfi, 0, sizeof(qfi));
3943
3944     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3945
3946     if (infoLevel > 0x100)
3947         outp->totalParms = 2;
3948     else
3949         outp->totalParms = 0;
3950
3951     userp = smb_GetTran2User(vcp, p);
3952     if (!userp) {
3953         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3954         code = CM_ERROR_BADSMB;
3955         goto done;
3956     }
3957
3958     lock_ObtainMutex(&fidp->mx);
3959     delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3960     scp = fidp->scp;
3961     osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3962     cm_HoldSCache(scp);
3963     lock_ReleaseMutex(&fidp->mx);
3964     lock_ObtainWrite(&scp->rw);
3965     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3966                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3967     if (code)
3968         goto done;
3969
3970     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3971
3972     lock_ConvertWToR(&scp->rw);
3973     readlock = 1;
3974
3975     /* now we have the status in the cache entry, and everything is locked.
3976      * Marshall the output data.
3977      */
3978     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3979         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3980         qfi.u.QFbasicInfo.creationTime = ft;
3981         qfi.u.QFbasicInfo.lastAccessTime = ft;
3982         qfi.u.QFbasicInfo.lastWriteTime = ft;
3983         qfi.u.QFbasicInfo.lastChangeTime = ft;
3984         attributes = smb_ExtAttributes(scp);
3985         qfi.u.QFbasicInfo.attributes = attributes;
3986     }
3987     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3988         qfi.u.QFstandardInfo.allocationSize = scp->length;
3989         qfi.u.QFstandardInfo.endOfFile = scp->length;
3990         qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3991         qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3992         qfi.u.QFstandardInfo.directory =
3993             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3994               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3995               scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3996     }
3997     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3998         qfi.u.QFeaInfo.eaSize = 0;
3999     }
4000     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4001         size_t len = 0;
4002         clientchar_t *name;
4003
4004         lock_ReleaseRead(&scp->rw);
4005         lock_ObtainMutex(&fidp->mx);
4006         lock_ObtainRead(&scp->rw);
4007         if (fidp->NTopen_wholepathp)
4008             name = fidp->NTopen_wholepathp;
4009         else
4010             name = _C("\\");    /* probably can't happen */
4011         lock_ReleaseMutex(&fidp->mx);
4012
4013         smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
4014         responseSize = len + 4; /* this is actually what we want to return */
4015         qfi.u.QFfileNameInfo.fileNameLength = len;
4016     }
4017     else if (infoLevel == SMB_QUERY_FILE_STREAM_INFO) {
4018         size_t len = 0;
4019
4020         if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
4021             scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4022             scp->fileType == CM_SCACHETYPE_INVALID) {
4023             /* Do not return the alternate streams for directories */
4024             responseSize = 0;
4025         } else {
4026             /* For now we have no alternate streams */
4027             qfi.u.QFfileStreamInfo.nextEntryOffset = 0;
4028             qfi.u.QFfileStreamInfo.streamSize = scp->length;
4029             qfi.u.QFfileStreamInfo.streamAllocationSize = scp->length;
4030             smb_UnparseString(opx, qfi.u.QFfileStreamInfo.fileName, L"::$DATA", &len, SMB_STRF_IGNORENUL);
4031             qfi.u.QFfileStreamInfo.streamNameLength = len;
4032             responseSize -= (sizeof(qfi.u.QFfileStreamInfo.fileName) - len);
4033         }
4034     }
4035     outp->totalData = responseSize;
4036
4037     /* send and free the packets */
4038   done:
4039     if (readlock)
4040         lock_ReleaseRead(&scp->rw);
4041     else
4042         lock_ReleaseWrite(&scp->rw);
4043     cm_ReleaseSCache(scp);
4044     cm_ReleaseUser(userp);
4045     smb_ReleaseFID(fidp);
4046     if (code == 0) {
4047         memcpy(outp->datap, &qfi, responseSize);
4048         smb_SendTran2Packet(vcp, outp, opx);
4049     } else {
4050         smb_SendTran2Error(vcp, p, opx, code);
4051     }
4052     smb_FreeTran2Packet(outp);
4053
4054     return 0;
4055 }
4056
4057
4058 /* TRANS2_SET_FILE_INFORMATION */
4059 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4060 {
4061     long code = 0;
4062     unsigned short fid;
4063     smb_fid_t *fidp;
4064     unsigned short infoLevel;
4065     smb_tran2Packet_t *outp;
4066     cm_user_t *userp = NULL;
4067     cm_scache_t *scp = NULL;
4068     cm_req_t req;
4069
4070     smb_InitReq(&req);
4071
4072     fid = p->parmsp[0];
4073     fidp = smb_FindFID(vcp, fid, 0);
4074
4075     if (fidp == NULL) {
4076         osi_Log2(smb_logp, "Tran2SetFileInfo Unknown SMB Fid vcp 0x%p fid %d",
4077                  vcp, fid);
4078         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
4079         return 0;
4080     }
4081
4082     infoLevel = p->parmsp[1];
4083     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
4084     if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
4085         osi_Log2(smb_logp, "Bad Tran2SetFileInfo op 0x%x infolevel 0x%x",
4086                   p->opcode, infoLevel);
4087         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
4088         smb_ReleaseFID(fidp);
4089         return 0;
4090     }
4091
4092     lock_ObtainMutex(&fidp->mx);
4093     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
4094         lock_ReleaseMutex(&fidp->mx);
4095         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
4096         smb_CloseFID(vcp, fidp, NULL, 0);
4097         smb_ReleaseFID(fidp);
4098         return 0;
4099     }
4100
4101     if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO &&
4102         !(fidp->flags & SMB_FID_OPENDELETE)) {
4103         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x",
4104                   fidp, fidp->scp, fidp->flags);
4105         lock_ReleaseMutex(&fidp->mx);
4106         smb_ReleaseFID(fidp);
4107         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
4108         return 0;
4109     }
4110     if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4111          infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
4112          && !(fidp->flags & SMB_FID_OPENWRITE)) {
4113         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x",
4114                   fidp, fidp->scp, fidp->flags);
4115         lock_ReleaseMutex(&fidp->mx);
4116         smb_ReleaseFID(fidp);
4117         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
4118         return 0;
4119     }
4120
4121     scp = fidp->scp;
4122     osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
4123     cm_HoldSCache(scp);
4124     lock_ReleaseMutex(&fidp->mx);
4125
4126     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
4127
4128     outp->totalParms = 2;
4129     outp->totalData = 0;
4130
4131     userp = smb_GetTran2User(vcp, p);
4132     if (!userp) {
4133         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
4134         code = CM_ERROR_BADSMB;
4135         goto done;
4136     }
4137
4138     if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
4139         FILETIME lastMod;
4140         unsigned int attribute;
4141         cm_attr_t attr;
4142         smb_tran2QFileInfo_t *sfi;
4143
4144         sfi = (smb_tran2QFileInfo_t *)p->datap;
4145
4146         /* lock the vnode with a callback; we need the current status
4147          * to determine what the new status is, in some cases.
4148          */
4149         lock_ObtainWrite(&scp->rw);
4150         code = cm_SyncOp(scp, NULL, userp, &req, 0,
4151                           CM_SCACHESYNC_GETSTATUS
4152                          | CM_SCACHESYNC_NEEDCALLBACK);
4153         if (code) {
4154             lock_ReleaseWrite(&scp->rw);
4155             goto done;
4156         }
4157
4158         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4159
4160         lock_ReleaseWrite(&scp->rw);
4161         lock_ObtainMutex(&fidp->mx);
4162         lock_ObtainRead(&scp->rw);
4163
4164         /* prepare for setattr call */
4165         attr.mask = 0;
4166
4167         lastMod = sfi->u.QFbasicInfo.lastWriteTime;
4168         /* when called as result of move a b, lastMod is (-1, -1).
4169          * If the check for -1 is not present, timestamp
4170          * of the resulting file will be 1969 (-1)
4171          */
4172         if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) &&
4173              lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
4174             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4175             cm_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
4176             fidp->flags |= SMB_FID_MTIMESETDONE;
4177         }
4178
4179         attribute = sfi->u.QFbasicInfo.attributes;
4180         if (attribute != 0) {
4181             if ((scp->unixModeBits & 0200)
4182                  && (attribute & SMB_ATTR_READONLY) != 0) {
4183                 /* make a writable file read-only */
4184                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4185                 attr.unixModeBits = scp->unixModeBits & ~0222;
4186             }
4187             else if ((scp->unixModeBits & 0200) == 0
4188                       && (attribute & SMB_ATTR_READONLY) == 0) {
4189                 /* make a read-only file writable */
4190                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4191                 attr.unixModeBits = scp->unixModeBits | 0222;
4192             }
4193         }
4194         lock_ReleaseRead(&scp->rw);
4195         lock_ReleaseMutex(&fidp->mx);
4196
4197         /* call setattr */
4198         if (attr.mask)
4199             code = cm_SetAttr(scp, &attr, userp, &req);
4200         else
4201             code = 0;
4202     }
4203     else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
4204         int delflag = *((char *)(p->datap));
4205         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p",
4206                  delflag, fidp, scp);
4207         if (*((char *)(p->datap))) {    /* File is Deleted */
4208             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
4209                                      &req);
4210             if (code == 0) {
4211                 lock_ObtainMutex(&fidp->mx);
4212                 fidp->flags |= SMB_FID_DELONCLOSE;
4213                 lock_ReleaseMutex(&fidp->mx);
4214             } else {
4215                 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x",
4216                          fidp, scp, code);
4217             }
4218         }
4219         else {
4220             code = 0;
4221             lock_ObtainMutex(&fidp->mx);
4222             fidp->flags &= ~SMB_FID_DELONCLOSE;
4223             lock_ReleaseMutex(&fidp->mx);
4224         }
4225     }
4226     else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
4227              infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
4228         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
4229         cm_attr_t attr;
4230
4231         attr.mask = CM_ATTRMASK_LENGTH;
4232         attr.length.LowPart = size.LowPart;
4233         attr.length.HighPart = size.HighPart;
4234         code = cm_SetAttr(scp, &attr, userp, &req);
4235     }
4236
4237   done:
4238     cm_ReleaseSCache(scp);
4239     cm_ReleaseUser(userp);
4240     smb_ReleaseFID(fidp);
4241     if (code == 0)
4242         smb_SendTran2Packet(vcp, outp, opx);
4243     else
4244         smb_SendTran2Error(vcp, p, opx, code);
4245     smb_FreeTran2Packet(outp);
4246
4247     return 0;
4248 }
4249
4250 /* TRANS2_FSCTL */
4251 long
4252 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4253 {
4254     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
4255     return CM_ERROR_BADOP;
4256 }
4257
4258 /* TRANS2_IOCTL2 */
4259 long
4260 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4261 {
4262     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
4263     return CM_ERROR_BADOP;
4264 }
4265
4266 /* TRANS2_FIND_NOTIFY_FIRST */
4267 long
4268 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4269 {
4270     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
4271     return CM_ERROR_BADOP;
4272 }
4273
4274 /* TRANS2_FIND_NOTIFY_NEXT */
4275 long
4276 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4277 {
4278     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
4279     return CM_ERROR_BADOP;
4280 }
4281
4282 /* TRANS2_CREATE_DIRECTORY */
4283 long
4284 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4285 {
4286     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
4287     return CM_ERROR_BADOP;
4288 }
4289
4290 /* TRANS2_SESSION_SETUP */
4291 long
4292 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4293 {
4294     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
4295     return CM_ERROR_BADOP;
4296 }
4297
4298 struct smb_v2_referral {
4299     USHORT ServerType;
4300     USHORT ReferralFlags;
4301     ULONG  Proximity;
4302     ULONG  TimeToLive;
4303     USHORT DfsPathOffset;
4304     USHORT DfsAlternativePathOffset;
4305     USHORT NetworkAddressOffset;
4306 };
4307
4308 /* TRANS2_GET_DFS_REFERRAL */
4309 long
4310 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
4311 {
4312     /* This is a UNICODE only request (bit15 of Flags2) */
4313     /* The TID must be IPC$ */
4314
4315     /* The documentation for the Flags response field is contradictory */
4316
4317     /* Use Version 1 Referral Element Format */
4318     /* ServerType = 0; indicates the next server should be queried for the file */
4319     /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
4320     /* Node = UnicodeString of UNC path of the next share name */
4321 #ifdef DFS_SUPPORT
4322     long code = 0;
4323     int maxReferralLevel = 0;
4324     clientchar_t requestFileName[1024] = _C("");
4325     clientchar_t referralPath[1024] = _C("");
4326     smb_tran2Packet_t *outp = 0;
4327     cm_user_t *userp = 0;
4328     cm_scache_t *scp = 0;
4329     cm_scache_t *dscp = 0;
4330     cm_req_t req;
4331     CPINFO CodePageInfo;
4332     int i, nbnLen, reqLen, refLen;
4333     int idx;
4334
4335     smb_InitReq(&req);
4336
4337     maxReferralLevel = p->parmsp[0];
4338
4339     GetCPInfo(CP_ACP, &CodePageInfo);
4340     cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
4341
4342     osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]",
4343              maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
4344
4345     nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
4346     reqLen = (int)cm_ClientStrLen(requestFileName);
4347
4348     if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
4349         !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
4350         requestFileName[nbnLen+1] == '\\')
4351     {
4352         int found = 0;
4353
4354         if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
4355             !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
4356             found = 1;
4357             cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4358             refLen = reqLen;
4359         } else {
4360             userp = smb_GetTran2User(vcp, p);
4361             if (!userp) {
4362                 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
4363                 code = CM_ERROR_BADSMB;
4364                 goto done;
4365             }
4366
4367             /*
4368              * We have a requested path.  Check to see if it is something
4369              * we know about.
4370              *
4371              * But be careful because the name that we might be searching
4372              * for might be a known name with the final character stripped
4373              * off.
4374              */
4375             code = cm_NameI(cm_RootSCachep(userp, &req), &requestFileName[nbnLen+2],
4376                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
4377                             userp, NULL, &req, &scp);
4378             if (code == 0 ||
4379                 code == CM_ERROR_ALLDOWN ||
4380                 code == CM_ERROR_ALLBUSY ||
4381                 code == CM_ERROR_ALLOFFLINE ||
4382                 code == CM_ERROR_NOSUCHCELL ||
4383                 code == CM_ERROR_NOSUCHVOLUME ||
4384                 code == CM_ERROR_NOACCESS) {
4385                 /* Yes it is. */
4386                 found = 1;
4387                 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4388                 refLen = reqLen;
4389             } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
4390                 clientchar_t temp[1024];
4391                 clientchar_t pathName[1024];
4392                 clientchar_t *lastComponent;
4393                 /*
4394                  * we have a msdfs link somewhere in the path
4395                  * we should figure out where in the path the link is.
4396                  * and return it.
4397                  */
4398                 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
4399
4400                 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
4401
4402                 do {
4403                     if (dscp) {
4404                         cm_ReleaseSCache(dscp);
4405                         dscp = 0;
4406                     }
4407                     if (scp) {
4408                         cm_ReleaseSCache(scp);
4409                         scp = 0;
4410                     }
4411                     /* smb_StripLastComponent will strip "::$DATA" if present */
4412                     smb_StripLastComponent(pathName, &lastComponent, temp);
4413
4414                     code = cm_NameI(cm_RootSCachep(userp, &req), pathName,
4415                                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4416                                     userp, NULL, &req, &dscp);
4417                     if (code == 0) {
4418                         code = cm_NameI(dscp, ++lastComponent,
4419                                         CM_FLAG_CASEFOLD,
4420                                         userp, NULL, &req, &scp);
4421                         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
4422                             break;
4423                     }
4424                 } while (code == CM_ERROR_PATH_NOT_COVERED);
4425
4426                 /* scp should now be the DfsLink we are looking for */
4427                 if (scp) {
4428                     /* figure out how much of the input path was used */
4429                     reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
4430
4431                     cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
4432                                               referralPath, lengthof(referralPath));
4433                     refLen = (int)cm_ClientStrLen(referralPath);
4434                     found = 1;
4435                 }
4436             } else {
4437                 clientchar_t shareName[MAX_PATH + 1];
4438                 clientchar_t *p, *q;
4439                 /* we may have a sharename that is a volume reference */
4440
4441                 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
4442                 {
4443                     *q = *p;
4444                 }
4445                 *q = '\0';
4446
4447                 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
4448                     code = cm_NameI(cm_RootSCachep(userp, &req), _C(""),
4449                                     CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
4450                                     userp, p, &req, &scp);
4451                     free(p);
4452
4453                     if (code == 0) {
4454                         found = 1;
4455                         cm_ClientStrCpy(referralPath, lengthof(referralPath),
4456                                         requestFileName);
4457                         refLen = reqLen;
4458                     }
4459                 }
4460             }
4461         }
4462
4463         if (found)
4464         {
4465             USHORT * sp;
4466             struct smb_v2_referral * v2ref;
4467             outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
4468
4469             sp = (USHORT *)outp->datap;
4470             idx = 0;
4471             sp[idx++] = reqLen;   /* path consumed */
4472             sp[idx++] = 1;        /* number of referrals */
4473             sp[idx++] = 0x03;     /* flags */
4474 #ifdef DFS_VERSION_1
4475             sp[idx++] = 1;        /* Version Number */
4476             sp[idx++] = refLen + 4;  /* Referral Size */
4477             sp[idx++] = 1;        /* Type = SMB Server */
4478             sp[idx++] = 0;        /* Do not strip path consumed */
4479             for ( i=0;i<=refLen; i++ )
4480                 sp[i+idx] = referralPath[i];
4481 #else /* DFS_VERSION_2 */
4482             sp[idx++] = 2;      /* Version Number */
4483             sp[idx++] = sizeof(struct smb_v2_referral);     /* Referral Size */
4484             idx += (sizeof(struct smb_v2_referral) / 2);
4485             v2ref = (struct smb_v2_referral *) &sp[5];
4486             v2ref->ServerType = 1;  /* SMB Server */
4487             v2ref->ReferralFlags = 0x03;
4488             v2ref->Proximity = 0;   /* closest */
4489             v2ref->TimeToLive = 3600; /* seconds */
4490             v2ref->DfsPathOffset = idx * 2;
4491             v2ref->DfsAlternativePathOffset = idx * 2;
4492             v2ref->NetworkAddressOffset = 0;
4493             for ( i=0;i<=refLen; i++ )
4494                 sp[i+idx] = referralPath[i];
4495 #endif
4496         } else {
4497             code = CM_ERROR_NOSUCHPATH;
4498         }
4499     } else {
4500         code = CM_ERROR_NOSUCHPATH;
4501     }
4502
4503   done:
4504     if (dscp)
4505         cm_ReleaseSCache(dscp);
4506     if (scp)
4507         cm_ReleaseSCache(scp);
4508     if (userp)
4509         cm_ReleaseUser(userp);
4510     if (code == 0)
4511         smb_SendTran2Packet(vcp, outp, op);
4512     else
4513         smb_SendTran2Error(vcp, p, op, code);
4514     if (outp)
4515         smb_FreeTran2Packet(outp);
4516
4517     return 0;
4518 #else /* DFS_SUPPORT */
4519     osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED");
4520     return CM_ERROR_NOSUCHDEVICE;
4521 #endif /* DFS_SUPPORT */
4522 }
4523
4524 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4525 long
4526 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4527 {
4528     /* This is a UNICODE only request (bit15 of Flags2) */
4529
4530     /* There is nothing we can do about this operation.  The client is going to
4531      * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
4532      * Unfortunately, there is really nothing we can do about it other then log it
4533      * somewhere.  Even then I don't think there is anything for us to do.
4534      * So let's return an error value.
4535      */
4536
4537     osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
4538     return CM_ERROR_BADOP;
4539 }
4540
4541 static long
4542 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp,
4543                           clientchar_t * tidPathp, clientchar_t * relPathp,
4544                           int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4545 {
4546     long code = 0;
4547     cm_scache_t *scp;
4548     cm_scache_t *targetScp;                     /* target if scp is a symlink */
4549     afs_uint32 dosTime;
4550     FILETIME ft;
4551     unsigned short attr;
4552     unsigned long lattr;
4553     smb_dirListPatch_t *patchp;
4554     smb_dirListPatch_t *npatchp;
4555     afs_uint32 rights;
4556     afs_int32 mustFake = 0;
4557     clientchar_t path[AFSPATHMAX];
4558
4559     code = cm_FindACLCache(dscp, userp, &rights);
4560     if (code == -1) {
4561         lock_ObtainWrite(&dscp->rw);
4562         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4563                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4564         if (code == 0)
4565             cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4566         lock_ReleaseWrite(&dscp->rw);
4567         if (code == CM_ERROR_NOACCESS) {
4568             mustFake = 1;
4569             code = 0;
4570         }
4571     }
4572     if (code)
4573         goto cleanup;
4574
4575     if (!mustFake) {    /* Bulk Stat */
4576         afs_uint32 count;
4577         cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4578
4579         memset(bsp, 0, sizeof(cm_bulkStat_t));
4580
4581         for (patchp = *dirPatchespp, count=0;
4582              patchp;
4583              patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4584             cm_scache_t *tscp = NULL;
4585             int i;
4586
4587             /* Do not look for a cm_scache_t or bulkstat an ioctl entry */
4588             if (patchp->flags & SMB_DIRLISTPATCH_IOCTL)
4589                 continue;
4590
4591             code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4592             if (code == 0) {
4593                 if (lock_TryWrite(&tscp->rw)) {
4594                     /* we have an entry that we can look at */
4595 #ifdef AFS_FREELANCE_CLIENT
4596                     if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4597                         code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4598                                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4599                         if (code == 0)
4600                             cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4601
4602                         lock_ReleaseWrite(&tscp->rw);
4603                         cm_ReleaseSCache(tscp);
4604                         continue;
4605                     }
4606 #endif /* AFS_FREELANCE_CLIENT */
4607                     if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4608                         /* we have a callback on it.  Don't bother
4609                         * fetching this stat entry, since we're happy
4610                         * with the info we have.
4611                         */
4612                         lock_ReleaseWrite(&tscp->rw);
4613                         cm_ReleaseSCache(tscp);
4614                         continue;
4615                     }
4616                     lock_ReleaseWrite(&tscp->rw);
4617                 } /* got lock */
4618                 cm_ReleaseSCache(tscp);
4619             }   /* found entry */
4620
4621             i = bsp->counter++;
4622             bsp->fids[i].Volume = patchp->fid.volume;
4623             bsp->fids[i].Vnode = patchp->fid.vnode;
4624             bsp->fids[i].Unique = patchp->fid.unique;
4625
4626             if (bsp->counter == AFSCBMAX) {
4627                 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4628                 memset(bsp, 0, sizeof(cm_bulkStat_t));
4629             }
4630         }
4631
4632         if (bsp->counter > 0)
4633             code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4634
4635         free(bsp);
4636     }
4637
4638     for( patchp = *dirPatchespp;
4639          patchp;
4640          patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4641         cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4642                             relPathp ? relPathp : _C(""), patchp->dep->name);
4643         reqp->relPathp = path;
4644         reqp->tidPathp = tidPathp;
4645
4646         if (patchp->flags & SMB_DIRLISTPATCH_IOCTL) {
4647             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4648                errors in the client. */
4649             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4650                 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4651
4652                 /* 1969-12-31 23:59:59 +00 */
4653                 ft.dwHighDateTime = 0x19DB200;
4654                 ft.dwLowDateTime = 0x5BB78980;
4655
4656                 /* copy to Creation Time */
4657                 fa->creationTime = ft;
4658                 fa->lastAccessTime = ft;
4659                 fa->lastWriteTime = ft;
4660                 fa->lastChangeTime = ft;
4661                 fa->extFileAttributes = SMB_ATTR_SYSTEM | SMB_ATTR_HIDDEN;
4662             } else {
4663                 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4664
4665                 /* 1969-12-31 23:59:58 +00*/
4666                 dosTime = 0xEBBFBF7D;
4667
4668                 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4669                 fa->lastAccessDateTime = fa->creationDateTime;
4670                 fa->lastWriteDateTime = fa->creationDateTime;
4671                 fa->attributes = SMB_ATTR_SYSTEM|SMB_ATTR_HIDDEN;
4672             }
4673             continue;
4674         }
4675
4676         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4677         reqp->relPathp = reqp->tidPathp = NULL;
4678         if (code)
4679             continue;
4680
4681         lock_ObtainWrite(&scp->rw);
4682         if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4683             lock_ReleaseWrite(&scp->rw);
4684
4685             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4686                errors in the client. */
4687             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4688                 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4689
4690                 /* 1969-12-31 23:59:59 +00 */
4691                 ft.dwHighDateTime = 0x19DB200;
4692                 ft.dwLowDateTime = 0x5BB78980;
4693
4694                 /* copy to Creation Time */
4695                 fa->creationTime = ft;
4696                 fa->lastAccessTime = ft;
4697                 fa->lastWriteTime = ft;
4698                 fa->lastChangeTime = ft;
4699
4700                 switch (scp->fileType) {
4701                 case CM_SCACHETYPE_DIRECTORY:
4702                 case CM_SCACHETYPE_MOUNTPOINT:
4703                 case CM_SCACHETYPE_INVALID:
4704                     fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4705                     break;
4706                 case CM_SCACHETYPE_SYMLINK:
4707                     if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4708                         fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4709                     else
4710                         fa->extFileAttributes = SMB_ATTR_NORMAL;
4711                     break;
4712                 default:
4713                     /* if we get here we either have a normal file
4714                      * or we have a file for which we have never
4715                      * received status info.  In this case, we can
4716                      * check the even/odd value of the entry's vnode.
4717                      * odd means it is to be treated as a directory
4718                      * and even means it is to be treated as a file.
4719                      */
4720                     if (mustFake && (scp->fid.vnode & 0x1))
4721                         fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4722                     else
4723                         fa->extFileAttributes = SMB_ATTR_NORMAL;
4724                 }
4725                 /* merge in hidden attribute */
4726                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4727                     fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4728                 }
4729             } else {
4730                 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4731
4732                 /* 1969-12-31 23:59:58 +00*/
4733                 dosTime = 0xEBBFBF7D;
4734
4735                 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4736                 fa->lastAccessDateTime = fa->creationDateTime;
4737                 fa->lastWriteDateTime = fa->creationDateTime;
4738
4739                 /* set the attribute */
4740                 switch (scp->fileType) {
4741                 case CM_SCACHETYPE_DIRECTORY:
4742                 case CM_SCACHETYPE_MOUNTPOINT:
4743                 case CM_SCACHETYPE_INVALID:
4744                     fa->attributes = SMB_ATTR_DIRECTORY;
4745                     break;
4746                 case CM_SCACHETYPE_SYMLINK:
4747                     if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4748                         fa->attributes = SMB_ATTR_DIRECTORY;
4749                     else
4750                         fa->attributes = SMB_ATTR_NORMAL;
4751                     break;
4752                 default:
4753                     /* if we get here we either have a normal file
4754                      * or we have a file for which we have never
4755                      * received status info.  In this case, we can
4756                      * check the even/odd value of the entry's vnode.
4757                      * even means it is to be treated as a directory
4758                      * and odd means it is to be treated as a file.
4759                      */
4760                     if (mustFake && (scp->fid.vnode & 0x1))
4761                         fa->attributes = SMB_ATTR_DIRECTORY;
4762                     else
4763                         fa->attributes = SMB_ATTR_NORMAL;
4764                 }
4765
4766                 /* merge in hidden (dot file) attribute */
4767                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4768                     fa->attributes |= SMB_ATTR_HIDDEN;
4769                 }
4770             }
4771
4772             cm_ReleaseSCache(scp);
4773             continue;
4774         }
4775
4776         /* now watch for a symlink */
4777         code = 0;
4778         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4779             lock_ReleaseWrite(&scp->rw);
4780             cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4781                                 relPathp ? relPathp : _C(""), patchp->dep->name);
4782             reqp->relPathp = path;
4783             reqp->tidPathp = tidPathp;
4784             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4785             reqp->relPathp = reqp->tidPathp = NULL;
4786             if (code == 0) {
4787                 /* we have a more accurate file to use (the
4788                  * target of the symbolic link).  Otherwise,
4789                  * we'll just use the symlink anyway.
4790                  */
4791                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4792                           scp, targetScp);
4793                 cm_ReleaseSCache(scp);
4794                 scp = targetScp;
4795             }
4796             lock_ObtainWrite(&scp->rw);
4797         }
4798
4799         lock_ConvertWToR(&scp->rw);
4800
4801         if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4802             smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4803
4804             /* get filetime */
4805             cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4806
4807             fa->creationTime = ft;
4808             fa->lastAccessTime = ft;
4809             fa->lastWriteTime = ft;
4810             fa->lastChangeTime = ft;
4811
4812             /* Use length for both file length and alloc length */
4813             fa->endOfFile = scp->length;
4814             fa->allocationSize = scp->length;
4815
4816             /* Copy attributes */
4817             lattr = smb_ExtAttributes(scp);
4818             if ((code == CM_ERROR_NOSUCHPATH &&
4819                 (scp->fileType == CM_SCACHETYPE_SYMLINK &&
4820                 cm_TargetPerceivedAsDirectory(scp->mountPointStringp))) ||
4821                 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4822                 if (lattr == SMB_ATTR_NORMAL)
4823                     lattr = SMB_ATTR_DIRECTORY;
4824                 else
4825                     lattr |= SMB_ATTR_DIRECTORY;
4826             }
4827             /* merge in hidden (dot file) attribute */
4828             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4829                 if (lattr == SMB_ATTR_NORMAL)
4830                     lattr = SMB_ATTR_HIDDEN;
4831                 else
4832                     lattr |= SMB_ATTR_HIDDEN;
4833             }
4834
4835             fa->extFileAttributes = lattr;
4836         } else {
4837             smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4838
4839             /* get dos time */
4840             cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4841
4842             fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4843             fa->lastAccessDateTime = fa->creationDateTime;
4844             fa->lastWriteDateTime = fa->creationDateTime;
4845
4846             /* copy out file length and alloc length,
4847              * using the same for both
4848              */
4849             fa->dataSize = scp->length.LowPart;
4850             fa->allocationSize = scp->length.LowPart;
4851
4852             /* finally copy out attributes as short */
4853             attr = smb_Attributes(scp);
4854             /* merge in hidden (dot file) attribute */
4855             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4856                 if (lattr == SMB_ATTR_NORMAL)
4857                     lattr = SMB_ATTR_HIDDEN;
4858                 else
4859                     lattr |= SMB_ATTR_HIDDEN;
4860             }
4861             fa->attributes = attr;
4862         }
4863
4864         lock_ReleaseRead(&scp->rw);
4865         cm_ReleaseSCache(scp);
4866     }
4867
4868     /* now free the patches */
4869     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4870         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4871         free(patchp);
4872     }
4873
4874     /* and mark the list as empty */
4875     *dirPatchespp = NULL;
4876
4877   cleanup:
4878     return code;
4879 }
4880
4881 /* smb_ReceiveTran2SearchDir implements both
4882  * Tran2_Find_First and Tran2_Find_Next
4883  */
4884 #define TRAN2_FIND_FLAG_CLOSE_SEARCH            0x01
4885 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END     0x02
4886 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS      0x04
4887 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH         0x08
4888 #define TRAN2_FIND_FLAG_BACKUP_INTENT           0x10
4889
4890 /* this is an optimized handler for T2SearchDir that handles the case
4891    where there are no wildcards in the search path.  I.e. an
4892    application is using FindFirst(Ex) to get information about a
4893    single file or directory.  It will attempt to do a single lookup.
4894    If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4895    the usual mechanism.
4896
4897    This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4898
4899    TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4900    */
4901 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4902 {
4903     int attribute;
4904     long nextCookie;
4905     long code = 0, code2 = 0;
4906     clientchar_t *pathp = 0;
4907     int maxCount;
4908     smb_dirListPatch_t *dirListPatchesp;
4909     smb_dirListPatch_t *curPatchp;
4910     size_t orbytes;                     /* # of bytes in this output record */
4911     size_t ohbytes;                     /* # of bytes, except file name */
4912     size_t onbytes;                     /* # of bytes in name, incl. term. null */
4913     cm_scache_t *scp = NULL;
4914     cm_scache_t *targetScp = NULL;
4915     cm_user_t *userp = NULL;
4916     char *op;                           /* output data ptr */
4917     char *origOp;                       /* original value of op */
4918     cm_space_t *spacep;                 /* for pathname buffer */
4919     unsigned long maxReturnData;        /* max # of return data */
4920     long maxReturnParms;                /* max # of return parms */
4921     long bytesInBuffer;                 /* # data bytes in the output buffer */
4922     clientchar_t *maskp;                        /* mask part of path */
4923     int infoLevel;
4924     int searchFlags;
4925     int eos;
4926     smb_tran2Packet_t *outp;            /* response packet */
4927     clientchar_t *tidPathp = 0;
4928     int align;
4929     clientchar_t shortName[13];         /* 8.3 name if needed */
4930     int NeedShortName;
4931     clientchar_t *shortNameEnd;
4932     cm_dirEntry_t * dep = NULL;
4933     cm_req_t req;
4934     char * s;
4935     void * attrp = NULL;
4936     smb_tran2Find_t * fp;
4937     int afs_ioctl = 0;                  /* is this query for _._AFS_IOCTL_._? */
4938     cm_dirFid_t dfid;
4939
4940     smb_InitReq(&req);
4941
4942     eos = 0;
4943     osi_assertx(p->opcode == 1, "invalid opcode");
4944
4945     /* find first; obtain basic parameters from request */
4946
4947     /* note that since we are going to failover to regular
4948      * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4949      * modify any of the input parameters here. */
4950     attribute = p->parmsp[0];
4951     maxCount = p->parmsp[1];
4952     infoLevel = p->parmsp[3];
4953     searchFlags = p->parmsp[2];
4954     pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4955     nextCookie = 0;
4956     maskp = cm_ClientStrRChr(pathp,  '\\');
4957     if (maskp == NULL)
4958         maskp = pathp;
4959     else
4960         maskp++;        /* skip over backslash */
4961     /* track if this is likely to match a lot of entries */
4962
4963     osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4964              osi_LogSaveClientString(smb_logp, pathp),
4965              osi_LogSaveClientString(smb_logp, maskp));
4966
4967     switch ( infoLevel ) {
4968     case SMB_INFO_STANDARD:
4969         s = "InfoStandard";
4970         ohbytes = sizeof(fp->u.FstandardInfo);
4971         break;
4972
4973     case SMB_INFO_QUERY_EA_SIZE:
4974         ohbytes = sizeof(fp->u.FeaSizeInfo);
4975         s = "InfoQueryEaSize";
4976         break;
4977
4978     case SMB_INFO_QUERY_EAS_FROM_LIST:
4979         ohbytes = sizeof(fp->u.FeasFromListInfo);
4980         s = "InfoQueryEasFromList";
4981         break;
4982
4983     case SMB_FIND_FILE_DIRECTORY_INFO:
4984         s = "FindFileDirectoryInfo";
4985         ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4986         break;
4987
4988     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4989         s = "FindFileFullDirectoryInfo";
4990         ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4991         break;
4992
4993     case SMB_FIND_FILE_NAMES_INFO:
4994         s = "FindFileNamesInfo";
4995         ohbytes = sizeof(fp->u.FfileNamesInfo);
4996         break;
4997
4998     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4999         s = "FindFileBothDirectoryInfo";
5000         ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5001         break;
5002
5003     default:
5004         s = "unknownInfoLevel";
5005         ohbytes = 0;
5006     }
5007
5008     osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
5009
5010     osi_Log4(smb_logp,
5011              "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5012              attribute, infoLevel, maxCount, searchFlags);
5013
5014     if (ohbytes == 0) {
5015         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5016         return CM_ERROR_INVAL;
5017     }
5018
5019     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5020         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;     /* no resume keys */
5021
5022     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5023         ohbytes += 4;
5024
5025     dirListPatchesp = NULL;
5026
5027     maxReturnData = p->maxReturnData;
5028     maxReturnParms = 10;        /* return params for findfirst, which
5029                                    is the only one we handle.*/
5030
5031     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5032                                       maxReturnData);
5033
5034     osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
5035              maxCount, osi_LogSaveClientString(smb_logp, pathp));
5036
5037     /* bail out if request looks bad */
5038     if (!pathp) {
5039         smb_FreeTran2Packet(outp);
5040         return CM_ERROR_BADSMB;
5041     }
5042
5043     userp = smb_GetTran2User(vcp, p);
5044     if (!userp) {
5045         osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
5046         smb_FreeTran2Packet(outp);
5047         return CM_ERROR_BADSMB;
5048     }
5049
5050     /* try to get the vnode for the path name next */
5051     spacep = cm_GetSpace();
5052     /* smb_StripLastComponent will strip "::$DATA" if present */
5053     smb_StripLastComponent(spacep->wdata, NULL, pathp);
5054     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5055     if (code) {
5056         cm_ReleaseUser(userp);
5057         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5058         smb_FreeTran2Packet(outp);
5059         return 0;
5060     }
5061
5062     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
5063                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5064                     userp, tidPathp, &req, &scp);
5065     cm_FreeSpace(spacep);
5066
5067     if (code) {
5068         cm_ReleaseUser(userp);
5069         smb_SendTran2Error(vcp, p, opx, code);
5070         smb_FreeTran2Packet(outp);
5071         return 0;
5072     }
5073
5074 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5075     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5076         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5077         cm_ReleaseSCache(scp);
5078         cm_ReleaseUser(userp);
5079         if ( WANTS_DFS_PATHNAMES(p) || pnc )
5080             code = CM_ERROR_PATH_NOT_COVERED;
5081         else
5082             code = CM_ERROR_NOSUCHPATH;
5083         smb_SendTran2Error(vcp, p, opx, code);
5084         smb_FreeTran2Packet(outp);
5085         return 0;
5086     }
5087 #endif /* DFS_SUPPORT */
5088     osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
5089
5090     afs_ioctl = (cm_ClientStrCmpI(maskp, CM_IOCTL_FILENAME_NOSLASH_W) == 0);
5091
5092     /*
5093      * If we are not searching for _._AFS_IOCTL_._, then we need to obtain
5094      * the target scp.
5095      */
5096     if (!afs_ioctl) {
5097         /* now do a single case sensitive lookup for the file in question */
5098         code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetScp);
5099
5100         /*
5101          * if a case sensitive match failed, we try a case insensitive
5102          * one next.
5103          */
5104         if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)
5105             code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetScp);
5106
5107         if (code == 0 && targetScp->fid.vnode == 0) {
5108             cm_ReleaseSCache(targetScp);
5109             code = CM_ERROR_NOSUCHFILE;
5110         }
5111
5112         if (code) {
5113             /*
5114              * if we can't find the directory entry, this block will
5115              * return CM_ERROR_NOSUCHFILE, which we will pass on to
5116              * smb_ReceiveTran2SearchDir().
5117              */
5118             cm_ReleaseSCache(scp);
5119             cm_ReleaseUser(userp);
5120             if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5121                 smb_SendTran2Error(vcp, p, opx, code);
5122                 code = 0;
5123             }
5124             smb_FreeTran2Packet(outp);
5125             return code;
5126         }
5127     }
5128
5129     /* now that we have the target in sight, we proceed with filling
5130        up the return data. */
5131
5132     op = origOp = outp->datap;
5133     bytesInBuffer = 0;
5134
5135     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5136         /* skip over resume key */
5137         op += 4;
5138     }
5139
5140     fp = (smb_tran2Find_t *) op;
5141
5142     if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
5143         && !cm_Is8Dot3(maskp)) {
5144
5145         /*
5146          * Since the _._AFS_IOCTL_._ file does not actually exist
5147          * we will make up a per directory FID equivalent to the
5148          * directory vnode and the uniqifier 0.
5149          */
5150         if (afs_ioctl) {
5151             dfid.vnode = htonl(scp->fid.vnode);
5152             dfid.unique = htonl(0);
5153         } else {
5154             dfid.vnode = htonl(targetScp->fid.vnode);
5155             dfid.unique = htonl(targetScp->fid.unique);
5156         }
5157
5158         cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
5159         NeedShortName = 1;
5160     } else {
5161         NeedShortName = 0;
5162     }
5163
5164     osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
5165              ntohl(dfid.vnode),
5166              ntohl(dfid.unique),
5167              osi_LogSaveClientString(smb_logp, pathp),
5168              (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5169
5170     /* Eliminate entries that don't match requested attributes */
5171     if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
5172         smb_IsDotFile(maskp)) {
5173
5174         code = CM_ERROR_NOSUCHFILE;
5175         osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
5176         goto skip_file;
5177
5178     }
5179
5180     if (!(attribute & SMB_ATTR_DIRECTORY) &&
5181         !afs_ioctl &&
5182         (targetScp->fileType == CM_SCACHETYPE_DIRECTORY ||
5183          targetScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
5184          targetScp->fileType == CM_SCACHETYPE_DFSLINK ||
5185          targetScp->fileType == CM_SCACHETYPE_INVALID)) {
5186
5187         code = CM_ERROR_NOSUCHFILE;
5188         osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
5189         goto skip_file;
5190
5191     }
5192
5193     /* add header to name & term. null */
5194     onbytes = 0;
5195     smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5196     orbytes = ohbytes + onbytes;
5197
5198     /* now, we round up the record to a 4 byte alignment, and we make
5199      * sure that we have enough room here for even the aligned version
5200      * (so we don't have to worry about an * overflow when we pad
5201      * things out below).  That's the reason for the alignment
5202      * arithmetic below.
5203      */
5204     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5205         align = (4 - (orbytes & 3)) & 3;
5206     else
5207         align = 0;
5208
5209     if (orbytes + align > maxReturnData) {
5210
5211         /* even though this request is unlikely to succeed with a
5212            failover, we do it anyway. */
5213         code = CM_ERROR_NOSUCHFILE;
5214         osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5215                  maxReturnData);
5216         goto skip_file;
5217     }
5218
5219     /* this is one of the entries to use: it is not deleted and it
5220      * matches the star pattern we're looking for.  Put out the name,
5221      * preceded by its length.
5222      */
5223     /* First zero everything else */
5224     memset(origOp, 0, orbytes);
5225
5226     onbytes = 0;
5227     smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5228
5229     switch (infoLevel) {
5230     case SMB_INFO_STANDARD:
5231         fp->u.FstandardInfo.fileNameLength = onbytes;
5232         attrp = &fp->u.FstandardInfo.fileAttrs;
5233         break;
5234
5235     case SMB_INFO_QUERY_EA_SIZE:
5236         fp->u.FeaSizeInfo.fileNameLength = onbytes;
5237         attrp = &fp->u.FeaSizeInfo.fileAttrs;
5238         fp->u.FeaSizeInfo.eaSize = 0;
5239         break;
5240
5241     case SMB_INFO_QUERY_EAS_FROM_LIST:
5242         fp->u.FeasFromListInfo.fileNameLength = onbytes;
5243         attrp = &fp->u.FeasFromListInfo.fileAttrs;
5244         fp->u.FeasFromListInfo.eaSize = 0;
5245         break;
5246
5247     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5248         if (NeedShortName) {
5249 #ifdef SMB_UNICODE
5250             int nchars;
5251
5252             nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5253                                             fp->u.FfileBothDirectoryInfo.shortName,
5254                                             sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5255             if (nchars > 0)
5256                 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5257             else
5258                 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5259             fp->u.FfileBothDirectoryInfo.reserved = 0;
5260 #else
5261             strcpy(fp->u.FfileBothDirectoryInfo.shortName,
5262                    shortName);
5263             fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5264 #endif
5265     }
5266         /* Fallthrough */
5267
5268     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5269         fp->u.FfileFullDirectoryInfo.eaSize = 0;
5270         /* Fallthrough */
5271
5272     case SMB_FIND_FILE_DIRECTORY_INFO:
5273         fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
5274         fp->u.FfileDirectoryInfo.fileIndex = 0;
5275         attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5276         fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5277         break;
5278
5279     case SMB_FIND_FILE_NAMES_INFO:
5280         fp->u.FfileNamesInfo.nextEntryOffset = 0;
5281         fp->u.FfileNamesInfo.fileIndex = 0;
5282         fp->u.FfileNamesInfo.fileNameLength = onbytes;
5283         break;
5284
5285     default:
5286         /* we shouldn't hit this case */
5287         osi_assertx(FALSE, "Unknown query type");
5288     }
5289
5290     if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5291         osi_assert(attrp != NULL);
5292
5293         curPatchp = malloc(sizeof(*curPatchp));
5294         osi_QAdd((osi_queue_t **) &dirListPatchesp,
5295                  &curPatchp->q);
5296         curPatchp->dptr = attrp;
5297
5298         if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
5299             curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5300         } else {
5301             curPatchp->flags = 0;
5302         }
5303
5304         /* temp */
5305         {
5306             int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
5307             dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
5308             cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
5309         }
5310
5311         if (afs_ioctl) {
5312             cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, scp->fid.vnode, 0);
5313             dep->fid.vnode = scp->fid.vnode;
5314             dep->fid.unique = 0;
5315             curPatchp->flags |= SMB_DIRLISTPATCH_IOCTL;
5316         } else {
5317             cm_SetFid(&curPatchp->fid, targetScp->fid.cell, targetScp->fid.volume, targetScp->fid.vnode, targetScp->fid.unique);
5318             dep->fid.vnode = targetScp->fid.vnode;
5319             dep->fid.unique = targetScp->fid.unique;
5320         }
5321
5322         curPatchp->dep = dep;
5323     }
5324
5325     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5326         /* put out resume key */
5327         *((u_long *)origOp) = 0;
5328     }
5329
5330     /* Adjust byte ptr and count */
5331     origOp += orbytes;  /* skip entire record */
5332     bytesInBuffer += orbytes;
5333
5334     /* and pad the record out */
5335     while (--align >= 0) {
5336         *origOp++ = 0;
5337         bytesInBuffer++;
5338     }
5339
5340     /* apply the patches */
5341     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
5342
5343     outp->parmsp[0] = 0;
5344     outp->parmsp[1] = 1;        /* number of names returned */
5345     outp->parmsp[2] = 1;        /* end of search */
5346     outp->parmsp[3] = 0;        /* nothing wrong with EAS */
5347     outp->parmsp[4] = 0;
5348
5349     outp->totalParms = 10;      /* in bytes */
5350
5351     outp->totalData = bytesInBuffer;
5352
5353     osi_Log0(smb_logp, "T2SDSingle done.");
5354
5355     if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5356         if (code)
5357             smb_SendTran2Error(vcp, p, opx, code);
5358         else
5359             smb_SendTran2Packet(vcp, outp, opx);
5360         code = 0;
5361     }
5362
5363  skip_file:
5364     smb_FreeTran2Packet(outp);
5365     if (dep)
5366         free(dep);
5367     if (scp)
5368         cm_ReleaseSCache(scp);
5369     if (targetScp)
5370         cm_ReleaseSCache(targetScp);
5371     cm_ReleaseUser(userp);
5372
5373     return code;
5374 }
5375
5376
5377 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
5378 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
5379 {
5380     int attribute;
5381     long nextCookie;
5382     char *tp;
5383     long code = 0, code2 = 0;
5384     clientchar_t *pathp;
5385     cm_dirEntry_t *dep = 0;
5386     int maxCount;
5387     smb_dirListPatch_t *dirListPatchesp = 0;
5388     smb_dirListPatch_t *curPatchp = 0;
5389     cm_buf_t *bufferp;
5390     long temp;
5391     size_t orbytes;                     /* # of bytes in this output record */
5392     size_t ohbytes;                     /* # of bytes, except file name */
5393     size_t onbytes;                     /* # of bytes in name, incl. term. null */
5394     osi_hyper_t dirLength;
5395     osi_hyper_t bufferOffset;
5396     osi_hyper_t curOffset;
5397     osi_hyper_t thyper;
5398     smb_dirSearch_t *dsp;
5399     cm_scache_t *scp;
5400     long entryInDir;
5401     long entryInBuffer;
5402     cm_pageHeader_t *pageHeaderp;
5403     cm_user_t *userp = NULL;
5404     int slotInPage;
5405     int returnedNames;
5406     long nextEntryCookie;
5407     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
5408     char *op;                   /* output data ptr */
5409     char *origOp;                       /* original value of op */
5410     cm_space_t *spacep;         /* for pathname buffer */
5411     unsigned long maxReturnData;                /* max # of return data */
5412     unsigned long maxReturnParms;               /* max # of return parms */
5413     long bytesInBuffer;         /* # data bytes in the output buffer */
5414     int starPattern;
5415     clientchar_t *maskp;                        /* mask part of path */
5416     int infoLevel;
5417     int searchFlags;
5418     int eos;
5419     smb_tran2Packet_t *outp;    /* response packet */
5420     clientchar_t *tidPathp;
5421     unsigned int align;
5422     clientchar_t shortName[13];         /* 8.3 name if needed */
5423     int NeedShortName;
5424     int foundInexact;
5425     clientchar_t *shortNameEnd;
5426     int fileType;
5427     cm_fid_t fid;
5428     cm_req_t req;
5429     void * attrp;
5430     char * s;
5431     smb_tran2Find_t * fp;
5432
5433     smb_InitReq(&req);
5434
5435     eos = 0;
5436     if (p->opcode == 1) {
5437         /* find first; obtain basic parameters from request */
5438         attribute = p->parmsp[0];
5439         maxCount = p->parmsp[1];
5440         infoLevel = p->parmsp[3];
5441         searchFlags = p->parmsp[2];
5442         pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
5443         nextCookie = 0;
5444         maskp = cm_ClientStrRChr(pathp,  '\\');
5445         if (maskp == NULL)
5446             maskp = pathp;
5447         else
5448             maskp++;    /* skip over backslash */
5449
5450         /* track if this is likely to match a lot of entries */
5451         starPattern = smb_V3IsStarMask(maskp);
5452
5453 #ifndef NOFINDFIRSTOPTIMIZE
5454         if (!starPattern) {
5455             /* if this is for a single directory or file, we let the
5456                optimized routine handle it.  The only error it
5457                returns is CM_ERROR_NOSUCHFILE.  The  */
5458             code = smb_T2SearchDirSingle(vcp, p, opx);
5459
5460             /* we only failover if we see a CM_ERROR_NOSUCHFILE */
5461             if (code != CM_ERROR_NOSUCHFILE) {
5462 #ifdef USE_BPLUS
5463                 /* unless we are using the BPlusTree */
5464                 if (code == CM_ERROR_BPLUS_NOMATCH)
5465                     code = CM_ERROR_NOSUCHFILE;
5466 #endif /* USE_BPLUS */
5467                 return code;
5468             }
5469         }
5470 #endif  /* NOFINDFIRSTOPTIMIZE */
5471         dir_enums++;
5472
5473         dsp = smb_NewDirSearch(1);
5474         dsp->attribute = attribute;
5475         cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask),  maskp);        /* and save mask */
5476     }
5477     else {
5478         osi_assertx(p->opcode == 2, "invalid opcode");
5479         /* find next; obtain basic parameters from request or open dir file */
5480         dsp = smb_FindDirSearch(p->parmsp[0]);
5481         maxCount = p->parmsp[1];
5482         infoLevel = p->parmsp[2];
5483         nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
5484         searchFlags = p->parmsp[5];
5485         if (!dsp) {
5486             osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
5487                      p->parmsp[0], nextCookie);
5488             return CM_ERROR_BADFD;
5489         }
5490         attribute = dsp->attribute;
5491         pathp = NULL;
5492         maskp = dsp->mask;
5493         starPattern = 1;        /* assume, since required a Find Next */
5494     }
5495
5496     switch ( infoLevel ) {
5497     case SMB_INFO_STANDARD:
5498         s = "InfoStandard";
5499         ohbytes = sizeof(fp->u.FstandardInfo);
5500         break;
5501
5502     case SMB_INFO_QUERY_EA_SIZE:
5503         ohbytes = sizeof(fp->u.FeaSizeInfo);
5504         s = "InfoQueryEaSize";
5505         break;
5506
5507     case SMB_INFO_QUERY_EAS_FROM_LIST:
5508         ohbytes = sizeof(fp->u.FeasFromListInfo);
5509         s = "InfoQueryEasFromList";
5510         break;
5511
5512     case SMB_FIND_FILE_DIRECTORY_INFO:
5513         s = "FindFileDirectoryInfo";
5514         ohbytes = sizeof(fp->u.FfileDirectoryInfo);
5515         break;
5516
5517     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5518         s = "FindFileFullDirectoryInfo";
5519         ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
5520         break;
5521
5522     case SMB_FIND_FILE_NAMES_INFO:
5523         s = "FindFileNamesInfo";
5524         ohbytes = sizeof(fp->u.FfileNamesInfo);
5525         break;
5526
5527     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5528         s = "FindFileBothDirectoryInfo";
5529         ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
5530         break;
5531
5532     default:
5533         s = "unknownInfoLevel";
5534         ohbytes = 0;
5535     }
5536
5537     osi_Log1(smb_logp, "T2 search dir info level: %s", s);
5538
5539     osi_Log4(smb_logp,
5540               "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
5541               attribute, infoLevel, maxCount, searchFlags);
5542
5543     osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
5544               p->opcode, dsp->cookie, nextCookie);
5545
5546     if (ohbytes == 0) {
5547         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
5548         smb_ReleaseDirSearch(dsp);
5549         return CM_ERROR_INVAL;
5550     }
5551
5552     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5553         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;     /* no resume keys */
5554
5555     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5556         ohbytes += 4;
5557
5558     dirListPatchesp = NULL;
5559
5560     maxReturnData = p->maxReturnData;
5561     if (p->opcode == 1) /* find first */
5562         maxReturnParms = 10;    /* bytes */
5563     else
5564         maxReturnParms = 8;     /* bytes */
5565
5566     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
5567                                       maxReturnData);
5568
5569     if (maxCount > 500)
5570         maxCount = 500;
5571
5572     osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
5573              maxCount, osi_LogSaveClientString(smb_logp, pathp));
5574
5575     /* bail out if request looks bad */
5576     if (p->opcode == 1 && !pathp) {
5577         smb_ReleaseDirSearch(dsp);
5578         smb_FreeTran2Packet(outp);
5579         return CM_ERROR_BADSMB;
5580     }
5581
5582     osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
5583              dsp->cookie, nextCookie, attribute);
5584
5585     userp = smb_GetTran2User(vcp, p);
5586     if (!userp) {
5587         osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
5588         smb_ReleaseDirSearch(dsp);
5589         smb_FreeTran2Packet(outp);
5590         return CM_ERROR_BADSMB;
5591     }
5592
5593     /* try to get the vnode for the path name next */
5594     lock_ObtainMutex(&dsp->mx);
5595     if (dsp->scp) {
5596         scp = dsp->scp;
5597         osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5598         cm_HoldSCache(scp);
5599         code = 0;
5600     } else {
5601         spacep = cm_GetSpace();
5602         /* smb_StripLastComponent will strip "::$DATA" if present */
5603         smb_StripLastComponent(spacep->wdata, NULL, pathp);
5604         code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
5605         if (code) {
5606             cm_ReleaseUser(userp);
5607             smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
5608             smb_FreeTran2Packet(outp);
5609             lock_ReleaseMutex(&dsp->mx);
5610             smb_DeleteDirSearch(dsp);
5611             smb_ReleaseDirSearch(dsp);
5612             return 0;
5613         }
5614
5615         cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
5616         cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
5617
5618         code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
5619                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5620                         userp, tidPathp, &req, &scp);
5621         cm_FreeSpace(spacep);
5622
5623         if (code == 0) {
5624 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5625             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5626                 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5627                 cm_ReleaseSCache(scp);
5628                 cm_ReleaseUser(userp);
5629                 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5630                     code = CM_ERROR_PATH_NOT_COVERED;
5631                 else
5632                     code = CM_ERROR_NOSUCHPATH;
5633                 smb_SendTran2Error(vcp, p, opx, code);
5634                 smb_FreeTran2Packet(outp);
5635                 lock_ReleaseMutex(&dsp->mx);
5636                 smb_DeleteDirSearch(dsp);
5637                 smb_ReleaseDirSearch(dsp);
5638                 return 0;
5639             }
5640 #endif /* DFS_SUPPORT */
5641             dsp->scp = scp;
5642             osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5643             /* we need one hold for the entry we just stored into,
5644              * and one for our own processing.  When we're done
5645              * with this function, we'll drop the one for our own
5646              * processing.  We held it once from the namei call,
5647              * and so we do another hold now.
5648              */
5649             cm_HoldSCache(scp);
5650             dsp->flags |= SMB_DIRSEARCH_BULKST;
5651         }
5652     }
5653     lock_ReleaseMutex(&dsp->mx);
5654     if (code) {
5655         cm_ReleaseUser(userp);
5656         smb_FreeTran2Packet(outp);
5657         smb_DeleteDirSearch(dsp);
5658         smb_ReleaseDirSearch(dsp);
5659         return code;
5660     }
5661
5662     /* get the directory size */
5663     lock_ObtainWrite(&scp->rw);
5664     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5665                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5666     if (code) {
5667         lock_ReleaseWrite(&scp->rw);
5668         cm_ReleaseSCache(scp);
5669         cm_ReleaseUser(userp);
5670         smb_FreeTran2Packet(outp);
5671         smb_DeleteDirSearch(dsp);
5672         smb_ReleaseDirSearch(dsp);
5673         return code;
5674     }
5675
5676     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5677
5678   startsearch:
5679     dirLength = scp->length;
5680     bufferp = NULL;
5681     bufferOffset.LowPart = bufferOffset.HighPart = 0;
5682     curOffset.HighPart = 0;
5683     curOffset.LowPart = nextCookie;
5684     origOp = outp->datap;
5685
5686     foundInexact = 0;
5687     code = 0;
5688     returnedNames = 0;
5689     bytesInBuffer = 0;
5690     while (1) {
5691         normchar_t normName[MAX_PATH]; /* Normalized name */
5692         clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5693
5694         op = origOp;
5695         if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5696             /* skip over resume key */
5697             op += 4;
5698
5699         fp = (smb_tran2Find_t *) op;
5700
5701         /* make sure that curOffset.LowPart doesn't point to the first
5702          * 32 bytes in the 2nd through last dir page, and that it doesn't
5703          * point at the first 13 32-byte chunks in the first dir page,
5704          * since those are dir and page headers, and don't contain useful
5705          * information.
5706          */
5707         temp = curOffset.LowPart & (2048-1);
5708         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5709             /* we're in the first page */
5710             if (temp < 13*32) temp = 13*32;
5711         }
5712         else {
5713             /* we're in a later dir page */
5714             if (temp < 32) temp = 32;
5715         }
5716
5717         /* make sure the low order 5 bits are zero */
5718         temp &= ~(32-1);
5719
5720         /* now put temp bits back ito curOffset.LowPart */
5721         curOffset.LowPart &= ~(2048-1);
5722         curOffset.LowPart |= temp;
5723
5724         /* check if we've passed the dir's EOF */
5725         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5726             osi_Log0(smb_logp, "T2 search dir passed eof");
5727             eos = 1;
5728             break;
5729         }
5730
5731         /* check if we've returned all the names that will fit in the
5732          * response packet; we check return count as well as the number
5733          * of bytes requested.  We check the # of bytes after we find
5734          * the dir entry, since we'll need to check its size.
5735          */
5736         if (returnedNames >= maxCount) {
5737             osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5738                       returnedNames, maxCount);
5739             break;
5740         }
5741
5742         /* when we have obtained as many entries as can be processed in
5743          * a single Bulk Status call to the file server, apply the dir listing
5744          * patches.
5745          */
5746         if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5747             lock_ReleaseWrite(&scp->rw);
5748             code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5749                                                dsp->relPath, infoLevel, userp, &req);
5750             lock_ObtainWrite(&scp->rw);
5751         }
5752         /* Then check to see if we have time left to process more entries */
5753         if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5754             osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5755             break;
5756         }
5757
5758         /* see if we can use the bufferp we have now; compute in which
5759          * page the current offset would be, and check whether that's
5760          * the offset of the buffer we have.  If not, get the buffer.
5761          */
5762         thyper.HighPart = curOffset.HighPart;
5763         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5764         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5765             /* wrong buffer */
5766             if (bufferp) {
5767                 buf_Release(bufferp);
5768                 bufferp = NULL;
5769             }
5770             lock_ReleaseWrite(&scp->rw);
5771             code = buf_Get(scp, &thyper, &req, &bufferp);
5772             lock_ObtainWrite(&scp->rw);
5773             if (code) {
5774                 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5775                 break;
5776             }
5777
5778             bufferOffset = thyper;
5779
5780             /* now get the data in the cache */
5781             while (1) {
5782                 code = cm_SyncOp(scp, bufferp, userp, &req,
5783                                  PRSFS_LOOKUP,
5784                                  CM_SCACHESYNC_NEEDCALLBACK
5785                                  | CM_SCACHESYNC_READ);
5786                 if (code) {
5787                     osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5788                     break;
5789                 }
5790
5791                 if (cm_HaveBuffer(scp, bufferp, 0)) {
5792                     osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5793                     cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5794                     break;
5795                 }
5796
5797                 /* otherwise, load the buffer and try again */
5798                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5799                                     &req);
5800                 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5801                 if (code) {
5802                     osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5803                               scp, bufferp, code);
5804                     break;
5805                 }
5806             }
5807             if (code) {
5808                 buf_Release(bufferp);
5809                 bufferp = NULL;
5810                 break;
5811             }
5812         }       /* if (wrong buffer) ... */
5813
5814         /* now we have the buffer containing the entry we're interested
5815          * in; copy it out if it represents a non-deleted entry.
5816          */
5817         entryInDir = curOffset.LowPart & (2048-1);
5818         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5819
5820         /* page header will help tell us which entries are free.  Page
5821          * header can change more often than once per buffer, since
5822          * AFS 3 dir page size may be less than (but not more than)
5823          * a buffer package buffer.
5824          */
5825         /* only look intra-buffer */
5826         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5827         temp &= ~(2048 - 1);    /* turn off intra-page bits */
5828         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5829
5830         /* now determine which entry we're looking at in the page.
5831          * If it is free (there's a free bitmap at the start of the
5832          * dir), we should skip these 32 bytes.
5833          */
5834         slotInPage = (entryInDir & 0x7e0) >> 5;
5835         if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5836             (1 << (slotInPage & 0x7)))) {
5837             /* this entry is free */
5838             numDirChunks = 1;   /* only skip this guy */
5839             goto nextEntry;
5840         }
5841
5842         tp = bufferp->datap + entryInBuffer;
5843         dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
5844
5845         /* while we're here, compute the next entry's location, too,
5846          * since we'll need it when writing out the cookie into the dir
5847          * listing stream.
5848          *
5849          * XXXX Probably should do more sanity checking.
5850          */
5851         numDirChunks = cm_NameEntries(dep->name, &onbytes);
5852
5853         /* compute offset of cookie representing next entry */
5854         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5855
5856         if (dep->fid.vnode == 0)
5857             goto nextEntry;             /* This entry is not in use */
5858
5859         if (cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName)) == 0 ||
5860             cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName)) == 0) {
5861
5862             osi_Log1(smb_logp, "Skipping entry [%s].  Can't convert or normalize FS String",
5863                      osi_LogSaveString(smb_logp, dep->name));
5864             goto nextEntry;
5865         }
5866
5867         /* Need 8.3 name? */
5868         NeedShortName = 0;
5869         if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO &&
5870             !cm_Is8Dot3(cfileName)) {
5871             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5872             NeedShortName = 1;
5873         }
5874
5875         osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5876                  dep->fid.vnode, dep->fid.unique,
5877                  osi_LogSaveClientString(smb_logp, cfileName),
5878                  NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5879
5880         /* When matching, we are using doing a case fold if we have a wildcard mask.
5881          * If we get a non-wildcard match, it's a lookup for a specific file.
5882          */
5883         if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5884             (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))
5885         {
5886             /* Eliminate entries that don't match requested attributes */
5887             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) &&
5888                 smb_IsDotFile(cfileName)) {
5889                 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5890                 goto nextEntry; /* no hidden files */
5891             }
5892
5893             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
5894             {
5895                 /* We have already done the cm_TryBulkStat above */
5896                 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5897                           ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5898                 fileType = cm_FindFileType(&fid);
5899                 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5900                  * "has filetype %d", dep->name, fileType);
5901                  */
5902                 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5903                      fileType == CM_SCACHETYPE_MOUNTPOINT ||
5904                      fileType == CM_SCACHETYPE_DFSLINK ||
5905                      fileType == CM_SCACHETYPE_INVALID)
5906                     osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5907                 goto nextEntry;
5908             }
5909
5910             /* finally check if this name will fit */
5911             onbytes = 0;
5912             smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5913             orbytes = ohbytes + onbytes;
5914
5915             /* now, we round up the record to a 4 byte alignment,
5916              * and we make sure that we have enough room here for
5917              * even the aligned version (so we don't have to worry
5918              * about an overflow when we pad things out below).
5919              * That's the reason for the alignment arithmetic below.
5920              */
5921             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5922                 align = (4 - (orbytes & 3)) & 3;
5923             else
5924                 align = 0;
5925
5926             if (orbytes + bytesInBuffer + align > maxReturnData) {
5927                 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5928                          maxReturnData);
5929                 break;
5930             }
5931
5932             /* this is one of the entries to use: it is not deleted
5933              * and it matches the star pattern we're looking for.
5934              * Put out the name, preceded by its length.
5935              */
5936             /* First zero everything else */
5937             memset(origOp, 0, orbytes);
5938
5939             onbytes = 0;
5940             smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5941
5942             switch (infoLevel) {
5943             case SMB_INFO_STANDARD:
5944                 fp->u.FstandardInfo.fileNameLength = onbytes;
5945                 attrp = &fp->u.FstandardInfo.fileAttrs;
5946                 break;
5947
5948             case SMB_INFO_QUERY_EA_SIZE:
5949                 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5950                 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5951                 fp->u.FeaSizeInfo.eaSize = 0;
5952                 break;
5953
5954             case SMB_INFO_QUERY_EAS_FROM_LIST:
5955                 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5956                 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5957                 fp->u.FeasFromListInfo.eaSize = 0;
5958                 break;
5959
5960             case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5961                 if (NeedShortName) {
5962 #ifdef SMB_UNICODE
5963                     int nchars;
5964
5965                     nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5966                                                     fp->u.FfileBothDirectoryInfo.shortName,
5967                                                     sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5968                     if (nchars > 0)
5969                         fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5970                     else
5971                         fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5972                     fp->u.FfileBothDirectoryInfo.reserved = 0;
5973 #else
5974                     cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5975                                     lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5976                                     shortName);
5977                     fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5978 #endif
5979                 }
5980                 /* Fallthrough */
5981
5982             case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5983                 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5984                 /* Fallthrough */
5985
5986             case SMB_FIND_FILE_DIRECTORY_INFO:
5987                 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5988                 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5989                 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5990                 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5991                 break;
5992
5993             case SMB_FIND_FILE_NAMES_INFO:
5994                 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5995                 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5996                 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5997                 attrp = NULL;
5998                 break;
5999
6000             default:
6001                 /* we shouldn't hit this case */
6002                 osi_assertx(FALSE, "Unknown query type");
6003             }
6004
6005             /* now, adjust the # of entries copied */
6006             returnedNames++;
6007
6008             /* now we emit the attribute.  This is tricky, since
6009              * we need to really stat the file to find out what
6010              * type of entry we've got.  Right now, we're copying
6011              * out data from a buffer, while holding the scp
6012              * locked, so it isn't really convenient to stat
6013              * something now.  We'll put in a place holder
6014              * now, and make a second pass before returning this
6015              * to get the real attributes.  So, we just skip the
6016              * data for now, and adjust it later.  We allocate a
6017              * patch record to make it easy to find this point
6018              * later.  The replay will happen at a time when it is
6019              * safe to unlock the directory.
6020              */
6021             if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
6022                 osi_assert(attrp != NULL);
6023                 curPatchp = malloc(sizeof(*curPatchp));
6024                 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
6025                 curPatchp->dptr = attrp;
6026
6027                 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
6028                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
6029                 } else {
6030                     curPatchp->flags = 0;
6031                 }
6032
6033                 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
6034
6035                 /* temp */
6036                 curPatchp->dep = dep;
6037             }
6038
6039             if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
6040                 /* put out resume key */
6041                 *((u_long *)origOp) = nextEntryCookie;
6042
6043             /* Adjust byte ptr and count */
6044             origOp += orbytes;  /* skip entire record */
6045             bytesInBuffer += orbytes;
6046
6047             /* and pad the record out */
6048             while (align-- > 0) {
6049                 *origOp++ = 0;
6050                 bytesInBuffer++;
6051             }
6052         }       /* if we're including this name */
6053         else if (!starPattern &&
6054                  !foundInexact &&
6055                  cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
6056             /* We were looking for exact matches, but here's an inexact one*/
6057             foundInexact = 1;
6058         }
6059
6060       nextEntry:
6061         /* and adjust curOffset to be where the new cookie is */
6062         thyper.HighPart = 0;
6063         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
6064         curOffset = LargeIntegerAdd(thyper, curOffset);
6065     } /* while copying data for dir listing */
6066
6067     /* If we didn't get a star pattern, we did an exact match during the first pass.
6068      * If there were no exact matches found, we fail over to inexact matches by
6069      * marking the query as a star pattern (matches all case permutations), and
6070      * re-running the query.
6071      */
6072     if (returnedNames == 0 && !starPattern && foundInexact) {
6073         osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
6074         starPattern = 1;
6075         goto startsearch;
6076     }
6077
6078     /* release the mutex */
6079     lock_ReleaseWrite(&scp->rw);
6080     if (bufferp) {
6081         buf_Release(bufferp);
6082         bufferp = NULL;
6083     }
6084
6085     /*
6086      * Finally, process whatever entries we have left.
6087      */
6088     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
6089                                       dsp->relPath, infoLevel, userp, &req);
6090
6091     /* now put out the final parameters */
6092     if (returnedNames == 0)
6093         eos = 1;
6094     if (p->opcode == 1) {
6095         /* find first */
6096         outp->parmsp[0] = (unsigned short) dsp->cookie;
6097         outp->parmsp[1] = returnedNames;
6098         outp->parmsp[2] = eos;
6099         outp->parmsp[3] = 0;            /* nothing wrong with EAS */
6100         outp->parmsp[4] = 0;
6101         /* don't need last name to continue
6102          * search, cookie is enough.  Normally,
6103          * this is the offset of the file name
6104          * of the last entry returned.
6105          */
6106         outp->totalParms = 10;  /* in bytes */
6107     }
6108     else {
6109         /* find next */
6110         outp->parmsp[0] = returnedNames;
6111         outp->parmsp[1] = eos;
6112         outp->parmsp[2] = 0;    /* EAS error */
6113         outp->parmsp[3] = 0;    /* last name, as above */
6114         outp->totalParms = 8;   /* in bytes */
6115     }
6116
6117     /* return # of bytes in the buffer */
6118     outp->totalData = bytesInBuffer;
6119
6120     /* Return error code if unsuccessful on first request */
6121     if (code == 0 && p->opcode == 1 && returnedNames == 0)
6122         code = CM_ERROR_NOSUCHFILE;
6123
6124     osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
6125              p->opcode, dsp->cookie, returnedNames, code);
6126
6127     /* if we're supposed to close the search after this request, or if
6128      * we're supposed to close the search if we're done, and we're done,
6129      * or if something went wrong, close the search.
6130      */
6131     if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) ||
6132         (returnedNames == 0) ||
6133         ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) ||
6134         code != 0)
6135         smb_DeleteDirSearch(dsp);
6136
6137     if (code)
6138         smb_SendTran2Error(vcp, p, opx, code);
6139     else
6140         smb_SendTran2Packet(vcp, outp, opx);
6141
6142     smb_FreeTran2Packet(outp);
6143     smb_ReleaseDirSearch(dsp);
6144     cm_ReleaseSCache(scp);
6145     cm_ReleaseUser(userp);
6146     return 0;
6147 }
6148
6149 /* SMB_COM_FIND_CLOSE2 */
6150 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6151 {
6152     int dirHandle;
6153     smb_dirSearch_t *dsp;
6154
6155     dirHandle = smb_GetSMBParm(inp, 0);
6156
6157     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
6158
6159     dsp = smb_FindDirSearch(dirHandle);
6160
6161     if (!dsp)
6162         return CM_ERROR_BADFD;
6163
6164     /* otherwise, we have an FD to destroy */
6165     smb_DeleteDirSearch(dsp);
6166     smb_ReleaseDirSearch(dsp);
6167
6168     /* and return results */
6169     smb_SetSMBDataLength(outp, 0);
6170
6171     return 0;
6172 }
6173
6174
6175 /* SMB_COM_FIND_NOTIFY_CLOSE */
6176 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6177 {
6178     smb_SetSMBDataLength(outp, 0);
6179     return 0;
6180 }
6181
6182 /* SMB_COM_OPEN_ANDX */
6183 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6184 {
6185     clientchar_t *pathp;
6186     long code = 0;
6187     cm_space_t *spacep;
6188     int excl;
6189     cm_user_t *userp;
6190     cm_scache_t *dscp;          /* dir we're dealing with */
6191     cm_scache_t *scp;           /* file we're creating */
6192     cm_attr_t setAttr;
6193     smb_fid_t *fidp;
6194     int attributes;
6195     clientchar_t *lastNamep;
6196     unsigned long dosTime;
6197     int openFun;
6198     int trunc;
6199     int openMode;
6200     int extraInfo;
6201     int openAction;
6202     int parmSlot;                       /* which parm we're dealing with */
6203     clientchar_t *tidPathp;
6204     cm_req_t req;
6205     int created = 0;
6206     BOOL is_rpc = FALSE;
6207     BOOL is_ipc = FALSE;
6208
6209     smb_InitReq(&req);
6210
6211     scp = NULL;
6212
6213     extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
6214     openFun = smb_GetSMBParm(inp, 8); /* open function */
6215     excl = ((openFun & 3) == 0);
6216     trunc = ((openFun & 3) == 2); /* truncate it */
6217     openMode = (smb_GetSMBParm(inp, 3) & 0x7);
6218     openAction = 0;             /* tracks what we did */
6219
6220     attributes = smb_GetSMBParm(inp, 5);
6221     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
6222
6223     pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
6224                                 SMB_STRF_ANSIPATH);
6225     if (!pathp)
6226         return CM_ERROR_BADSMB;
6227
6228     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6229     if (code) {
6230         if (code == CM_ERROR_TIDIPC) {
6231             is_ipc = TRUE;
6232         } else {
6233             return CM_ERROR_NOSUCHPATH;
6234         }
6235     }
6236
6237     spacep = inp->spacep;
6238     /* smb_StripLastComponent will strip "::$DATA" if present */
6239     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6240
6241     if (lastNamep &&
6242
6243         /* special case magic file name for receiving IOCTL requests
6244          * (since IOCTL calls themselves aren't getting through).
6245          */
6246         (cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
6247
6248          /* Or an RPC endpoint (is_rpc = TRUE assignment is intentional) */
6249          (is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)))) {
6250
6251         unsigned short file_type = 0;
6252         unsigned short device_state = 0;
6253
6254         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6255         if (is_rpc) {
6256             code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
6257             osi_Log1(smb_logp, "OpenAndX Setting up RPC on fid[%d]", fidp->fid);
6258             if (code) {
6259                 osi_Log1(smb_logp, "smb_SetupRPCFid failure code [%d]", code);
6260                 smb_ReleaseFID(fidp);
6261                 return code;
6262             }
6263         } else {
6264             smb_SetupIoctlFid(fidp, spacep);
6265             osi_Log1(smb_logp, "OpenAndX Setting up IOCTL on fid[%d]", fidp->fid);
6266         }
6267
6268         /* set inp->fid so that later read calls in same msg can find fid */
6269         inp->fid = fidp->fid;
6270
6271         /* copy out remainder of the parms */
6272         parmSlot = 2;
6273         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6274         if (extraInfo) {
6275             smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
6276             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* mod time */
6277             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6278             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* len */
6279             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
6280             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6281             smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;
6282             smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;
6283         }
6284         /* and the final "always present" stuff */
6285         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
6286         /* next write out the "unique" ID */
6287         smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
6288         smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
6289         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6290         smb_SetSMBDataLength(outp, 0);
6291
6292         /* and clean up fid reference */
6293         smb_ReleaseFID(fidp);
6294         return 0;
6295     }
6296
6297 #ifndef DFS_SUPPORT
6298     if (is_ipc) {
6299         osi_Log0(smb_logp, "NTOpenX rejecting IPC TID");
6300         return CM_ERROR_BADFD;
6301     }
6302 #endif
6303
6304     if (!cm_IsValidClientString(pathp)) {
6305 #ifdef DEBUG
6306         clientchar_t * hexp;
6307
6308         hexp = cm_GetRawCharsAlloc(pathp, -1);
6309         osi_Log1(smb_logp, "NTOpenX rejecting invalid name. [%S]",
6310                  osi_LogSaveClientString(smb_logp, hexp));
6311         if (hexp)
6312             free(hexp);
6313 #else
6314         osi_Log0(smb_logp, "NTOpenX rejecting invalid name");
6315 #endif
6316         return CM_ERROR_BADNTFILENAME;
6317     }
6318
6319 #ifdef DEBUG_VERBOSE
6320     {
6321         char *hexp, *asciip;
6322         asciip = (lastNamep ? lastNamep : pathp );
6323         hexp = osi_HexifyString(asciip);
6324         DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
6325         free(hexp);
6326     }
6327 #endif
6328     userp = smb_GetUserFromVCP(vcp, inp);
6329
6330     dscp = NULL;
6331     code = cm_NameI(cm_RootSCachep(userp, &req), pathp,
6332                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6333                     userp, tidPathp, &req, &scp);
6334
6335 #ifdef DFS_SUPPORT
6336     if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6337         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
6338         cm_ReleaseSCache(scp);
6339         cm_ReleaseUser(userp);
6340         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6341             return CM_ERROR_PATH_NOT_COVERED;
6342         else
6343             return CM_ERROR_NOSUCHPATH;
6344     }
6345 #endif /* DFS_SUPPORT */
6346
6347     if (code != 0) {
6348         if (code == CM_ERROR_NOSUCHFILE ||
6349             code == CM_ERROR_NOSUCHPATH ||
6350             code == CM_ERROR_BPLUS_NOMATCH)
6351             code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
6352                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6353                             userp, tidPathp, &req, &dscp);
6354         if (code) {
6355             cm_ReleaseUser(userp);
6356             return code;
6357         }
6358
6359 #ifdef DFS_SUPPORT
6360         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6361             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6362                                                       spacep->wdata);
6363             cm_ReleaseSCache(dscp);
6364             cm_ReleaseUser(userp);
6365             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6366                 return CM_ERROR_PATH_NOT_COVERED;
6367             else
6368                 return CM_ERROR_NOSUCHPATH;
6369         }
6370 #endif /* DFS_SUPPORT */
6371         /* otherwise, scp points to the parent directory.  Do a lookup,
6372          * and truncate the file if we find it, otherwise we create the
6373          * file.
6374          */
6375         if (!lastNamep)
6376             lastNamep = pathp;
6377         else
6378             lastNamep++;
6379         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
6380                           &req, &scp);
6381         if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6382             cm_ReleaseSCache(dscp);
6383             cm_ReleaseUser(userp);
6384             return code;
6385         }
6386     }
6387
6388     /* if we get here, if code is 0, the file exists and is represented by
6389      * scp.  Otherwise, we have to create it.  The dir may be represented
6390      * by dscp, or we may have found the file directly.  If code is non-zero,
6391      * scp is NULL.
6392      */
6393     if (code == 0) {
6394         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
6395         if (code) {
6396             if (dscp) cm_ReleaseSCache(dscp);
6397             cm_ReleaseSCache(scp);
6398             cm_ReleaseUser(userp);
6399             return code;
6400         }
6401
6402         if (excl) {
6403             /* oops, file shouldn't be there */
6404             if (dscp)
6405                 cm_ReleaseSCache(dscp);
6406             cm_ReleaseSCache(scp);
6407             cm_ReleaseUser(userp);
6408             return CM_ERROR_EXISTS;
6409         }
6410
6411         if (trunc) {
6412             setAttr.mask = CM_ATTRMASK_LENGTH;
6413             setAttr.length.LowPart = 0;
6414             setAttr.length.HighPart = 0;
6415             code = cm_SetAttr(scp, &setAttr, userp, &req);
6416             openAction = 3;     /* truncated existing file */
6417         }
6418         else openAction = 1;    /* found existing file */
6419     }
6420     else if (!(openFun & SMB_ATTR_DIRECTORY)) {
6421         /* don't create if not found */
6422         if (dscp) cm_ReleaseSCache(dscp);
6423         cm_ReleaseUser(userp);
6424         return CM_ERROR_NOSUCHFILE;
6425     }
6426     else {
6427         osi_assertx(dscp != NULL, "null cm_scache_t");
6428         osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
6429                  osi_LogSaveClientString(smb_logp, lastNamep));
6430         openAction = 2; /* created file */
6431         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6432         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
6433         smb_SetInitialModeBitsForFile(attributes, &setAttr);
6434
6435         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6436                          &req);
6437         if (code == 0) {
6438             created = 1;
6439             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6440                 smb_NotifyChange(FILE_ACTION_ADDED,
6441                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6442                                  dscp, lastNamep, NULL, TRUE);
6443         } else if (!excl && code == CM_ERROR_EXISTS) {
6444             /* not an exclusive create, and someone else tried
6445              * creating it already, then we open it anyway.  We
6446              * don't bother retrying after this, since if this next
6447              * fails, that means that the file was deleted after we
6448              * started this call.
6449              */
6450             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6451                              userp, &req, &scp);
6452             if (code == 0) {
6453                 if (trunc) {
6454                     setAttr.mask = CM_ATTRMASK_LENGTH;
6455                     setAttr.length.LowPart = 0;
6456                     setAttr.length.HighPart = 0;
6457                     code = cm_SetAttr(scp, &setAttr, userp, &req);
6458                 }
6459             }   /* lookup succeeded */
6460         }
6461     }
6462
6463     /* we don't need this any longer */
6464     if (dscp)
6465         cm_ReleaseSCache(dscp);
6466
6467     if (code) {
6468         /* something went wrong creating or truncating the file */
6469         if (scp)
6470             cm_ReleaseSCache(scp);
6471         cm_ReleaseUser(userp);
6472         return code;
6473     }
6474
6475     /* make sure we're about to open a file */
6476     if (scp->fileType != CM_SCACHETYPE_FILE) {
6477         cm_ReleaseSCache(scp);
6478         cm_ReleaseUser(userp);
6479         return CM_ERROR_ISDIR;
6480     }
6481
6482     /* now all we have to do is open the file itself */
6483     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6484     osi_assertx(fidp, "null smb_fid_t");
6485
6486     cm_HoldUser(userp);
6487     lock_ObtainMutex(&fidp->mx);
6488     /* save a pointer to the vnode */
6489     fidp->scp = scp;
6490     lock_ObtainWrite(&scp->rw);
6491     scp->flags |= CM_SCACHEFLAG_SMB_FID;
6492     lock_ReleaseWrite(&scp->rw);
6493     osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
6494     /* also the user */
6495     fidp->userp = userp;
6496
6497     /* compute open mode */
6498     if (openMode != 1)
6499         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
6500     if (openMode == 1 || openMode == 2)
6501         fidp->flags |= SMB_FID_OPENWRITE;
6502
6503     /* remember if the file was newly created */
6504     if (created)
6505         fidp->flags |= SMB_FID_CREATED;
6506
6507     lock_ReleaseMutex(&fidp->mx);
6508     smb_ReleaseFID(fidp);
6509
6510     cm_Open(scp, 0, userp);
6511
6512     /* set inp->fid so that later read calls in same msg can find fid */
6513     inp->fid = fidp->fid;
6514
6515     /* copy out remainder of the parms */
6516     parmSlot = 2;
6517     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6518     lock_ObtainRead(&scp->rw);
6519     if (extraInfo) {
6520         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
6521         smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
6522         smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
6523         smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
6524         smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
6525         smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
6526         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
6527         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
6528         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
6529     }
6530     /* and the final "always present" stuff */
6531     smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
6532     /* next write out the "unique" ID */
6533     smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
6534     smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
6535     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
6536     lock_ReleaseRead(&scp->rw);
6537     smb_SetSMBDataLength(outp, 0);
6538
6539     osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
6540
6541     cm_ReleaseUser(userp);
6542     /* leave scp held since we put it in fidp->scp */
6543     return 0;
6544 }
6545
6546 static void smb_GetLockParams(unsigned char LockType,
6547                               char ** buf,
6548                               unsigned int * ppid,
6549                               LARGE_INTEGER * pOffset,
6550                               LARGE_INTEGER * pLength)
6551 {
6552     if (LockType & LOCKING_ANDX_LARGE_FILES) {
6553         /* Large Files */
6554         *ppid = *((USHORT *) *buf);
6555         pOffset->HighPart = *((LONG *)(*buf + 4));
6556         pOffset->LowPart = *((DWORD *)(*buf + 8));
6557         pLength->HighPart = *((LONG *)(*buf + 12));
6558         pLength->LowPart = *((DWORD *)(*buf + 16));
6559         *buf += 20;
6560     }
6561     else {
6562         /* Not Large Files */
6563         *ppid = *((USHORT *) *buf);
6564         pOffset->HighPart = 0;
6565         pOffset->LowPart = *((DWORD *)(*buf + 2));
6566         pLength->HighPart = 0;
6567         pLength->LowPart = *((DWORD *)(*buf + 6));
6568         *buf += 10;
6569     }
6570 }
6571
6572 /* SMB_COM_LOCKING_ANDX */
6573 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6574 {
6575     cm_req_t req;
6576     cm_user_t *userp;
6577     unsigned short fid;
6578     smb_fid_t *fidp;
6579     cm_scache_t *scp;
6580     unsigned char LockType;
6581     unsigned short NumberOfUnlocks, NumberOfLocks;
6582     afs_uint32 Timeout;
6583     char *op;
6584     char *op_locks;
6585     LARGE_INTEGER LOffset, LLength;
6586     smb_waitingLockRequest_t *wlRequest = NULL;
6587     cm_file_lock_t *lockp;
6588     long code = 0;
6589     int i;
6590     cm_key_t key;
6591     unsigned int pid;
6592     afs_uint32 smb_vc_hold_required = 0;
6593
6594     smb_InitReq(&req);
6595
6596     fid = smb_GetSMBParm(inp, 2);
6597     fid = smb_ChainFID(fid, inp);
6598
6599     fidp = smb_FindFID(vcp, fid, 0);
6600     if (!fidp) {
6601         osi_Log2(smb_logp, "V3LockingX Unknown SMB Fid vcp 0x%p fid %d",
6602                  vcp, fid);
6603         return CM_ERROR_BADFD;
6604     }
6605     lock_ObtainMutex(&fidp->mx);
6606     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6607         lock_ReleaseMutex(&fidp->mx);
6608         smb_CloseFID(vcp, fidp, NULL, 0);
6609         smb_ReleaseFID(fidp);
6610         return CM_ERROR_NOSUCHFILE;
6611     }
6612
6613     if (fidp->flags & SMB_FID_IOCTL) {
6614         osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
6615         lock_ReleaseMutex(&fidp->mx);
6616         smb_ReleaseFID(fidp);
6617         return CM_ERROR_BADFD;
6618     }
6619     scp = fidp->scp;
6620     osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
6621     cm_HoldSCache(scp);
6622     lock_ReleaseMutex(&fidp->mx);
6623
6624     /* set inp->fid so that later read calls in same msg can find fid */
6625     inp->fid = fid;
6626
6627     userp = smb_GetUserFromVCP(vcp, inp);
6628     smb_HoldVC(vcp);
6629
6630     lock_ObtainWrite(&scp->rw);
6631     code = cm_SyncOp(scp, NULL, userp, &req, 0,
6632                       CM_SCACHESYNC_NEEDCALLBACK
6633                          | CM_SCACHESYNC_GETSTATUS
6634                          | CM_SCACHESYNC_LOCK);
6635     if (code) {
6636         osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
6637         goto doneSync;
6638     }
6639
6640     LockType = smb_GetSMBParm(inp, 3) & 0xff;
6641     Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
6642     NumberOfUnlocks = smb_GetSMBParm(inp, 6);
6643     NumberOfLocks = smb_GetSMBParm(inp, 7);
6644
6645     if (!(fidp->flags & SMB_FID_OPENWRITE) &&
6646         !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
6647         /* somebody wants exclusive locks on a file that they only
6648            opened for reading.  We downgrade this to a shared lock. */
6649         osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
6650         LockType |= LOCKING_ANDX_SHARED_LOCK;
6651     }
6652
6653     if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6654         /* AFS does not support atomic changes of lock types from read or write and vice-versa */
6655         osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]");
6656         code = CM_ERROR_BADOP;
6657         goto done;
6658
6659     }
6660
6661     op = smb_GetSMBData(inp, NULL);
6662
6663     if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
6664         /* Cancel outstanding lock requests */
6665         smb_waitingLock_t * wl;
6666
6667         for (i=0; i<NumberOfLocks; i++) {
6668             smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6669
6670             key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6671
6672             lock_ObtainWrite(&smb_globalLock);
6673             for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6674             {
6675                 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6676                     if (cm_KeyEquals(&wl->key, &key, 0) && LargeIntegerEqualTo(wl->LOffset, LOffset) &&
6677                         LargeIntegerEqualTo(wl->LLength, LLength)) {
6678                         wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6679                         goto found_lock_request;
6680                     }
6681                 }
6682             }
6683           found_lock_request:
6684             lock_ReleaseWrite(&smb_globalLock);
6685         }
6686         code = 0;
6687         smb_SetSMBDataLength(outp, 0);
6688         goto done;
6689     }
6690
6691
6692     for (i=0; i<NumberOfUnlocks; i++) {
6693         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6694
6695         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6696
6697         code = cm_Unlock(scp, LockType, LOffset, LLength, key, 0, userp, &req);
6698
6699         if (code)
6700             goto done;
6701     }
6702
6703     op_locks = op;
6704
6705     for (i=0; i<NumberOfLocks; i++) {
6706         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6707
6708         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6709
6710         code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6711                         userp, &req, &lockp);
6712
6713         if (code == CM_ERROR_NOACCESS && LockType == LockWrite &&
6714             (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6715         {
6716             code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6717                             userp, &req, &lockp);
6718         }
6719
6720         if (code == CM_ERROR_LOCK_NOT_GRANTED && Timeout != 0) {
6721             smb_waitingLock_t * wLock;
6722
6723             /* Put on waiting list */
6724             if(wlRequest == NULL) {
6725                 int j;
6726                 char * opt;
6727                 cm_key_t tkey;
6728                 LARGE_INTEGER tOffset, tLength;
6729
6730                 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6731
6732                 osi_assertx(wlRequest != NULL, "null wlRequest");
6733
6734                 wlRequest->vcp = vcp;
6735                 smb_vc_hold_required = 1;
6736                 wlRequest->scp = scp;
6737                 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6738                 cm_HoldSCache(scp);
6739                 wlRequest->inp = smb_CopyPacket(inp);
6740                 wlRequest->outp = smb_CopyPacket(outp);
6741                 wlRequest->lockType = LockType;
6742                 wlRequest->msTimeout = Timeout;
6743                 wlRequest->start_t = osi_Time();
6744                 wlRequest->locks = NULL;
6745
6746                 /* The waiting lock request needs to have enough
6747                    information to undo all the locks in the request.
6748                    We do the following to store info about locks that
6749                    have already been granted.  Sure, we can get most
6750                    of the info from the packet, but the packet doesn't
6751                    hold the result of cm_Lock call.  In practice we
6752                    only receive packets with one or two locks, so we
6753                    are only wasting a few bytes here and there and
6754                    only for a limited period of time until the waiting
6755                    lock times out or is freed. */
6756
6757                 for(opt = op_locks, j=i; j > 0; j--) {
6758                     smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6759
6760                     tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6761
6762                     wLock = malloc(sizeof(smb_waitingLock_t));
6763
6764                     osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6765
6766                     wLock->key = tkey;
6767                     wLock->LOffset = tOffset;
6768                     wLock->LLength = tLength;
6769                     wLock->lockp = NULL;
6770                     wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6771                     osi_QAdd((osi_queue_t **) &wlRequest->locks,
6772                              &wLock->q);
6773                 }
6774             }
6775
6776             wLock = malloc(sizeof(smb_waitingLock_t));
6777
6778             osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6779
6780             wLock->key = key;
6781             wLock->LOffset = LOffset;
6782             wLock->LLength = LLength;
6783             wLock->lockp = lockp;
6784             wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6785             osi_QAdd((osi_queue_t **) &wlRequest->locks,
6786                      &wLock->q);
6787
6788             osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6789                      wLock);
6790
6791             code = 0;
6792             continue;
6793         }
6794
6795         if (code) {
6796             osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6797             break;
6798         }
6799     }
6800
6801     if (code) {
6802
6803         /* Since something went wrong with the lock number i, we now
6804            have to go ahead and release any locks acquired before the
6805            failure.  All locks before lock number i (of which there
6806            are i of them) have either been successful or are waiting.
6807            Either case requires calling cm_Unlock(). */
6808
6809         /* And purge the waiting lock */
6810         if(wlRequest != NULL) {
6811             smb_waitingLock_t * wl;
6812             smb_waitingLock_t * wlNext;
6813             long ul_code;
6814
6815             for(wl = wlRequest->locks; wl; wl = wlNext) {
6816
6817                 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6818
6819                 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, 0, userp, &req);
6820
6821                 if(ul_code != 0) {
6822                     osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6823                 } else {
6824                     osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6825                 }
6826
6827                 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6828                 free(wl);
6829
6830             }
6831
6832             smb_ReleaseVC(wlRequest->vcp);
6833             cm_ReleaseSCache(wlRequest->scp);
6834             smb_FreePacket(wlRequest->inp);
6835             smb_FreePacket(wlRequest->outp);
6836
6837             free(wlRequest);
6838
6839             wlRequest = NULL;
6840         }
6841
6842     } else {
6843
6844         if (wlRequest != NULL) {
6845
6846             lock_ObtainWrite(&smb_globalLock);
6847             osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6848                      &wlRequest->q);
6849             osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6850             lock_ReleaseWrite(&smb_globalLock);
6851
6852             /* don't send reply immediately */
6853             outp->flags |= SMB_PACKETFLAG_NOSEND;
6854         }
6855
6856         smb_SetSMBDataLength(outp, 0);
6857     }
6858
6859   done:
6860     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6861
6862   doneSync:
6863     lock_ReleaseWrite(&scp->rw);
6864     cm_ReleaseSCache(scp);
6865     cm_ReleaseUser(userp);
6866     smb_ReleaseFID(fidp);
6867     if (!smb_vc_hold_required)
6868         smb_HoldVC(vcp);
6869
6870     return code;
6871 }
6872
6873 /* SMB_COM_QUERY_INFORMATION2 */
6874 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6875 {
6876     unsigned short fid;
6877     smb_fid_t *fidp;
6878     cm_scache_t *scp;
6879     long code = 0;
6880     afs_uint32 searchTime;
6881     cm_user_t *userp;
6882     cm_req_t req;
6883     int readlock = 0;
6884
6885     smb_InitReq(&req);
6886
6887     fid = smb_GetSMBParm(inp, 0);
6888     fid = smb_ChainFID(fid, inp);
6889
6890     fidp = smb_FindFID(vcp, fid, 0);
6891     if (!fidp) {
6892         osi_Log2(smb_logp, "V3GetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6893                  vcp, fid);
6894         return CM_ERROR_BADFD;
6895     }
6896     lock_ObtainMutex(&fidp->mx);
6897     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6898         lock_ReleaseMutex(&fidp->mx);
6899         smb_CloseFID(vcp, fidp, NULL, 0);
6900         smb_ReleaseFID(fidp);
6901         return CM_ERROR_NOSUCHFILE;
6902     }
6903
6904     if (fidp->flags & SMB_FID_IOCTL) {
6905         lock_ReleaseMutex(&fidp->mx);
6906         smb_ReleaseFID(fidp);
6907         return CM_ERROR_BADFD;
6908     }
6909     scp = fidp->scp;
6910     osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6911     cm_HoldSCache(scp);
6912     lock_ReleaseMutex(&fidp->mx);
6913
6914     userp = smb_GetUserFromVCP(vcp, inp);
6915
6916
6917     /* otherwise, stat the file */
6918     lock_ObtainWrite(&scp->rw);
6919     code = cm_SyncOp(scp, NULL, userp, &req, 0,
6920                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6921     if (code)
6922         goto done;
6923
6924     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6925
6926     lock_ConvertWToR(&scp->rw);
6927     readlock = 1;
6928
6929     /* decode times.  We need a search time, but the response to this
6930      * call provides the date first, not the time, as returned in the
6931      * searchTime variable.  So we take the high-order bits first.
6932      */
6933     cm_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6934     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);       /* ctime */
6935     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6936     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);       /* atime */
6937     smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6938     smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);       /* mtime */
6939     smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6940
6941     /* now handle file size and allocation size */
6942     smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);              /* file size */
6943     smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6944     smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);              /* alloc size */
6945     smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6946
6947     /* file attribute */
6948     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6949
6950     /* and finalize stuff */
6951     smb_SetSMBDataLength(outp, 0);
6952     code = 0;
6953
6954   done:
6955     if (readlock)
6956         lock_ReleaseRead(&scp->rw);
6957     else
6958         lock_ReleaseWrite(&scp->rw);
6959     cm_ReleaseSCache(scp);
6960     cm_ReleaseUser(userp);
6961     smb_ReleaseFID(fidp);
6962     return code;
6963 }
6964
6965 /* SMB_COM_SET_INFORMATION2 */
6966 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6967 {
6968     unsigned short fid;
6969     smb_fid_t *fidp;
6970     cm_scache_t *scp;
6971     long code = 0;
6972     afs_uint32 searchTime;
6973     time_t unixTime;
6974     cm_user_t *userp;
6975     cm_attr_t attrs;
6976     cm_req_t req;
6977
6978     smb_InitReq(&req);
6979
6980     fid = smb_GetSMBParm(inp, 0);
6981     fid = smb_ChainFID(fid, inp);
6982
6983     fidp = smb_FindFID(vcp, fid, 0);
6984     if (!fidp) {
6985         osi_Log2(smb_logp, "V3SetAttributes Unknown SMB Fid vcp 0x%p fid %d",
6986                  vcp, fid);
6987         return CM_ERROR_BADFD;
6988     }
6989     lock_ObtainMutex(&fidp->mx);
6990     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6991         lock_ReleaseMutex(&fidp->mx);
6992         smb_CloseFID(vcp, fidp, NULL, 0);
6993         smb_ReleaseFID(fidp);
6994         return CM_ERROR_NOSUCHFILE;
6995     }
6996
6997     if (fidp->flags & SMB_FID_IOCTL) {
6998         lock_ReleaseMutex(&fidp->mx);
6999         smb_ReleaseFID(fidp);
7000         return CM_ERROR_BADFD;
7001     }
7002     scp = fidp->scp;
7003     osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
7004     cm_HoldSCache(scp);
7005     lock_ReleaseMutex(&fidp->mx);
7006
7007     userp = smb_GetUserFromVCP(vcp, inp);
7008
7009     /* now prepare to call cm_setattr.  This message only sets various times,
7010      * and AFS only implements mtime, and we'll set the mtime if that's
7011      * requested.  The others we'll ignore.
7012      */
7013     searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
7014
7015     if (searchTime != 0) {
7016         cm_UnixTimeFromSearchTime(&unixTime, searchTime);
7017
7018         if ( unixTime != -1 ) {
7019             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
7020             attrs.clientModTime = unixTime;
7021             code = cm_SetAttr(scp, &attrs, userp, &req);
7022
7023             osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
7024         } else {
7025             osi_Log1(smb_logp, "**cm_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
7026         }
7027     }
7028     else
7029         code = 0;
7030
7031     cm_ReleaseSCache(scp);
7032     cm_ReleaseUser(userp);
7033     smb_ReleaseFID(fidp);
7034     return code;
7035 }
7036
7037 /* SMB_COM_WRITE_ANDX */
7038 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7039 {
7040     osi_hyper_t offset;
7041     long count, written = 0, total_written = 0;
7042     unsigned short fd;
7043     unsigned pid;
7044     smb_fid_t *fidp;
7045     smb_t *smbp = (smb_t*) inp;
7046     long code = 0;
7047     cm_scache_t *scp;
7048     cm_user_t *userp;
7049     char *op;
7050     int inDataBlockCount;
7051
7052     fd = smb_GetSMBParm(inp, 2);
7053     count = smb_GetSMBParm(inp, 10);
7054
7055     offset.HighPart = 0;
7056     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7057
7058     if (*inp->wctp == 14) {
7059         /* we have a request with 64-bit file offsets */
7060         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7061     }
7062
7063     op = inp->data + smb_GetSMBParm(inp, 11);
7064     inDataBlockCount = count;
7065
7066     osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
7067              fd, offset.HighPart, offset.LowPart, count);
7068
7069     fd = smb_ChainFID(fd, inp);
7070     fidp = smb_FindFID(vcp, fd, 0);
7071     if (!fidp) {
7072         osi_Log2(smb_logp, "smb_ReceiveV3WriteX Unknown SMB Fid vcp 0x%p fid %d",
7073                  vcp, fd);
7074         return CM_ERROR_BADFD;
7075     }
7076     lock_ObtainMutex(&fidp->mx);
7077     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7078         lock_ReleaseMutex(&fidp->mx);
7079         smb_CloseFID(vcp, fidp, NULL, 0);
7080         smb_ReleaseFID(fidp);
7081         return CM_ERROR_NOSUCHFILE;
7082     }
7083
7084     if (fidp->flags & SMB_FID_IOCTL) {
7085         lock_ReleaseMutex(&fidp->mx);
7086         code = smb_IoctlV3Write(fidp, vcp, inp, outp);
7087         smb_ReleaseFID(fidp);
7088         return code;
7089     }
7090
7091     if (fidp->flags & SMB_FID_RPC) {
7092         lock_ReleaseMutex(&fidp->mx);
7093         code = smb_RPCV3Write(fidp, vcp, inp, outp);
7094         smb_ReleaseFID(fidp);
7095         return code;
7096     }
7097
7098     if (!fidp->scp) {
7099         lock_ReleaseMutex(&fidp->mx);
7100         smb_ReleaseFID(fidp);
7101         return CM_ERROR_BADFDOP;
7102     }
7103
7104     scp = fidp->scp;
7105     cm_HoldSCache(scp);
7106     lock_ReleaseMutex(&fidp->mx);
7107
7108     userp = smb_GetUserFromVCP(vcp, inp);
7109
7110     /* special case: 0 bytes transferred means there is no data
7111        transferred.  A slight departure from SMB_COM_WRITE where this
7112        means that we are supposed to truncate the file at this
7113        position. */
7114
7115     {
7116         cm_key_t key;
7117         LARGE_INTEGER LOffset;
7118         LARGE_INTEGER LLength;
7119
7120         pid = smbp->pid;
7121         key = cm_GenerateKey(vcp->vcID, pid, fd);
7122
7123         LOffset.HighPart = offset.HighPart;
7124         LOffset.LowPart = offset.LowPart;
7125         LLength.HighPart = 0;
7126         LLength.LowPart = count;
7127
7128         lock_ObtainWrite(&scp->rw);
7129         code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7130         lock_ReleaseWrite(&scp->rw);
7131
7132         if (code)
7133             goto done;
7134     }
7135
7136     /*
7137      * Work around bug in NT client
7138      *
7139      * When copying a file, the NT client should first copy the data,
7140      * then copy the last write time.  But sometimes the NT client does
7141      * these in the wrong order, so the data copies would inadvertently
7142      * cause the last write time to be overwritten.  We try to detect this,
7143      * and don't set client mod time if we think that would go against the
7144      * intention.
7145      */
7146     lock_ObtainMutex(&fidp->mx);
7147     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7148         lock_ObtainWrite(&fidp->scp->rw);
7149         scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7150         scp->clientModTime = time(NULL);
7151         lock_ReleaseWrite(&fidp->scp->rw);
7152     }
7153     lock_ReleaseMutex(&fidp->mx);
7154
7155     code = 0;
7156     while ( code == 0 && count > 0 ) {
7157         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7158         if (code == 0 && written == 0)
7159             code = CM_ERROR_PARTIALWRITE;
7160
7161         offset = LargeIntegerAdd(offset,
7162                                  ConvertLongToLargeInteger(written));
7163         count -= written;
7164         total_written += written;
7165         written = 0;
7166     }
7167
7168     /* slots 0 and 1 are reserved for request chaining and will be
7169        filled in when we return. */
7170     smb_SetSMBParm(outp, 2, total_written);
7171     smb_SetSMBParm(outp, 3, 0); /* reserved */
7172     smb_SetSMBParm(outp, 4, 0); /* reserved */
7173     smb_SetSMBParm(outp, 5, 0); /* reserved */
7174     smb_SetSMBDataLength(outp, 0);
7175
7176  done:
7177
7178     cm_ReleaseSCache(scp);
7179     cm_ReleaseUser(userp);
7180     smb_ReleaseFID(fidp);
7181
7182     return code;
7183 }
7184
7185 /* SMB_COM_READ_ANDX */
7186 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7187 {
7188     osi_hyper_t offset;
7189     long count;
7190     long finalCount = 0;
7191     unsigned short fd;
7192     unsigned pid;
7193     smb_fid_t *fidp;
7194     smb_t *smbp = (smb_t*) inp;
7195     long code = 0;
7196     cm_scache_t *scp;
7197     cm_user_t *userp;
7198     cm_key_t key;
7199     char *op;
7200
7201     fd = smb_GetSMBParm(inp, 2); /* File ID */
7202     count = smb_GetSMBParm(inp, 5); /* MaxCount */
7203     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7204
7205     if (*inp->wctp == 12) {
7206         /* a request with 64-bit offsets */
7207         offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
7208
7209         if (LargeIntegerLessThanZero(offset)) {
7210             osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
7211                      offset.HighPart, offset.LowPart);
7212             return CM_ERROR_BADSMB;
7213         }
7214     } else {
7215         offset.HighPart = 0;
7216     }
7217
7218     osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
7219              fd, offset.HighPart, offset.LowPart, count);
7220
7221     fd = smb_ChainFID(fd, inp);
7222     fidp = smb_FindFID(vcp, fd, 0);
7223     if (!fidp) {
7224         osi_Log2(smb_logp, "smb_ReceiveV3Read Unknown SMB Fid vcp 0x%p fid %d",
7225                  vcp, fd);
7226         return CM_ERROR_BADFD;
7227     }
7228
7229     lock_ObtainMutex(&fidp->mx);
7230
7231     if (fidp->flags & SMB_FID_IOCTL) {
7232         lock_ReleaseMutex(&fidp->mx);
7233         inp->fid = fd;
7234         code = smb_IoctlV3Read(fidp, vcp, inp, outp);
7235         smb_ReleaseFID(fidp);
7236         return code;
7237     }
7238
7239     if (fidp->flags & SMB_FID_RPC) {
7240         lock_ReleaseMutex(&fidp->mx);
7241         inp->fid = fd;
7242         code = smb_RPCV3Read(fidp, vcp, inp, outp);
7243         smb_ReleaseFID(fidp);
7244         return code;
7245     }
7246
7247     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7248         lock_ReleaseMutex(&fidp->mx);
7249         smb_CloseFID(vcp, fidp, NULL, 0);
7250         smb_ReleaseFID(fidp);
7251         return CM_ERROR_NOSUCHFILE;
7252     }
7253
7254     if (!fidp->scp) {
7255         lock_ReleaseMutex(&fidp->mx);
7256         smb_ReleaseFID(fidp);
7257         return CM_ERROR_BADFDOP;
7258     }
7259
7260     scp = fidp->scp;
7261     cm_HoldSCache(scp);
7262
7263     lock_ReleaseMutex(&fidp->mx);
7264
7265     pid = smbp->pid;
7266     key = cm_GenerateKey(vcp->vcID, pid, fd);
7267     {
7268         LARGE_INTEGER LOffset, LLength;
7269
7270         LOffset.HighPart = offset.HighPart;
7271         LOffset.LowPart = offset.LowPart;
7272         LLength.HighPart = 0;
7273         LLength.LowPart = count;
7274
7275         lock_ObtainWrite(&scp->rw);
7276         code = cm_LockCheckRead(scp, LOffset, LLength, key);
7277         lock_ReleaseWrite(&scp->rw);
7278     }
7279     cm_ReleaseSCache(scp);
7280
7281     if (code) {
7282         smb_ReleaseFID(fidp);
7283         return code;
7284     }
7285
7286     /* set inp->fid so that later read calls in same msg can find fid */
7287     inp->fid = fd;
7288
7289     userp = smb_GetUserFromVCP(vcp, inp);
7290
7291     /* 0 and 1 are reserved for request chaining, were setup by our caller,
7292      * and will be further filled in after we return.
7293      */
7294     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
7295     smb_SetSMBParm(outp, 3, 0); /* resvd */
7296     smb_SetSMBParm(outp, 4, 0); /* resvd */
7297     smb_SetSMBParm(outp, 5, count);     /* # of bytes we're going to read */
7298     /* fill in #6 when we have all the parameters' space reserved */
7299     smb_SetSMBParm(outp, 7, 0); /* resv'd */
7300     smb_SetSMBParm(outp, 8, 0); /* resv'd */
7301     smb_SetSMBParm(outp, 9, 0); /* resv'd */
7302     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
7303     smb_SetSMBParm(outp, 11, 0);        /* reserved */
7304
7305     /* get op ptr after putting in the parms, since otherwise we don't
7306      * know where the data really is.
7307      */
7308     op = smb_GetSMBData(outp, NULL);
7309
7310     /* now fill in offset from start of SMB header to first data byte (to op) */
7311     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
7312
7313     /* set the packet data length the count of the # of bytes */
7314     smb_SetSMBDataLength(outp, count);
7315
7316     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7317
7318     /* fix some things up */
7319     smb_SetSMBParm(outp, 5, finalCount);
7320     smb_SetSMBDataLength(outp, finalCount);
7321
7322     cm_ReleaseUser(userp);
7323     smb_ReleaseFID(fidp);
7324     return code;
7325 }
7326
7327 /*
7328  * Values for createDisp, copied from NTDDK.H
7329  */
7330 #define  FILE_SUPERSEDE 0       // (???)
7331 #define  FILE_OPEN      1       // (open)
7332 #define  FILE_CREATE    2       // (exclusive)
7333 #define  FILE_OPEN_IF   3       // (non-exclusive)
7334 #define  FILE_OVERWRITE 4       // (open & truncate, but do not create)
7335 #define  FILE_OVERWRITE_IF 5    // (open & truncate, or create)
7336
7337 /* Flags field */
7338 #define REQUEST_OPLOCK 2
7339 #define REQUEST_BATCH_OPLOCK 4
7340 #define OPEN_DIRECTORY 8
7341 #define EXTENDED_RESPONSE_REQUIRED 0x10
7342
7343 /* CreateOptions field. */
7344 #define FILE_DIRECTORY_FILE       0x0001
7345 #define FILE_WRITE_THROUGH        0x0002
7346 #define FILE_SEQUENTIAL_ONLY      0x0004
7347 #define FILE_NON_DIRECTORY_FILE   0x0040
7348 #define FILE_NO_EA_KNOWLEDGE      0x0200
7349 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
7350 #define FILE_RANDOM_ACCESS        0x0800
7351 #define FILE_DELETE_ON_CLOSE      0x1000
7352 #define FILE_OPEN_BY_FILE_ID      0x2000
7353 #define FILE_OPEN_FOR_BACKUP_INTENT             0x00004000
7354 #define FILE_NO_COMPRESSION                     0x00008000
7355 #define FILE_RESERVE_OPFILTER                   0x00100000
7356 #define FILE_OPEN_REPARSE_POINT                 0x00200000
7357 #define FILE_OPEN_NO_RECALL                     0x00400000
7358 #define FILE_OPEN_FOR_FREE_SPACE_QUERY          0x00800000
7359
7360 /* SMB_COM_NT_CREATE_ANDX */
7361 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7362 {
7363     clientchar_t *pathp, *realPathp;
7364     long code = 0;
7365     cm_space_t *spacep;
7366     cm_user_t *userp;
7367     cm_scache_t *dscp;          /* parent dir */
7368     cm_scache_t *scp;           /* file to create or open */
7369     cm_scache_t *targetScp;     /* if scp is a symlink */
7370     cm_attr_t setAttr;
7371     clientchar_t *lastNamep;
7372     clientchar_t *treeStartp;
7373     unsigned short nameLength;
7374     unsigned int flags;
7375     unsigned int requestOpLock;
7376     unsigned int requestBatchOpLock;
7377     unsigned int mustBeDir;
7378     unsigned int extendedRespRequired;
7379     unsigned int treeCreate;
7380     int realDirFlag;
7381     unsigned int desiredAccess;
7382     unsigned int extAttributes;
7383     unsigned int createDisp;
7384     unsigned int createOptions;
7385     unsigned int shareAccess;
7386     unsigned short baseFid;
7387     smb_fid_t *baseFidp;
7388     smb_fid_t *fidp;
7389     cm_scache_t *baseDirp;
7390     unsigned short openAction;
7391     int parmSlot;
7392     long fidflags;
7393     FILETIME ft;
7394     LARGE_INTEGER sz;
7395     clientchar_t *tidPathp;
7396     BOOL foundscp;
7397     cm_req_t req;
7398     int created = 0;
7399     int prefetch = 0;
7400     int checkDoneRequired = 0;
7401     cm_lock_data_t *ldp = NULL;
7402     BOOL is_rpc = FALSE;
7403     BOOL is_ipc = FALSE;
7404
7405     smb_InitReq(&req);
7406
7407     /* This code is very long and has a lot of if-then-else clauses
7408      * scp and dscp get reused frequently and we need to ensure that
7409      * we don't lose a reference.  Start by ensuring that they are NULL.
7410      */
7411     scp = NULL;
7412     dscp = NULL;
7413     treeCreate = FALSE;
7414     foundscp = FALSE;
7415
7416     nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
7417     flags = smb_GetSMBOffsetParm(inp, 3, 1)
7418         | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
7419     requestOpLock = flags & REQUEST_OPLOCK;
7420     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7421     mustBeDir = flags & OPEN_DIRECTORY;
7422     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7423
7424     /*
7425      * Why all of a sudden 32-bit FID?
7426      * We will reject all bits higher than 16.
7427      */
7428     if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
7429         return CM_ERROR_INVAL;
7430     baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
7431     desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
7432         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7433     extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
7434         | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
7435     shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
7436         | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
7437     createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
7438         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
7439     createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
7440         | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
7441
7442     /* mustBeDir is never set; createOptions directory bit seems to be
7443      * more important
7444      */
7445     if (createOptions & FILE_DIRECTORY_FILE)
7446         realDirFlag = 1;
7447     else if (createOptions & FILE_NON_DIRECTORY_FILE)
7448         realDirFlag = 0;
7449     else
7450         realDirFlag = -1;
7451
7452     pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
7453                               NULL, SMB_STRF_ANSIPATH);
7454
7455     /* Sometimes path is not null-terminated, so we make a copy. */
7456     realPathp = malloc(nameLength+sizeof(clientchar_t));
7457     memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
7458     realPathp[nameLength/sizeof(clientchar_t)] = 0;
7459
7460     spacep = inp->spacep;
7461     /* smb_StripLastComponent will strip "::$DATA" if present */
7462     smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7463
7464     osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
7465     osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
7466     osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
7467
7468     if (baseFid == 0) {
7469         baseFidp = NULL;
7470         baseDirp = cm_RootSCachep(cm_rootUserp, &req);
7471         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7472         if (code == CM_ERROR_TIDIPC) {
7473             /* Attempt to use a TID allocated for IPC.  The client
7474              * is probably looking for DCE RPC end points which we
7475              * don't support OR it could be looking to make a DFS
7476              * referral request.
7477              */
7478             osi_Log0(smb_logp, "NTCreateX received IPC TID");
7479             is_ipc = TRUE;
7480         }
7481     }
7482
7483     osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
7484
7485     if (lastNamep &&
7486
7487         ((is_ipc && MSRPC_IsWellKnownService(lastNamep) && (is_rpc = TRUE)) ||
7488
7489          /* special case magic file name for receiving IOCTL requests
7490           * (since IOCTL calls themselves aren't getting through).
7491           */
7492          cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0)) {
7493
7494         unsigned short file_type = 0;
7495         unsigned short device_state = 0;
7496
7497         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7498
7499         if (is_rpc) {
7500             code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
7501             osi_Log1(smb_logp, "NTCreateX Setting up RPC on fid[%d]", fidp->fid);
7502             if (code) {
7503                 osi_Log1(smb_logp, "smb_SetupRPCFid() failure code [%d]", code);
7504                 smb_ReleaseFID(fidp);
7505                 free(realPathp);
7506                 return code;
7507             }
7508         } else {
7509             smb_SetupIoctlFid(fidp, spacep);
7510             osi_Log1(smb_logp, "NTCreateX Setting up IOCTL on fid[%d]", fidp->fid);
7511         }
7512
7513         /* set inp->fid so that later read calls in same msg can find fid */
7514         inp->fid = fidp->fid;
7515
7516         /* out parms */
7517         parmSlot = 2;
7518         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
7519         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7520         smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
7521         /* times */
7522         memset(&ft, 0, sizeof(ft));
7523         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7524         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7525         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7526         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7527         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
7528         sz.HighPart = 0x7fff; sz.LowPart = 0;
7529         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
7530         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
7531         smb_SetSMBParm(outp, parmSlot, file_type); parmSlot++;  /* filetype */
7532         smb_SetSMBParm(outp, parmSlot, device_state); parmSlot++;       /* dev state */
7533         smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
7534         smb_SetSMBDataLength(outp, 0);
7535
7536         /* clean up fid reference */
7537         smb_ReleaseFID(fidp);
7538         free(realPathp);
7539         return 0;
7540     }
7541
7542 #ifndef DFS_SUPPORT
7543     if (is_ipc) {
7544         osi_Log0(smb_logp, "NTCreateX rejecting IPC TID");
7545         free(realPathp);
7546         return CM_ERROR_BADFD;
7547     }
7548 #endif
7549
7550     if (!cm_IsValidClientString(realPathp)) {
7551 #ifdef DEBUG
7552         clientchar_t * hexp;
7553
7554         hexp = cm_GetRawCharsAlloc(realPathp, -1);
7555         osi_Log1(smb_logp, "NTCreateX rejecting invalid name. [%S]",
7556                  osi_LogSaveClientString(smb_logp, hexp));
7557         if (hexp)
7558             free(hexp);
7559 #else
7560         osi_Log0(smb_logp, "NTCreateX rejecting invalid name");
7561 #endif
7562         free(realPathp);
7563         return CM_ERROR_BADNTFILENAME;
7564     }
7565
7566     userp = smb_GetUserFromVCP(vcp, inp);
7567     if (!userp) {
7568         osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
7569         free(realPathp);
7570         return CM_ERROR_INVAL;
7571     }
7572
7573     if (baseFidp != 0) {
7574         baseFidp = smb_FindFID(vcp, baseFid, 0);
7575         if (!baseFidp) {
7576             osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
7577             cm_ReleaseUser(userp);
7578             free(realPathp);
7579             return CM_ERROR_INVAL;
7580         }
7581
7582         if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7583             free(realPathp);
7584             smb_CloseFID(vcp, baseFidp, NULL, 0);
7585             smb_ReleaseFID(baseFidp);
7586             cm_ReleaseUser(userp);
7587             return CM_ERROR_NOSUCHPATH;
7588         }
7589
7590         baseDirp = baseFidp->scp;
7591         tidPathp = NULL;
7592     }
7593
7594     /* compute open mode */
7595     fidflags = 0;
7596     if (desiredAccess & DELETE)
7597         fidflags |= SMB_FID_OPENDELETE;
7598     if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7599         fidflags |= SMB_FID_OPENREAD_LISTDIR;
7600     if (desiredAccess & AFS_ACCESS_WRITE)
7601         fidflags |= SMB_FID_OPENWRITE;
7602     if (createOptions & FILE_DELETE_ON_CLOSE)
7603         fidflags |= SMB_FID_DELONCLOSE;
7604     if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7605         fidflags |= SMB_FID_SEQUENTIAL;
7606     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7607         fidflags |= SMB_FID_RANDOM;
7608     if (createOptions & FILE_OPEN_REPARSE_POINT)
7609         osi_Log0(smb_logp, "NTCreateX Open Reparse Point");
7610     if (smb_IsExecutableFileName(lastNamep))
7611         fidflags |= SMB_FID_EXECUTABLE;
7612
7613     /* and the share mode */
7614     if (shareAccess & FILE_SHARE_READ)
7615         fidflags |= SMB_FID_SHARE_READ;
7616     if (shareAccess & FILE_SHARE_WRITE)
7617         fidflags |= SMB_FID_SHARE_WRITE;
7618
7619     osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
7620     code = 0;
7621
7622     /* For an exclusive create, we want to do a case sensitive match for the last component. */
7623     if ( createDisp == FILE_CREATE ||
7624          createDisp == FILE_OVERWRITE ||
7625          createDisp == FILE_OVERWRITE_IF) {
7626         code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7627                         userp, tidPathp, &req, &dscp);
7628         if (code == 0) {
7629 #ifdef DFS_SUPPORT
7630             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7631                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7632                                                           spacep->wdata);
7633                 cm_ReleaseSCache(dscp);
7634                 cm_ReleaseUser(userp);
7635                 free(realPathp);
7636                 if (baseFidp)
7637                     smb_ReleaseFID(baseFidp);
7638                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7639                     return CM_ERROR_PATH_NOT_COVERED;
7640                 else
7641                     return CM_ERROR_NOSUCHPATH;
7642             }
7643 #endif /* DFS_SUPPORT */
7644             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7645                              userp, &req, &scp);
7646             if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7647                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
7648                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7649                 if (code == 0 && realDirFlag == 1) {
7650                     cm_ReleaseSCache(scp);
7651                     cm_ReleaseSCache(dscp);
7652                     cm_ReleaseUser(userp);
7653                     free(realPathp);
7654                     if (baseFidp)
7655                         smb_ReleaseFID(baseFidp);
7656                     return CM_ERROR_EXISTS;
7657                 }
7658             }
7659             /* we have both scp and dscp */
7660         }
7661     } else {
7662         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7663                         userp, tidPathp, &req, &scp);
7664 #ifdef DFS_SUPPORT
7665         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7666             int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7667             cm_ReleaseSCache(scp);
7668             cm_ReleaseUser(userp);
7669             free(realPathp);
7670             if (baseFidp)
7671                 smb_ReleaseFID(baseFidp);
7672             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7673                 return CM_ERROR_PATH_NOT_COVERED;
7674             else
7675                 return CM_ERROR_NOSUCHPATH;
7676         }
7677 #endif /* DFS_SUPPORT */
7678         /* we might have scp but not dscp */
7679     }
7680
7681     if (code &&
7682         code != CM_ERROR_NOSUCHFILE &&
7683         code != CM_ERROR_NOSUCHPATH &&
7684         code != CM_ERROR_BPLUS_NOMATCH) {
7685         cm_ReleaseUser(userp);
7686         free(realPathp);
7687         if (baseFidp)
7688             smb_ReleaseFID(baseFidp);
7689         return code;
7690     }
7691
7692     if (scp)
7693         foundscp = TRUE;
7694
7695     if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7696         /* look up parent directory */
7697         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
7698          * the immediate parent.  We have to work our way up realPathp until we hit something that we
7699          * recognize.
7700          */
7701
7702         /* we might or might not have scp */
7703
7704         if (dscp == NULL) {
7705             do {
7706                 clientchar_t *tp;
7707
7708                 code = cm_NameI(baseDirp, spacep->wdata,
7709                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7710                                 userp, tidPathp, &req, &dscp);
7711
7712 #ifdef DFS_SUPPORT
7713                 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7714                     int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
7715                                                               spacep->wdata);
7716                     if (scp)
7717                         cm_ReleaseSCache(scp);
7718                     cm_ReleaseSCache(dscp);
7719                     cm_ReleaseUser(userp);
7720                     free(realPathp);
7721                     if (baseFidp)
7722                         smb_ReleaseFID(baseFidp);
7723                     if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7724                         return CM_ERROR_PATH_NOT_COVERED;
7725                     else
7726                         return CM_ERROR_NOSUCHPATH;
7727                 }
7728 #endif /* DFS_SUPPORT */
7729
7730                 if (code &&
7731                     (code == CM_ERROR_NOSUCHFILE ||
7732                      code == CM_ERROR_NOSUCHPATH ||
7733                      code == CM_ERROR_BPLUS_NOMATCH) &&
7734                     (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
7735                     (createDisp == FILE_CREATE) &&
7736                     (realDirFlag == 1)) {
7737                     *tp++ = 0;
7738                     treeCreate = TRUE;
7739                     treeStartp = realPathp + (tp - spacep->wdata);
7740
7741                     if (*tp && !smb_IsLegalFilename(tp)) {
7742                         cm_ReleaseUser(userp);
7743                         if (baseFidp)
7744                             smb_ReleaseFID(baseFidp);
7745                         free(realPathp);
7746                         if (scp)
7747                             cm_ReleaseSCache(scp);
7748                         return CM_ERROR_BADNTFILENAME;
7749                     }
7750                     code = 0;
7751                 }
7752             } while (dscp == NULL && code == 0);
7753         } else
7754             code = 0;
7755
7756         /* we might have scp and we might have dscp */
7757
7758         if (baseFidp)
7759             smb_ReleaseFID(baseFidp);
7760
7761         if (code) {
7762             osi_Log0(smb_logp,"NTCreateX parent not found");
7763             if (scp)
7764                 cm_ReleaseSCache(scp);
7765             if (dscp)
7766                 cm_ReleaseSCache(dscp);
7767             cm_ReleaseUser(userp);
7768             free(realPathp);
7769             return code;
7770         }
7771
7772         if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7773             /* A file exists where we want a directory. */
7774             if (scp)
7775                 cm_ReleaseSCache(scp);
7776             cm_ReleaseSCache(dscp);
7777             cm_ReleaseUser(userp);
7778             free(realPathp);
7779             return CM_ERROR_EXISTS;
7780         }
7781
7782         if (!lastNamep)
7783             lastNamep = realPathp;
7784         else
7785             lastNamep++;
7786
7787         if (!smb_IsLegalFilename(lastNamep)) {
7788             if (scp)
7789                 cm_ReleaseSCache(scp);
7790             if (dscp)
7791                 cm_ReleaseSCache(dscp);
7792             cm_ReleaseUser(userp);
7793             free(realPathp);
7794             return CM_ERROR_BADNTFILENAME;
7795         }
7796
7797         if (!foundscp && !treeCreate) {
7798             if ( createDisp == FILE_CREATE ||
7799                  createDisp == FILE_OVERWRITE ||
7800                  createDisp == FILE_OVERWRITE_IF)
7801             {
7802                 code = cm_Lookup(dscp, lastNamep,
7803                                   CM_FLAG_FOLLOW, userp, &req, &scp);
7804             } else {
7805                 code = cm_Lookup(dscp, lastNamep,
7806                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7807                                  userp, &req, &scp);
7808             }
7809             if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7810                 if (dscp)
7811                     cm_ReleaseSCache(dscp);
7812                 cm_ReleaseUser(userp);
7813                 free(realPathp);
7814                 return code;
7815             }
7816         }
7817         /* we have scp and dscp */
7818     } else {
7819         /* we have scp but not dscp */
7820         if (baseFidp)
7821             smb_ReleaseFID(baseFidp);
7822     }
7823
7824     /* if we get here, if code is 0, the file exists and is represented by
7825      * scp.  Otherwise, we have to create it.  The dir may be represented
7826      * by dscp, or we may have found the file directly.  If code is non-zero,
7827      * scp is NULL.
7828      */
7829     if (code == 0 && !treeCreate) {
7830         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7831         if (code) {
7832             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7833             if (dscp)
7834                 cm_ReleaseSCache(dscp);
7835             if (scp)
7836                 cm_ReleaseSCache(scp);
7837             cm_ReleaseUser(userp);
7838             free(realPathp);
7839             return code;
7840         }
7841         checkDoneRequired = 1;
7842
7843         if (createDisp == FILE_CREATE) {
7844             /* oops, file shouldn't be there */
7845             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7846             if (dscp)
7847                 cm_ReleaseSCache(dscp);
7848             if (scp)
7849                 cm_ReleaseSCache(scp);
7850             cm_ReleaseUser(userp);
7851             free(realPathp);
7852             return CM_ERROR_EXISTS;
7853         }
7854
7855         if ( createDisp == FILE_OVERWRITE ||
7856              createDisp == FILE_OVERWRITE_IF) {
7857
7858             setAttr.mask = CM_ATTRMASK_LENGTH;
7859             setAttr.length.LowPart = 0;
7860             setAttr.length.HighPart = 0;
7861             /* now watch for a symlink */
7862             code = 0;
7863             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7864                 targetScp = 0;
7865                 osi_assertx(dscp != NULL, "null cm_scache_t");
7866                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7867                 if (code == 0) {
7868                     /* we have a more accurate file to use (the
7869                      * target of the symbolic link).  Otherwise,
7870                      * we'll just use the symlink anyway.
7871                      */
7872                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
7873                               scp, targetScp);
7874                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7875                     cm_ReleaseSCache(scp);
7876                     scp = targetScp;
7877                     code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7878                     if (code) {
7879                         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7880                         if (dscp)
7881                             cm_ReleaseSCache(dscp);
7882                         if (scp)
7883                             cm_ReleaseSCache(scp);
7884                         cm_ReleaseUser(userp);
7885                         free(realPathp);
7886                         return code;
7887                     }
7888                 }
7889             }
7890             code = cm_SetAttr(scp, &setAttr, userp, &req);
7891             openAction = 3;     /* truncated existing file */
7892         }
7893         else
7894             openAction = 1;     /* found existing file */
7895
7896     } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7897         /* don't create if not found */
7898         if (dscp)
7899             cm_ReleaseSCache(dscp);
7900         if (scp)
7901             cm_ReleaseSCache(scp);
7902         cm_ReleaseUser(userp);
7903         free(realPathp);
7904         return CM_ERROR_NOSUCHFILE;
7905     } else if (realDirFlag == 0 || realDirFlag == -1) {
7906         osi_assertx(dscp != NULL, "null cm_scache_t");
7907         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7908                   osi_LogSaveClientString(smb_logp, lastNamep));
7909         openAction = 2;         /* created file */
7910         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7911         setAttr.clientModTime = time(NULL);
7912         smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
7913
7914         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7915         if (code == 0) {
7916             created = 1;
7917             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7918                 smb_NotifyChange(FILE_ACTION_ADDED,
7919                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7920                                  dscp, lastNamep, NULL, TRUE);
7921         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7922             /* Not an exclusive create, and someone else tried
7923              * creating it already, then we open it anyway.  We
7924              * don't bother retrying after this, since if this next
7925              * fails, that means that the file was deleted after we
7926              * started this call.
7927              */
7928             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7929                               userp, &req, &scp);
7930             if (code == 0) {
7931                 if (createDisp == FILE_OVERWRITE_IF) {
7932                     setAttr.mask = CM_ATTRMASK_LENGTH;
7933                     setAttr.length.LowPart = 0;
7934                     setAttr.length.HighPart = 0;
7935
7936                     /* now watch for a symlink */
7937                     code = 0;
7938                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7939                         targetScp = 0;
7940                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7941                         if (code == 0) {
7942                             /* we have a more accurate file to use (the
7943                              * target of the symbolic link).  Otherwise,
7944                              * we'll just use the symlink anyway.
7945                              */
7946                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
7947                                       scp, targetScp);
7948                             cm_ReleaseSCache(scp);
7949                             scp = targetScp;
7950                         }
7951                     }
7952                     code = cm_SetAttr(scp, &setAttr, userp, &req);
7953                 }
7954             }   /* lookup succeeded */
7955         }
7956     } else {
7957         clientchar_t *tp, *pp;
7958         clientchar_t *cp; /* This component */
7959         int clen = 0; /* length of component */
7960         cm_scache_t *tscp1, *tscp2;
7961         int isLast = 0;
7962
7963         /* create directory */
7964         if ( !treeCreate )
7965             treeStartp = lastNamep;
7966         osi_assertx(dscp != NULL, "null cm_scache_t");
7967         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7968                   osi_LogSaveClientString(smb_logp, treeStartp));
7969         openAction = 2;         /* created directory */
7970
7971         /* if the request is to create the root directory
7972          * it will appear as a directory name of the nul-string
7973          * and a code of CM_ERROR_NOSUCHFILE
7974          */
7975         if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7976             code = CM_ERROR_EXISTS;
7977
7978         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7979         setAttr.clientModTime = time(NULL);
7980         smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
7981
7982         pp = treeStartp;
7983         cp = spacep->wdata;
7984         tscp1 = dscp;
7985         cm_HoldSCache(tscp1);
7986         tscp2 = NULL;
7987
7988         while (pp && *pp) {
7989             tp = cm_ClientStrChr(pp, '\\');
7990             if (!tp) {
7991                 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7992                 clen = (int)cm_ClientStrLen(cp);
7993                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
7994             } else {
7995                 clen = (int)(tp - pp);
7996                 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7997                                  pp, clen);
7998                 *(cp + clen) = 0;
7999                 tp++;
8000             }
8001             pp = tp;
8002
8003             if (clen == 0)
8004                 continue; /* the supplied path can't have consecutive slashes either , but */
8005
8006             /* cp is the next component to be created. */
8007             code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
8008             if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
8009                 smb_NotifyChange(FILE_ACTION_ADDED,
8010                                  FILE_NOTIFY_CHANGE_DIR_NAME,
8011                                  tscp1, cp, NULL, TRUE);
8012             if (code == 0 ||
8013                 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8014                 /* Not an exclusive create, and someone else tried
8015                  * creating it already, then we open it anyway.  We
8016                  * don't bother retrying after this, since if this next
8017                  * fails, that means that the file was deleted after we
8018                  * started this call.
8019                  */
8020                 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
8021                                  userp, &req, &tscp2);
8022             }
8023             if (code)
8024                 break;
8025
8026             if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
8027                 cm_ReleaseSCache(tscp1);
8028                 tscp1 = tscp2; /* Newly created directory will be next parent */
8029                 /* the hold is transfered to tscp1 from tscp2 */
8030             }
8031         }
8032
8033         if (dscp)
8034             cm_ReleaseSCache(dscp);
8035         dscp = tscp1;
8036         if (scp)
8037             cm_ReleaseSCache(scp);
8038         scp = tscp2;
8039         /*
8040          * if we get here and code == 0, then scp is the last directory created, and dscp is the
8041          * parent of scp.
8042          */
8043     }
8044
8045     if (code) {
8046         /* something went wrong creating or truncating the file */
8047         if (checkDoneRequired)
8048             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8049         if (scp)
8050             cm_ReleaseSCache(scp);
8051         if (dscp)
8052             cm_ReleaseSCache(dscp);
8053         cm_ReleaseUser(userp);
8054         free(realPathp);
8055         return code;
8056     }
8057
8058     /* make sure we have file vs. dir right (only applies for single component case) */
8059     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8060         /* now watch for a symlink */
8061         code = 0;
8062         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8063             cm_scache_t * targetScp = 0;
8064             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8065             if (code == 0) {
8066                 /* we have a more accurate file to use (the
8067                 * target of the symbolic link).  Otherwise,
8068                 * we'll just use the symlink anyway.
8069                 */
8070                 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
8071                 if (checkDoneRequired) {
8072                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8073                     checkDoneRequired = 0;
8074                 }
8075                 cm_ReleaseSCache(scp);
8076                 scp = targetScp;
8077             }
8078         }
8079
8080         if (scp->fileType != CM_SCACHETYPE_FILE) {
8081             if (checkDoneRequired)
8082                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8083             if (dscp)
8084                 cm_ReleaseSCache(dscp);
8085             cm_ReleaseSCache(scp);
8086             cm_ReleaseUser(userp);
8087             free(realPathp);
8088             return CM_ERROR_ISDIR;
8089         }
8090     }
8091
8092     /* (only applies to single component case) */
8093     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8094         if (checkDoneRequired)
8095             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8096         cm_ReleaseSCache(scp);
8097         if (dscp)
8098             cm_ReleaseSCache(dscp);
8099         cm_ReleaseUser(userp);
8100         free(realPathp);
8101         return CM_ERROR_NOTDIR;
8102     }
8103
8104     /* open the file itself */
8105     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8106     osi_assertx(fidp, "null smb_fid_t");
8107
8108     /* save a reference to the user */
8109     cm_HoldUser(userp);
8110     fidp->userp = userp;
8111
8112     /* If we are restricting sharing, we should do so with a suitable
8113        share lock. */
8114     if (scp->fileType == CM_SCACHETYPE_FILE &&
8115         !(fidflags & SMB_FID_SHARE_WRITE)) {
8116         cm_key_t key;
8117         LARGE_INTEGER LOffset, LLength;
8118         int sLockType;
8119
8120         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8121         LOffset.LowPart = SMB_FID_QLOCK_LOW;
8122         LLength.HighPart = 0;
8123         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8124
8125         /* If we are not opening the file for writing, then we don't
8126            try to get an exclusive lock.  No one else should be able to
8127            get an exclusive lock on the file anyway, although someone
8128            else can get a shared lock. */
8129         if ((fidflags & SMB_FID_SHARE_READ) ||
8130             !(fidflags & SMB_FID_OPENWRITE)) {
8131             sLockType = LOCKING_ANDX_SHARED_LOCK;
8132         } else {
8133             sLockType = 0;
8134         }
8135
8136         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8137
8138         lock_ObtainWrite(&scp->rw);
8139         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8140         lock_ReleaseWrite(&scp->rw);
8141
8142         if (code) {
8143             if (checkDoneRequired)
8144                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8145             cm_ReleaseSCache(scp);
8146             if (dscp)
8147                 cm_ReleaseSCache(dscp);
8148             cm_ReleaseUser(userp);
8149             /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
8150             smb_CloseFID(vcp, fidp, NULL, 0);
8151             smb_ReleaseFID(fidp);
8152             free(realPathp);
8153             return CM_ERROR_SHARING_VIOLATION;
8154         }
8155     }
8156
8157     /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
8158     if (checkDoneRequired) {
8159         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8160         checkDoneRequired = 0;
8161     }
8162
8163     lock_ObtainMutex(&fidp->mx);
8164     /* save a pointer to the vnode */
8165     fidp->scp = scp;    /* Hold transfered to fidp->scp and no longer needed */
8166     lock_ObtainWrite(&scp->rw);
8167     scp->flags |= CM_SCACHEFLAG_SMB_FID;
8168     lock_ReleaseWrite(&scp->rw);
8169     osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
8170
8171     fidp->flags = fidflags;
8172
8173     /* remember if the file was newly created */
8174     if (created)
8175         fidp->flags |= SMB_FID_CREATED;
8176
8177     /* save parent dir and pathname for delete or change notification */
8178     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8179         osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
8180         fidp->flags |= SMB_FID_NTOPEN;
8181         fidp->NTopen_dscp = dscp;
8182         dscp = NULL;
8183         fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8184     }
8185     fidp->NTopen_wholepathp = realPathp;
8186     lock_ReleaseMutex(&fidp->mx);
8187
8188     /* we don't need this any longer */
8189     if (dscp) {
8190         cm_ReleaseSCache(dscp);
8191         dscp = NULL;
8192     }
8193
8194     cm_Open(scp, 0, userp);
8195
8196     /* set inp->fid so that later read calls in same msg can find fid */
8197     inp->fid = fidp->fid;
8198
8199     lock_ObtainRead(&scp->rw);
8200
8201     /*
8202      * Always send the standard response.  Sending the extended
8203      * response results in the Explorer Shell being unable to
8204      * access directories at random times.
8205      */
8206     if (1 /*!extendedRespRequired */) {
8207         /* out parms */
8208         parmSlot = 2;
8209         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
8210         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8211         smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8212         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8213         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8214         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8215         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8216         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8217         smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8218         parmSlot += 2;
8219         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8220         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8221         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
8222         smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8223         parmSlot++;     /* dev state */
8224         smb_SetSMBParmByte(outp, parmSlot,
8225                             (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8226                               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8227                               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8228         smb_SetSMBDataLength(outp, 0);
8229     } else {
8230         /* out parms */
8231         parmSlot = 2;
8232         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
8233         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
8234         smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
8235         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8236         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8237         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8238         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8239         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
8240         smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
8241         parmSlot += 2;
8242         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8243         smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
8244         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
8245         smb_SetSMBParm(outp, parmSlot, NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS);
8246         parmSlot++;     /* dev state */
8247         smb_SetSMBParmByte(outp, parmSlot,
8248                             (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8249                               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8250                               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
8251         /* Setting the GUID results in a failure with cygwin */
8252         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8253         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8254         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8255         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8256         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8257         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8258         /* Maxmimal access rights */
8259         smb_SetSMBParmLong(outp, parmSlot, 0x001f01ff); parmSlot += 2;
8260         /* Guest access rights */
8261         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8262         smb_SetSMBDataLength(outp, 0);
8263     }
8264
8265     if ((fidp->flags & SMB_FID_EXECUTABLE) &&
8266         LargeIntegerGreaterThanZero(scp->length) &&
8267         !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8268         prefetch = 1;
8269     }
8270     lock_ReleaseRead(&scp->rw);
8271
8272     if (prefetch)
8273         cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
8274                            scp->length.LowPart, scp->length.HighPart,
8275                            userp, &req);
8276
8277
8278     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
8279               osi_LogSaveClientString(smb_logp, realPathp));
8280
8281     cm_ReleaseUser(userp);
8282     smb_ReleaseFID(fidp);
8283
8284     /* Can't free realPathp if we get here since
8285        fidp->NTopen_wholepathp is pointing there */
8286
8287     /* leave scp held since we put it in fidp->scp */
8288     return 0;
8289 }
8290
8291 /*
8292  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
8293  * Instead, ultimately, would like to use a subroutine for common code.
8294  */
8295
8296 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
8297 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8298 {
8299     clientchar_t *pathp, *realPathp;
8300     long code = 0;
8301     cm_space_t *spacep;
8302     cm_user_t *userp;
8303     cm_scache_t *dscp;          /* parent dir */
8304     cm_scache_t *scp;           /* file to create or open */
8305     cm_scache_t *targetScp;     /* if scp is a symlink */
8306     cm_attr_t setAttr;
8307     clientchar_t *lastNamep;
8308     unsigned long nameLength;
8309     unsigned int flags;
8310     unsigned int requestOpLock;
8311     unsigned int requestBatchOpLock;
8312     unsigned int mustBeDir;
8313     unsigned int extendedRespRequired;
8314     int realDirFlag;
8315     unsigned int desiredAccess;
8316     unsigned int allocSize;
8317     unsigned int shareAccess;
8318     unsigned int extAttributes;
8319     unsigned int createDisp;
8320     unsigned int sdLen;
8321     unsigned int eaLen;
8322     unsigned int impLevel;
8323     unsigned int secFlags;
8324     unsigned int createOptions;
8325     unsigned short baseFid;
8326     smb_fid_t *baseFidp;
8327     smb_fid_t *fidp;
8328     cm_scache_t *baseDirp;
8329     unsigned short openAction;
8330     int parmSlot;
8331     long fidflags;
8332     FILETIME ft;
8333     clientchar_t *tidPathp;
8334     BOOL foundscp;
8335     int parmOffset, dataOffset;
8336     char *parmp;
8337     ULONG *lparmp;
8338     char *outData;
8339     cm_req_t req;
8340     int created = 0;
8341     int prefetch = 0;
8342     cm_lock_data_t *ldp = NULL;
8343     int checkDoneRequired = 0;
8344
8345     smb_InitReq(&req);
8346
8347     foundscp = FALSE;
8348     scp = NULL;
8349
8350     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8351         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8352     parmp = inp->data + parmOffset;
8353     lparmp = (ULONG *) parmp;
8354
8355     flags = lparmp[0];
8356     requestOpLock = flags & REQUEST_OPLOCK;
8357     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
8358     mustBeDir = flags & OPEN_DIRECTORY;
8359     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
8360
8361     /*
8362      * Why all of a sudden 32-bit FID?
8363      * We will reject all bits higher than 16.
8364      */
8365     if (lparmp[1] & 0xFFFF0000)
8366         return CM_ERROR_INVAL;
8367     baseFid = (unsigned short)lparmp[1];
8368     desiredAccess = lparmp[2];
8369     allocSize = lparmp[3];
8370     extAttributes = lparmp[5];
8371     shareAccess = lparmp[6];
8372     createDisp = lparmp[7];
8373     createOptions = lparmp[8];
8374     sdLen = lparmp[9];
8375     eaLen = lparmp[10];
8376     nameLength = lparmp[11];    /* spec says chars but appears to be bytes */
8377     impLevel = lparmp[12];
8378     secFlags = lparmp[13];
8379
8380     /* mustBeDir is never set; createOptions directory bit seems to be
8381      * more important
8382      */
8383     if (createOptions & FILE_DIRECTORY_FILE)
8384         realDirFlag = 1;
8385     else if (createOptions & FILE_NON_DIRECTORY_FILE)
8386         realDirFlag = 0;
8387     else
8388         realDirFlag = -1;
8389
8390     pathp = smb_ParseStringCb(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
8391                                nameLength, NULL, SMB_STRF_ANSIPATH);
8392     /* Sometimes path is not nul-terminated, so we make a copy. */
8393     realPathp = malloc(nameLength+sizeof(clientchar_t));
8394     memcpy(realPathp, pathp, nameLength);
8395     realPathp[nameLength/sizeof(clientchar_t)] = 0;
8396     spacep = cm_GetSpace();
8397     /* smb_StripLastComponent will strip "::$DATA" if present */
8398     smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
8399
8400     osi_Log1(smb_logp,"NTTranCreate %S",osi_LogSaveStringW(smb_logp,realPathp));
8401     osi_Log4(smb_logp,"... da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
8402     osi_Log4(smb_logp,"... co[%x],sdl[%x],eal[%x],as[%x],flags[%x]",createOptions,sdLen,eaLen,allocSize);
8403     osi_Log3(smb_logp,"... imp[%x],sec[%x],flags[%x]", impLevel, secFlags, flags);
8404
8405     if ( realDirFlag == 1 &&
8406          ( createDisp == FILE_SUPERSEDE ||
8407            createDisp == FILE_OVERWRITE ||
8408            createDisp == FILE_OVERWRITE_IF))
8409     {
8410         osi_Log0(smb_logp, "NTTranCreate rejecting invalid readDirFlag and createDisp combination");
8411         cm_FreeSpace(spacep);
8412         free(realPathp);
8413         return CM_ERROR_INVAL;
8414     }
8415
8416     /*
8417      * Nothing here to handle SMB_IOCTL_FILENAME.
8418      * Will add it if necessary.
8419      */
8420
8421     if (!cm_IsValidClientString(realPathp)) {
8422 #ifdef DEBUG
8423         clientchar_t * hexp;
8424
8425         hexp = cm_GetRawCharsAlloc(realPathp, -1);
8426         osi_Log1(smb_logp, "NTTranCreate rejecting invalid name. [%S]",
8427                  osi_LogSaveClientString(smb_logp, hexp));
8428         if (hexp)
8429         free(hexp);
8430 #else
8431         osi_Log0(smb_logp, "NTTranCreate rejecting invalid name.");
8432 #endif
8433         cm_FreeSpace(spacep);
8434         free(realPathp);
8435         return CM_ERROR_BADNTFILENAME;
8436     }
8437
8438     userp = smb_GetUserFromVCP(vcp, inp);
8439     if (!userp) {
8440         osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
8441         cm_FreeSpace(spacep);
8442         free(realPathp);
8443         return CM_ERROR_INVAL;
8444     }
8445
8446     if (baseFid == 0) {
8447         baseFidp = NULL;
8448         baseDirp = cm_RootSCachep(cm_rootUserp, &req);
8449         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8450         if (code == CM_ERROR_TIDIPC) {
8451             /* Attempt to use a TID allocated for IPC.  The client
8452              * is probably looking for DCE RPC end points which we
8453              * don't support OR it could be looking to make a DFS
8454              * referral request.
8455              */
8456             osi_Log0(smb_logp, "NTTranCreate received IPC TID");
8457 #ifndef DFS_SUPPORT
8458             cm_FreeSpace(spacep);
8459             free(realPathp);
8460             cm_ReleaseUser(userp);
8461             return CM_ERROR_NOSUCHPATH;
8462 #endif
8463         }
8464     } else {
8465         baseFidp = smb_FindFID(vcp, baseFid, 0);
8466         if (!baseFidp) {
8467             osi_Log2(smb_logp, "NTTranCreate Unknown SMB Fid vcp 0x%p fid %d",
8468                       vcp, baseFid);
8469             cm_FreeSpace(spacep);
8470             free(realPathp);
8471             cm_ReleaseUser(userp);
8472             return CM_ERROR_BADFD;
8473         }
8474
8475         if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8476             cm_FreeSpace(spacep);
8477             free(realPathp);
8478             cm_ReleaseUser(userp);
8479             smb_CloseFID(vcp, baseFidp, NULL, 0);
8480             smb_ReleaseFID(baseFidp);
8481             return CM_ERROR_NOSUCHPATH;
8482         }
8483
8484         baseDirp = baseFidp->scp;
8485         tidPathp = NULL;
8486     }
8487
8488     /* compute open mode */
8489     fidflags = 0;
8490     if (desiredAccess & DELETE)
8491         fidflags |= SMB_FID_OPENDELETE;
8492     if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
8493         fidflags |= SMB_FID_OPENREAD_LISTDIR;
8494     if (desiredAccess & AFS_ACCESS_WRITE)
8495         fidflags |= SMB_FID_OPENWRITE;
8496     if (createOptions & FILE_DELETE_ON_CLOSE)
8497         fidflags |= SMB_FID_DELONCLOSE;
8498     if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
8499         fidflags |= SMB_FID_SEQUENTIAL;
8500     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
8501         fidflags |= SMB_FID_RANDOM;
8502     if (createOptions & FILE_OPEN_REPARSE_POINT)
8503         osi_Log0(smb_logp, "NTTranCreate Open Reparse Point");
8504     if (smb_IsExecutableFileName(lastNamep))
8505         fidflags |= SMB_FID_EXECUTABLE;
8506
8507     /* And the share mode */
8508     if (shareAccess & FILE_SHARE_READ)
8509         fidflags |= SMB_FID_SHARE_READ;
8510     if (shareAccess & FILE_SHARE_WRITE)
8511         fidflags |= SMB_FID_SHARE_WRITE;
8512
8513     dscp = NULL;
8514     code = 0;
8515
8516     code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8517                     userp, tidPathp, &req, &dscp);
8518     if (code == 0) {
8519 #ifdef DFS_SUPPORT
8520         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8521             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8522             cm_ReleaseSCache(dscp);
8523             cm_ReleaseUser(userp);
8524             cm_FreeSpace(spacep);
8525             free(realPathp);
8526             if (baseFidp)
8527                 smb_ReleaseFID(baseFidp);
8528             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8529                 return CM_ERROR_PATH_NOT_COVERED;
8530             else
8531                 return CM_ERROR_NOSUCHPATH;
8532         }
8533 #endif /* DFS_SUPPORT */
8534         code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
8535                          userp, &req, &scp);
8536         if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
8537
8538             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp,
8539                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
8540             if (code == 0 && realDirFlag == 1 &&
8541                 (createDisp == FILE_OPEN ||
8542                  createDisp == FILE_OVERWRITE ||
8543                  createDisp == FILE_OVERWRITE_IF)) {
8544                 cm_ReleaseSCache(scp);
8545                 cm_ReleaseSCache(dscp);
8546                 cm_ReleaseUser(userp);
8547                 cm_FreeSpace(spacep);
8548                 free(realPathp);
8549                 if (baseFidp)
8550                     smb_ReleaseFID(baseFidp);
8551                 return CM_ERROR_EXISTS;
8552             }
8553         }
8554     } else {
8555         cm_ReleaseUser(userp);
8556         if (baseFidp)
8557             smb_ReleaseFID(baseFidp);
8558         cm_FreeSpace(spacep);
8559         free(realPathp);
8560         return CM_ERROR_NOSUCHPATH;
8561     }
8562
8563     if (code == 0)
8564         foundscp = TRUE;
8565
8566     if (code == CM_ERROR_NOSUCHFILE ||
8567         code == CM_ERROR_NOSUCHPATH ||
8568         code == CM_ERROR_BPLUS_NOMATCH ||
8569         (code == 0 && (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)))) {
8570         code = 0;
8571
8572         cm_FreeSpace(spacep);
8573
8574         if (baseFidp)
8575             smb_ReleaseFID(baseFidp);
8576
8577         if (code) {
8578             cm_ReleaseSCache(dscp);
8579             cm_ReleaseUser(userp);
8580             free(realPathp);
8581             return code;
8582         }
8583
8584         if (!lastNamep)
8585             lastNamep = realPathp;
8586         else
8587             lastNamep++;
8588
8589         if (!smb_IsLegalFilename(lastNamep)) {
8590             cm_ReleaseSCache(dscp);
8591             cm_ReleaseUser(userp);
8592             free(realPathp);
8593             return CM_ERROR_BADNTFILENAME;
8594         }
8595
8596         if (!foundscp) {
8597             if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF || createDisp == FILE_OPEN_IF) {
8598                 code = cm_Lookup(dscp, lastNamep,
8599                                   CM_FLAG_FOLLOW, userp, &req, &scp);
8600             } else {
8601                 code = cm_Lookup(dscp, lastNamep,
8602                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
8603                                  userp, &req, &scp);
8604             }
8605             if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8606                 cm_ReleaseSCache(dscp);
8607                 cm_ReleaseUser(userp);
8608                 free(realPathp);
8609                 return code;
8610             }
8611         }
8612     } else {
8613         if (baseFidp)
8614             smb_ReleaseFID(baseFidp);
8615         cm_FreeSpace(spacep);
8616     }
8617
8618     /* if we get here, if code is 0, the file exists and is represented by
8619      * scp.  Otherwise, we have to create it.  The dir may be represented
8620      * by dscp, or we may have found the file directly.  If code is non-zero,
8621      * scp is NULL.
8622      */
8623     if (code == 0) {
8624         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8625         if (code) {
8626             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8627             cm_ReleaseSCache(dscp);
8628             cm_ReleaseSCache(scp);
8629             cm_ReleaseUser(userp);
8630             free(realPathp);
8631             return code;
8632         }
8633         checkDoneRequired = 1;
8634
8635         if (createDisp == FILE_CREATE) {
8636             /* oops, file shouldn't be there */
8637             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8638             cm_ReleaseSCache(dscp);
8639             cm_ReleaseSCache(scp);
8640             cm_ReleaseUser(userp);
8641             free(realPathp);
8642             return CM_ERROR_EXISTS;
8643         }
8644
8645         if (createDisp == FILE_OVERWRITE ||
8646             createDisp == FILE_OVERWRITE_IF) {
8647             setAttr.mask = CM_ATTRMASK_LENGTH;
8648             setAttr.length.LowPart = 0;
8649             setAttr.length.HighPart = 0;
8650
8651             /* now watch for a symlink */
8652             code = 0;
8653             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8654                 targetScp = 0;
8655                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8656                 if (code == 0) {
8657                     /* we have a more accurate file to use (the
8658                     * target of the symbolic link).  Otherwise,
8659                     * we'll just use the symlink anyway.
8660                     */
8661                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
8662                               scp, targetScp);
8663                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8664                     cm_ReleaseSCache(scp);
8665                     scp = targetScp;
8666                     code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
8667                     if (code) {
8668                         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8669                         cm_ReleaseSCache(dscp);
8670                         if (scp)
8671                             cm_ReleaseSCache(scp);
8672                         cm_ReleaseUser(userp);
8673                         free(realPathp);
8674                         return code;
8675                     }
8676                 }
8677             }
8678             code = cm_SetAttr(scp, &setAttr, userp, &req);
8679             openAction = 3;     /* truncated existing file */
8680         }
8681         else openAction = 1;    /* found existing file */
8682     }
8683     else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
8684         /* don't create if not found */
8685         cm_ReleaseSCache(dscp);
8686         cm_ReleaseUser(userp);
8687         free(realPathp);
8688         return CM_ERROR_NOSUCHFILE;
8689     }
8690     else if (realDirFlag == 0 || realDirFlag == -1) {
8691         /* createDisp: FILE_SUPERSEDE, FILE_CREATE, FILE_OPEN_IF, FILE_OVERWRITE_IF */
8692         osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
8693                   osi_LogSaveClientString(smb_logp, lastNamep));
8694         openAction = 2;         /* created file */
8695         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8696         setAttr.clientModTime = time(NULL);
8697         smb_SetInitialModeBitsForFile(extAttributes, &setAttr);
8698
8699         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8700                           &req);
8701         if (code == 0) {
8702             created = 1;
8703             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8704                 smb_NotifyChange(FILE_ACTION_ADDED,
8705                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8706                                  dscp, lastNamep, NULL, TRUE);
8707         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
8708             /* Not an exclusive create, and someone else tried
8709              * creating it already, then we open it anyway.  We
8710              * don't bother retrying after this, since if this next
8711              * fails, that means that the file was deleted after we
8712              * started this call.
8713              */
8714             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8715                               userp, &req, &scp);
8716             if (code == 0) {
8717                 if (createDisp == FILE_OVERWRITE_IF) {
8718                     setAttr.mask = CM_ATTRMASK_LENGTH;
8719                     setAttr.length.LowPart = 0;
8720                     setAttr.length.HighPart = 0;
8721
8722                     /* now watch for a symlink */
8723                     code = 0;
8724                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8725                         targetScp = 0;
8726                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8727                         if (code == 0) {
8728                             /* we have a more accurate file to use (the
8729                             * target of the symbolic link).  Otherwise,
8730                             * we'll just use the symlink anyway.
8731                             */
8732                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
8733                                       scp, targetScp);
8734                             cm_ReleaseSCache(scp);
8735                             scp = targetScp;
8736                         }
8737                     }
8738                     code = cm_SetAttr(scp, &setAttr, userp, &req);
8739                 }
8740             }   /* lookup succeeded */
8741         }
8742     } else {
8743         /* create directory; createDisp: FILE_CREATE, FILE_OPEN_IF */
8744         osi_Log1(smb_logp,
8745                   "smb_ReceiveNTTranCreate creating directory %S",
8746                   osi_LogSaveClientString(smb_logp, lastNamep));
8747         openAction = 2;         /* created directory */
8748         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8749         setAttr.clientModTime = time(NULL);
8750         smb_SetInitialModeBitsForDir(extAttributes, &setAttr);
8751
8752         code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8753         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8754             smb_NotifyChange(FILE_ACTION_ADDED,
8755                               FILE_NOTIFY_CHANGE_DIR_NAME,
8756                               dscp, lastNamep, NULL, TRUE);
8757         if (code == 0 ||
8758             (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
8759             /* Not an exclusive create, and someone else tried
8760              * creating it already, then we open it anyway.  We
8761              * don't bother retrying after this, since if this next
8762              * fails, that means that the file was deleted after we
8763              * started this call.
8764              */
8765             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
8766                               userp, &req, &scp);
8767         }
8768     }
8769
8770     if (code) {
8771         /* something went wrong creating or truncating the file */
8772         if (checkDoneRequired)
8773             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8774         if (scp)
8775             cm_ReleaseSCache(scp);
8776         cm_ReleaseUser(userp);
8777         free(realPathp);
8778         return code;
8779     }
8780
8781     /* make sure we have file vs. dir right */
8782     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
8783         /* now watch for a symlink */
8784         code = 0;
8785         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
8786             targetScp = 0;
8787             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
8788             if (code == 0) {
8789                 /* we have a more accurate file to use (the
8790                 * target of the symbolic link).  Otherwise,
8791                 * we'll just use the symlink anyway.
8792                 */
8793                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
8794                           scp, targetScp);
8795                 if (checkDoneRequired) {
8796                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8797                     checkDoneRequired = 0;
8798                 }
8799                 cm_ReleaseSCache(scp);
8800                 scp = targetScp;
8801             }
8802         }
8803
8804         if (scp->fileType != CM_SCACHETYPE_FILE) {
8805             if (checkDoneRequired)
8806                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8807             cm_ReleaseSCache(scp);
8808             cm_ReleaseUser(userp);
8809             free(realPathp);
8810             return CM_ERROR_ISDIR;
8811         }
8812     }
8813
8814     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8815         if (checkDoneRequired)
8816             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8817         cm_ReleaseSCache(scp);
8818         cm_ReleaseUser(userp);
8819         free(realPathp);
8820         return CM_ERROR_NOTDIR;
8821     }
8822
8823     /* open the file itself */
8824     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8825     osi_assertx(fidp, "null smb_fid_t");
8826
8827     /* save a reference to the user */
8828     cm_HoldUser(userp);
8829     fidp->userp = userp;
8830
8831     /* If we are restricting sharing, we should do so with a suitable
8832        share lock. */
8833     if (scp->fileType == CM_SCACHETYPE_FILE &&
8834         !(fidflags & SMB_FID_SHARE_WRITE)) {
8835         cm_key_t key;
8836         LARGE_INTEGER LOffset, LLength;
8837         int sLockType;
8838
8839         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8840         LOffset.LowPart = SMB_FID_QLOCK_LOW;
8841         LLength.HighPart = 0;
8842         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8843
8844         /* Similar to what we do in handling NTCreateX.  We get a
8845            shared lock if we are only opening the file for reading. */
8846         if ((fidflags & SMB_FID_SHARE_READ) ||
8847             !(fidflags & SMB_FID_OPENWRITE)) {
8848             sLockType = LOCKING_ANDX_SHARED_LOCK;
8849         } else {
8850             sLockType = 0;
8851         }
8852
8853         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8854
8855         lock_ObtainWrite(&scp->rw);
8856         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8857         lock_ReleaseWrite(&scp->rw);
8858
8859         if (code) {
8860             if (checkDoneRequired)
8861                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8862             cm_ReleaseSCache(scp);
8863             cm_ReleaseUser(userp);
8864             /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
8865             smb_CloseFID(vcp, fidp, NULL, 0);
8866             smb_ReleaseFID(fidp);
8867             free(realPathp);
8868             return CM_ERROR_SHARING_VIOLATION;
8869         }
8870     }
8871
8872     /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8873     if (checkDoneRequired) {
8874         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8875         checkDoneRequired = 0;
8876     }
8877
8878     lock_ObtainMutex(&fidp->mx);
8879     /* save a pointer to the vnode */
8880     fidp->scp = scp;
8881     lock_ObtainWrite(&scp->rw);
8882     scp->flags |= CM_SCACHEFLAG_SMB_FID;
8883     lock_ReleaseWrite(&scp->rw);
8884     osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8885
8886     fidp->flags = fidflags;
8887
8888     /* remember if the file was newly created */
8889     if (created)
8890         fidp->flags |= SMB_FID_CREATED;
8891
8892     /* save parent dir and pathname for deletion or change notification */
8893     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8894         fidp->flags |= SMB_FID_NTOPEN;
8895         fidp->NTopen_dscp = dscp;
8896         osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8897         dscp = NULL;
8898         fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8899     }
8900     fidp->NTopen_wholepathp = realPathp;
8901     lock_ReleaseMutex(&fidp->mx);
8902
8903     /* we don't need this any longer */
8904     if (dscp)
8905         cm_ReleaseSCache(dscp);
8906
8907     cm_Open(scp, 0, userp);
8908
8909     /* set inp->fid so that later read calls in same msg can find fid */
8910     inp->fid = fidp->fid;
8911
8912     /* check whether we are required to send an extended response */
8913     if (!extendedRespRequired) {
8914         /* out parms */
8915         parmOffset = 8*4 + 39;
8916         parmOffset += 1;        /* pad to 4 */
8917         dataOffset = parmOffset + 70;
8918
8919         parmSlot = 1;
8920         outp->oddByte = 1;
8921         /* Total Parameter Count */
8922         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8923         /* Total Data Count */
8924         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8925         /* Parameter Count */
8926         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8927         /* Parameter Offset */
8928         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8929         /* Parameter Displacement */
8930         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8931         /* Data Count */
8932         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8933         /* Data Offset */
8934         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8935         /* Data Displacement */
8936         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8937         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
8938         smb_SetSMBDataLength(outp, 70);
8939
8940         lock_ObtainRead(&scp->rw);
8941         outData = smb_GetSMBData(outp, NULL);
8942         outData++;                      /* round to get to parmOffset */
8943         *outData = 0; outData++;        /* oplock */
8944         *outData = 0; outData++;        /* reserved */
8945         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8946         *((ULONG *)outData) = openAction; outData += 4;
8947         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
8948         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8949         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
8950         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
8951         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
8952         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
8953         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8954         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8955         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8956         *((USHORT *)outData) = 0; outData += 2; /* filetype */
8957         *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
8958         outData += 2;   /* dev state */
8959         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8960                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8961                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8962         outData += 2;   /* is a dir? */
8963     } else {
8964         /* out parms */
8965         parmOffset = 8*4 + 39;
8966         parmOffset += 1;        /* pad to 4 */
8967         dataOffset = parmOffset + 104;
8968
8969         parmSlot = 1;
8970         outp->oddByte = 1;
8971         /* Total Parameter Count */
8972         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8973         /* Total Data Count */
8974         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8975         /* Parameter Count */
8976         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8977         /* Parameter Offset */
8978         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8979         /* Parameter Displacement */
8980         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8981         /* Data Count */
8982         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8983         /* Data Offset */
8984         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8985         /* Data Displacement */
8986         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8987         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
8988         smb_SetSMBDataLength(outp, 105);
8989
8990         lock_ObtainRead(&scp->rw);
8991         outData = smb_GetSMBData(outp, NULL);
8992         outData++;                      /* round to get to parmOffset */
8993         *outData = 0; outData++;        /* oplock */
8994         *outData = 1; outData++;        /* response type */
8995         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8996         *((ULONG *)outData) = openAction; outData += 4;
8997         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
8998         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8999         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
9000         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
9001         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
9002         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
9003         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
9004         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
9005         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
9006         *((USHORT *)outData) = 0; outData += 2; /* filetype */
9007         *((USHORT *)outData) = NO_REPARSETAG|NO_SUBSTREAMS|NO_EAS;
9008         outData += 2;   /* dev state */
9009         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
9010                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
9011                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
9012         outData += 1;   /* is a dir? */
9013         /* Setting the GUID results in failures with cygwin */
9014         memset(outData,0,24); outData += 24; /* GUID */
9015         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
9016         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
9017     }
9018
9019     if ((fidp->flags & SMB_FID_EXECUTABLE) &&
9020          LargeIntegerGreaterThanZero(scp->length) &&
9021          !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
9022         prefetch = 1;
9023     }
9024     lock_ReleaseRead(&scp->rw);
9025
9026     if (prefetch)
9027         cm_QueueBKGRequest(scp, cm_BkgPrefetch, 0, 0,
9028                            scp->length.LowPart, scp->length.HighPart,
9029                            userp, &req);
9030
9031     osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
9032
9033     cm_ReleaseUser(userp);
9034     smb_ReleaseFID(fidp);
9035
9036     /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
9037     /* leave scp held since we put it in fidp->scp */
9038     return 0;
9039 }
9040
9041 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
9042 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
9043         smb_packet_t *outp)
9044 {
9045     smb_packet_t *savedPacketp;
9046     ULONG filter;
9047     USHORT fid, watchtree;
9048     smb_fid_t *fidp;
9049     cm_scache_t *scp;
9050
9051     filter = smb_GetSMBParm(inp, 19) |
9052              (smb_GetSMBParm(inp, 20) << 16);
9053     fid = smb_GetSMBParm(inp, 21);
9054     watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
9055
9056     fidp = smb_FindFID(vcp, fid, 0);
9057     if (!fidp) {
9058         osi_Log2(smb_logp, "NotifyChange Unknown SMB Fid vcp 0x%p fid %d",
9059                  vcp, fid);
9060         return CM_ERROR_BADFD;
9061     }
9062
9063     lock_ObtainMutex(&fidp->mx);
9064     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
9065         lock_ReleaseMutex(&fidp->mx);
9066         smb_CloseFID(vcp, fidp, NULL, 0);
9067         smb_ReleaseFID(fidp);
9068         return CM_ERROR_NOSUCHFILE;
9069     }
9070     scp = fidp->scp;
9071     cm_HoldSCache(scp);
9072     lock_ReleaseMutex(&fidp->mx);
9073
9074     /* Create a copy of the Directory Watch Packet to use when sending the
9075      * notification if in the future a matching change is detected.
9076      */
9077     savedPacketp = smb_CopyPacket(inp);
9078     if (vcp != savedPacketp->vcp) {
9079         smb_HoldVC(vcp);
9080         if (savedPacketp->vcp)
9081             smb_ReleaseVC(savedPacketp->vcp);
9082         savedPacketp->vcp = vcp;
9083     }
9084
9085     /* Add the watch to the list of events to send notifications for */
9086     lock_ObtainMutex(&smb_Dir_Watch_Lock);
9087     savedPacketp->nextp = smb_Directory_Watches;
9088     smb_Directory_Watches = savedPacketp;
9089     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9090
9091     osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"",
9092               fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
9093     osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
9094              filter, fid, watchtree);
9095     if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9096         osi_Log0(smb_logp, "      Notify Change File Name");
9097     if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9098         osi_Log0(smb_logp, "      Notify Change Directory Name");
9099     if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9100         osi_Log0(smb_logp, "      Notify Change Attributes");
9101     if (filter & FILE_NOTIFY_CHANGE_SIZE)
9102         osi_Log0(smb_logp, "      Notify Change Size");
9103     if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9104         osi_Log0(smb_logp, "      Notify Change Last Write");
9105     if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9106         osi_Log0(smb_logp, "      Notify Change Last Access");
9107     if (filter & FILE_NOTIFY_CHANGE_CREATION)
9108         osi_Log0(smb_logp, "      Notify Change Creation");
9109     if (filter & FILE_NOTIFY_CHANGE_EA)
9110         osi_Log0(smb_logp, "      Notify Change Extended Attributes");
9111     if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9112         osi_Log0(smb_logp, "      Notify Change Security");
9113     if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9114         osi_Log0(smb_logp, "      Notify Change Stream Name");
9115     if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9116         osi_Log0(smb_logp, "      Notify Change Stream Size");
9117     if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9118         osi_Log0(smb_logp, "      Notify Change Stream Write");
9119
9120     lock_ObtainWrite(&scp->rw);
9121     if (watchtree)
9122         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
9123     else
9124         scp->flags |= CM_SCACHEFLAG_WATCHED;
9125     lock_ReleaseWrite(&scp->rw);
9126     cm_ReleaseSCache(scp);
9127     smb_ReleaseFID(fidp);
9128
9129     outp->flags |= SMB_PACKETFLAG_NOSEND;
9130     return 0;
9131 }
9132
9133 unsigned char nullSecurityDesc[] = {
9134     0x01,                               /* security descriptor revision */
9135     0x00,                               /* reserved, should be zero */
9136     0x04, 0x80,                         /* security descriptor control;
9137                                          * 0x0004 : null-DACL present - everyone has full access
9138                                          * 0x8000 : relative format */
9139     0x14, 0x00, 0x00, 0x00,             /* offset of owner SID */
9140     0x20, 0x00, 0x00, 0x00,             /* offset of group SID */
9141     0x00, 0x00, 0x00, 0x00,             /* offset of DACL would go here */
9142     0x00, 0x00, 0x00, 0x00,             /* offset of SACL would go here */
9143     0x01, 0x01, 0x00, 0x00,             /* "everyone SID" owner SID */
9144     0x00, 0x00, 0x00, 0x01,
9145     0x00, 0x00, 0x00, 0x00,
9146     0x01, 0x01, 0x00, 0x00,             /* "everyone SID" owner SID */
9147     0x00, 0x00, 0x00, 0x01,
9148     0x00, 0x00, 0x00, 0x00
9149 };
9150
9151 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
9152 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9153 {
9154     int parmOffset, parmCount, dataOffset, dataCount;
9155     int totalParmCount, totalDataCount;
9156     int parmSlot;
9157     int maxData, maxParm;
9158     int inTotalParm, inTotalData;
9159     int inParm, inData;
9160     int inParmOffset, inDataOffset;
9161     char *outData;
9162     char *parmp;
9163     USHORT *sparmp;
9164     ULONG *lparmp;
9165     USHORT fid;
9166     ULONG securityInformation;
9167     smb_fid_t *fidp;
9168     long code = 0;
9169     DWORD dwLength;
9170
9171     /*
9172      * For details on the meanings of the various
9173      * SMB_COM_TRANSACTION fields, see sections 2.2.4.33
9174      * of http://msdn.microsoft.com/en-us/library/ee442092%28PROT.13%29.aspx
9175      */
9176
9177     inTotalParm = smb_GetSMBOffsetParm(inp, 1, 1)
9178         | (smb_GetSMBOffsetParm(inp, 2, 1) << 16);
9179
9180     inTotalData = smb_GetSMBOffsetParm(inp, 3, 1)
9181         | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
9182
9183     maxParm = smb_GetSMBOffsetParm(inp, 5, 1)
9184         | (smb_GetSMBOffsetParm(inp, 6, 1) << 16);
9185
9186     maxData = smb_GetSMBOffsetParm(inp, 7, 1)
9187         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
9188
9189     inParm = smb_GetSMBOffsetParm(inp, 9, 1)
9190         | (smb_GetSMBOffsetParm(inp, 10, 1) << 16);
9191
9192     inParmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
9193         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
9194
9195     inData = smb_GetSMBOffsetParm(inp, 13, 1)
9196         | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
9197
9198     inDataOffset = smb_GetSMBOffsetParm(inp, 15, 1)
9199         | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
9200
9201     parmp = inp->data + inParmOffset;
9202     sparmp = (USHORT *) parmp;
9203     lparmp = (ULONG *) parmp;
9204
9205     fid = sparmp[0];
9206     securityInformation = lparmp[1];
9207
9208     fidp = smb_FindFID(vcp, fid, 0);
9209     if (!fidp) {
9210         osi_Log2(smb_logp, "smb_ReceiveNTTranQuerySecurityDesc Unknown SMB Fid vcp 0x%p fid %d",
9211                  vcp, fid);
9212         return CM_ERROR_BADFD;
9213     }
9214
9215     lock_ObtainMutex(&fidp->mx);
9216     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
9217         lock_ReleaseMutex(&fidp->mx);
9218         smb_CloseFID(vcp, fidp, NULL, 0);
9219         smb_ReleaseFID(fidp);
9220         return CM_ERROR_NOSUCHFILE;
9221     }
9222     lock_ReleaseMutex(&fidp->mx);
9223
9224     osi_Log4(smb_logp,"smb_ReceiveNTTranQuerySecurityDesc fidp 0x%p scp 0x%p file \"%S\" Info=0x%x",
9225               fidp, fidp->scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp),
9226               securityInformation);
9227
9228     smb_ReleaseFID(fidp);
9229
9230     if ( securityInformation & ~(OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION) )
9231     {
9232         code = CM_ERROR_BAD_LEVEL;
9233         goto done;
9234     }
9235
9236     dwLength = sizeof( nullSecurityDesc);
9237
9238     totalDataCount = dwLength;
9239     totalParmCount = 4;
9240
9241     if (maxData >= totalDataCount) {
9242         dataCount = totalDataCount;
9243         parmCount = min(totalParmCount, maxParm);
9244     } else if (maxParm >= totalParmCount) {
9245         totalDataCount = dataCount = 0;
9246         parmCount = totalParmCount;
9247     } else {
9248         totalDataCount = dataCount = 0;
9249         totalParmCount = parmCount = 0;
9250     }
9251
9252     /* out parms */
9253     parmOffset = 8*4 + 39;
9254     parmOffset += 1;    /* pad to 4 */
9255
9256     dataOffset = parmOffset + parmCount;
9257
9258     parmSlot = 1;
9259     outp->oddByte = 1;
9260     /* Total Parameter Count */
9261     smb_SetSMBParmLong(outp, parmSlot, totalParmCount); parmSlot += 2;
9262     /* Total Data Count */
9263     smb_SetSMBParmLong(outp, parmSlot, totalDataCount); parmSlot += 2;
9264     /* Parameter Count */
9265     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
9266     /* Parameter Offset */
9267     smb_SetSMBParmLong(outp, parmSlot, parmCount ? parmOffset : 0); parmSlot += 2;
9268     /* Parameter Displacement */
9269     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9270     /* Data Count */
9271     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
9272     /* Data Offset */
9273     smb_SetSMBParmLong(outp, parmSlot, dataCount ? dataOffset : 0); parmSlot += 2;
9274     /* Data Displacement */
9275     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
9276     /* Setup Count */
9277     smb_SetSMBParmByte(outp, parmSlot, 0);
9278
9279     if (parmCount == totalParmCount && dwLength == dataCount) {
9280         smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
9281
9282         /* Data */
9283         outData = smb_GetSMBData(outp, NULL);
9284         outData++;                      /* round to get to dataOffset */
9285
9286         *((ULONG *)outData) = dataCount; outData += 4;  /* SD Length (4 bytes) */
9287         memcpy(outData, nullSecurityDesc, dataCount);
9288         outData += dataCount;
9289
9290         code = 0;
9291     } else if (parmCount >= 4) {
9292         smb_SetSMBDataLength(outp, 1 + parmCount);
9293
9294         /* Data */
9295         outData = smb_GetSMBData(outp, NULL);
9296         outData++;                      /* round to get to dataOffset */
9297
9298         *((ULONG *)outData) = dwLength; outData += 4;   /* SD Length (4 bytes) */
9299         code = CM_ERROR_BUFFERTOOSMALL;
9300     } else {
9301         smb_SetSMBDataLength(outp, 0);
9302         code = CM_ERROR_BUFFER_OVERFLOW;
9303     }
9304
9305   done:
9306     return code;
9307 }
9308
9309 /* SMB_COM_NT_TRANSACT
9310
9311    SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
9312  */
9313 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9314 {
9315     unsigned short function;
9316
9317     function = smb_GetSMBParm(inp, 18);
9318
9319     osi_Log1(smb_logp, "SMB NT Transact function %d", function);
9320
9321     /* We can handle long names */
9322     if (vcp->flags & SMB_VCFLAG_USENT)
9323         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
9324
9325     switch (function) {
9326     case 1:                     /* NT_TRANSACT_CREATE */
9327         return smb_ReceiveNTTranCreate(vcp, inp, outp);
9328     case 2:                     /* NT_TRANSACT_IOCTL */
9329         osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
9330         break;
9331     case 3:                     /* NT_TRANSACT_SET_SECURITY_DESC */
9332         osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
9333         break;
9334     case 4:                     /* NT_TRANSACT_NOTIFY_CHANGE */
9335         return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
9336     case 5:                     /* NT_TRANSACT_RENAME */
9337         osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
9338         break;
9339     case 6:                     /* NT_TRANSACT_QUERY_SECURITY_DESC */
9340         return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
9341     case 7:
9342         osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
9343         break;
9344     case 8:
9345         osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
9346         break;
9347     }
9348     return CM_ERROR_BADOP;
9349 }
9350
9351 /*
9352  * smb_NotifyChange -- find relevant change notification messages and
9353  *                     reply to them
9354  *
9355  * If we don't know the file name (i.e. a callback break), filename is
9356  * NULL, and we return a zero-length list.
9357  *
9358  * At present there is not a single call to smb_NotifyChange that
9359  * has the isDirectParent parameter set to FALSE.
9360  */
9361 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
9362         cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
9363         BOOL isDirectParent)
9364 {
9365     smb_packet_t *watch, *lastWatch, *nextWatch;
9366     ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
9367     char *outData, *oldOutData;
9368     ULONG filter;
9369     USHORT fid, wtree;
9370     ULONG maxLen;
9371     BOOL twoEntries = FALSE;
9372     ULONG otherNameLen, oldParmCount = 0;
9373     DWORD otherAction;
9374     smb_fid_t *fidp;
9375
9376     /* Get ready for rename within directory */
9377     if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
9378         twoEntries = TRUE;
9379         otherAction = FILE_ACTION_RENAMED_NEW_NAME;
9380     }
9381
9382     osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
9383              osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
9384     if (action == 0)
9385         osi_Log0(smb_logp,"      FILE_ACTION_NONE");
9386     if (action == FILE_ACTION_ADDED)
9387         osi_Log0(smb_logp,"      FILE_ACTION_ADDED");
9388     if (action == FILE_ACTION_REMOVED)
9389         osi_Log0(smb_logp,"      FILE_ACTION_REMOVED");
9390     if (action == FILE_ACTION_MODIFIED)
9391         osi_Log0(smb_logp,"      FILE_ACTION_MODIFIED");
9392     if (action == FILE_ACTION_RENAMED_OLD_NAME)
9393         osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_OLD_NAME");
9394     if (action == FILE_ACTION_RENAMED_NEW_NAME)
9395         osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_NEW_NAME");
9396
9397     lock_ObtainMutex(&smb_Dir_Watch_Lock);
9398     watch = smb_Directory_Watches;
9399     while (watch) {
9400         filter = smb_GetSMBParm(watch, 19)
9401             | (smb_GetSMBParm(watch, 20) << 16);
9402         fid = smb_GetSMBParm(watch, 21);
9403         wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
9404
9405         maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
9406             | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
9407
9408         /*
9409          * Strange hack - bug in NT Client and NT Server that we must emulate?
9410          */
9411         if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
9412             filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
9413
9414         fidp = smb_FindFID(watch->vcp, fid, 0);
9415         if (!fidp) {
9416             osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
9417             lastWatch = watch;
9418             watch = watch->nextp;
9419             continue;
9420         }
9421
9422         if (fidp->scp != dscp ||
9423             fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
9424             (filter & notifyFilter) == 0 ||
9425             (!isDirectParent && !wtree))
9426         {
9427             osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
9428             lastWatch = watch;
9429             watch = watch->nextp;
9430             smb_ReleaseFID(fidp);
9431             continue;
9432         }
9433
9434         osi_Log4(smb_logp,
9435                   "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
9436                   fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
9437         if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
9438             osi_Log0(smb_logp, "      Notify Change File Name");
9439         if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
9440             osi_Log0(smb_logp, "      Notify Change Directory Name");
9441         if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
9442             osi_Log0(smb_logp, "      Notify Change Attributes");
9443         if (filter & FILE_NOTIFY_CHANGE_SIZE)
9444             osi_Log0(smb_logp, "      Notify Change Size");
9445         if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
9446             osi_Log0(smb_logp, "      Notify Change Last Write");
9447         if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
9448             osi_Log0(smb_logp, "      Notify Change Last Access");
9449         if (filter & FILE_NOTIFY_CHANGE_CREATION)
9450             osi_Log0(smb_logp, "      Notify Change Creation");
9451         if (filter & FILE_NOTIFY_CHANGE_EA)
9452             osi_Log0(smb_logp, "      Notify Change Extended Attributes");
9453         if (filter & FILE_NOTIFY_CHANGE_SECURITY)
9454             osi_Log0(smb_logp, "      Notify Change Security");
9455         if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
9456             osi_Log0(smb_logp, "      Notify Change Stream Name");
9457         if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
9458             osi_Log0(smb_logp, "      Notify Change Stream Size");
9459         if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
9460             osi_Log0(smb_logp, "      Notify Change Stream Write");
9461
9462         /* A watch can only be notified once.  Remove it from the list */
9463         nextWatch = watch->nextp;
9464         if (watch == smb_Directory_Watches)
9465             smb_Directory_Watches = nextWatch;
9466         else
9467             lastWatch->nextp = nextWatch;
9468
9469         /* Turn off WATCHED flag in dscp */
9470         lock_ObtainWrite(&dscp->rw);
9471         if (wtree)
9472             dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9473         else
9474             dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
9475         lock_ReleaseWrite(&dscp->rw);
9476
9477         /* Convert to response packet */
9478         ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
9479 #ifdef SEND_CANONICAL_PATHNAMES
9480         ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
9481 #endif
9482         ((smb_t *) watch)->wct = 0;
9483
9484         /* out parms */
9485         if (filename == NULL) {
9486             parmCount = 0;
9487         } else {
9488             nameLen = (ULONG)cm_ClientStrLen(filename);
9489             parmCount = 3*4 + nameLen*2;
9490             parmCount = (parmCount + 3) & ~3;   /* pad to 4 */
9491             if (twoEntries) {
9492                 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
9493                 oldParmCount = parmCount;
9494                 parmCount += 3*4 + otherNameLen*2;
9495                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
9496             }
9497             if (maxLen < parmCount)
9498                 parmCount = 0;  /* not enough room */
9499         }
9500         parmOffset = 8*4 + 39;
9501         parmOffset += 1;                        /* pad to 4 */
9502         dataOffset = parmOffset + parmCount;
9503
9504         parmSlot = 1;
9505         watch->oddByte = 1;
9506         /* Total Parameter Count */
9507         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9508         /* Total Data Count */
9509         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9510         /* Parameter Count */
9511         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
9512         /* Parameter Offset */
9513         smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
9514         /* Parameter Displacement */
9515         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9516         /* Data Count */
9517         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9518         /* Data Offset */
9519         smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
9520         /* Data Displacement */
9521         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
9522         smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
9523         smb_SetSMBDataLength(watch, parmCount + 1);
9524
9525         if (parmCount != 0) {
9526             outData = smb_GetSMBData(watch, NULL);
9527             outData++;  /* round to get to parmOffset */
9528             oldOutData = outData;
9529             *((DWORD *)outData) = oldParmCount; outData += 4;
9530             /* Next Entry Offset */
9531             *((DWORD *)outData) = action; outData += 4;
9532             /* Action */
9533             *((DWORD *)outData) = nameLen*2; outData += 4;
9534             /* File Name Length */
9535
9536             smb_UnparseString(watch, outData, filename, NULL, 0);
9537             /* File Name */
9538
9539             if (twoEntries) {
9540                 outData = oldOutData + oldParmCount;
9541                 *((DWORD *)outData) = 0; outData += 4;
9542                 /* Next Entry Offset */
9543                 *((DWORD *)outData) = otherAction; outData += 4;
9544                 /* Action */
9545                 *((DWORD *)outData) = otherNameLen*2;
9546                 outData += 4;   /* File Name Length */
9547                 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
9548             }
9549         }
9550
9551         /*
9552          * If filename is null, we don't know the cause of the
9553          * change notification.  We return zero data (see above),
9554          * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
9555          * (= 0x010C).  We set the error code here by hand, without
9556          * modifying wct and bcc.
9557          */
9558         if (filename == NULL) {
9559             ((smb_t *) watch)->rcls = 0x0C;
9560             ((smb_t *) watch)->reh = 0x01;
9561             ((smb_t *) watch)->errLow = 0;
9562             ((smb_t *) watch)->errHigh = 0;
9563             /* Set NT Status codes flag */
9564             ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9565         }
9566
9567         smb_SendPacket(watch->vcp, watch);
9568         smb_FreePacket(watch);
9569
9570         smb_ReleaseFID(fidp);
9571         watch = nextWatch;
9572     }
9573     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9574 }
9575
9576 /* SMB_COM_NT_CANCEL */
9577 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9578 {
9579     unsigned char *replyWctp;
9580     smb_packet_t *watch, *lastWatch;
9581     USHORT fid, watchtree;
9582     smb_fid_t *fidp;
9583     cm_scache_t *scp;
9584
9585     osi_Log0(smb_logp, "SMB3 receive NT cancel");
9586
9587     lock_ObtainMutex(&smb_Dir_Watch_Lock);
9588     watch = smb_Directory_Watches;
9589     while (watch) {
9590         if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
9591              && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
9592              && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
9593              && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
9594             if (watch == smb_Directory_Watches)
9595                 smb_Directory_Watches = watch->nextp;
9596             else
9597                 lastWatch->nextp = watch->nextp;
9598             lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9599
9600             /* Turn off WATCHED flag in scp */
9601             fid = smb_GetSMBParm(watch, 21);
9602             watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
9603
9604             if (vcp != watch->vcp)
9605                 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x",
9606                           vcp, watch->vcp);
9607
9608             fidp = smb_FindFID(vcp, fid, 0);
9609             if (fidp) {
9610                 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S",
9611                          fid, watchtree,
9612                          (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
9613
9614                 scp = fidp->scp;
9615                 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
9616                 if (scp) {
9617                     lock_ObtainWrite(&scp->rw);
9618                     if (watchtree)
9619                         scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
9620                     else
9621                         scp->flags &= ~CM_SCACHEFLAG_WATCHED;
9622                     lock_ReleaseWrite(&scp->rw);
9623                 }
9624                 smb_ReleaseFID(fidp);
9625             } else {
9626                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
9627             }
9628
9629             /* assume STATUS32; return 0xC0000120 (CANCELED) */
9630             replyWctp = watch->wctp;
9631             *replyWctp++ = 0;
9632             *replyWctp++ = 0;
9633             *replyWctp++ = 0;
9634             ((smb_t *)watch)->rcls = 0x20;
9635             ((smb_t *)watch)->reh = 0x1;
9636             ((smb_t *)watch)->errLow = 0;
9637             ((smb_t *)watch)->errHigh = 0xC0;
9638             ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9639             smb_SendPacket(vcp, watch);
9640             smb_FreePacket(watch);
9641             return 0;
9642         }
9643         lastWatch = watch;
9644         watch = watch->nextp;
9645     }
9646     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
9647
9648     return 0;
9649 }
9650
9651 /*
9652  * NT rename also does hard links.
9653  */
9654
9655 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
9656 #define RENAME_FLAG_HARD_LINK                0x103
9657 #define RENAME_FLAG_RENAME                   0x104
9658 #define RENAME_FLAG_COPY                     0x105
9659
9660 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
9661 {
9662     clientchar_t *oldPathp, *newPathp;
9663     long code = 0;
9664     char * tp;
9665     int attrs;
9666     int rename_type;
9667
9668     attrs = smb_GetSMBParm(inp, 0);
9669     rename_type = smb_GetSMBParm(inp, 1);
9670
9671     if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
9672         osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
9673         return CM_ERROR_NOACCESS;
9674     }
9675
9676     tp = smb_GetSMBData(inp, NULL);
9677     oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9678     if (!oldPathp)
9679         return CM_ERROR_BADSMB;
9680     newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
9681     if (!newPathp)
9682         return CM_ERROR_BADSMB;
9683
9684     osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
9685              osi_LogSaveClientString(smb_logp, oldPathp),
9686              osi_LogSaveClientString(smb_logp, newPathp),
9687              ((rename_type==RENAME_FLAG_RENAME)?"rename":(rename_type==RENAME_FLAG_HARD_LINK)?"hardlink":"other"));
9688
9689     if (rename_type == RENAME_FLAG_RENAME) {
9690         code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
9691     } else if (rename_type == RENAME_FLAG_HARD_LINK) { /* RENAME_FLAG_HARD_LINK */
9692         code = smb_Link(vcp,inp,oldPathp,newPathp);
9693     } else
9694         code = CM_ERROR_BADOP;
9695     return code;
9696 }
9697
9698 void smb3_Init()
9699 {
9700     lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock", LOCK_HIERARCHY_SMB_DIRWATCH);
9701 }
9702
9703 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9704 {
9705     smb_username_t *unp;
9706     cm_user_t *     userp;
9707
9708     unp = smb_FindUserByName(usern, machine, flags);
9709     if (!unp->userp) {
9710         lock_ObtainMutex(&unp->mx);
9711         unp->userp = cm_NewUser();
9712         lock_ReleaseMutex(&unp->mx);
9713         osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9714     }  else     {
9715         osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9716     }
9717     userp = unp->userp;
9718     cm_HoldUser(userp);
9719     smb_ReleaseUsername(unp);
9720     return userp;
9721 }
9722
9723 cm_user_t *smb_FindCMUserBySID(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
9724 {
9725     smb_username_t *unp;
9726     cm_user_t *     userp;
9727
9728     unp = smb_FindUserByName(usern, machine, flags);
9729     if (!unp->userp) {
9730         lock_ObtainMutex(&unp->mx);
9731         unp->flags |= SMB_USERNAMEFLAG_SID;
9732         unp->userp = cm_NewUser();
9733         lock_ReleaseMutex(&unp->mx);
9734         osi_Log2(smb_logp,"smb_FindCMUserBySID New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9735     }  else     {
9736         osi_Log2(smb_logp,"smb_FindCMUserBySID Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
9737     }
9738     userp = unp->userp;
9739     cm_HoldUser(userp);
9740     smb_ReleaseUsername(unp);
9741     return userp;
9742 }