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