dc1f940d5010b23bdca06697e1eae7d23a283c4d
[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
2120     /* We sometimes see 0 word count.  What to do? */
2121     if (*inp->wctp == 0) {
2122         osi_Log0(smb_logp, "Transaction2 word count = 0"); 
2123         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2124
2125         smb_SetSMBDataLength(outp, 0);
2126         smb_SendPacket(vcp, outp);
2127         return 0;
2128     }
2129
2130     totalParms = smb_GetSMBParm(inp, 0);
2131     totalData = smb_GetSMBParm(inp, 1);
2132         
2133     firstPacket = (inp->inCom == 0x32);
2134         
2135     /* find the packet we're reassembling */
2136     lock_ObtainWrite(&smb_globalLock);
2137     asp = smb_FindTran2Packet(vcp, inp);
2138     if (!asp) {
2139         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2140     }
2141     lock_ReleaseWrite(&smb_globalLock);
2142         
2143     /* now merge in this latest packet; start by looking up offsets */
2144     if (firstPacket) {
2145         parmDisp = dataDisp = 0;
2146         parmOffset = smb_GetSMBParm(inp, 10);
2147         dataOffset = smb_GetSMBParm(inp, 12);
2148         parmCount = smb_GetSMBParm(inp, 9);
2149         dataCount = smb_GetSMBParm(inp, 11);
2150         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2151         asp->maxReturnData = smb_GetSMBParm(inp, 3);
2152
2153         osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2154                  totalData, dataCount, asp->maxReturnData);
2155     }
2156     else {
2157         parmDisp = smb_GetSMBParm(inp, 4);
2158         parmOffset = smb_GetSMBParm(inp, 3);
2159         dataDisp = smb_GetSMBParm(inp, 7);
2160         dataOffset = smb_GetSMBParm(inp, 6);
2161         parmCount = smb_GetSMBParm(inp, 2);
2162         dataCount = smb_GetSMBParm(inp, 5);
2163
2164         osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2165                  parmCount, dataCount);
2166     }   
2167
2168     /* now copy the parms and data */
2169     if ( asp->totalParms > 0 && parmCount != 0 )
2170     {
2171         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2172     }
2173     if ( asp->totalData > 0 && dataCount != 0 ) {
2174         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2175     }
2176
2177     /* account for new bytes */
2178     asp->curData += dataCount;
2179     asp->curParms += parmCount;
2180
2181     /* finally, if we're done, remove the packet from the queue and dispatch it */
2182     if (asp->totalParms > 0 &&
2183         asp->curParms > 0 &&
2184         asp->totalData <= asp->curData &&
2185         asp->totalParms <= asp->curParms) {
2186         /* we've received it all */
2187         lock_ObtainWrite(&smb_globalLock);
2188         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2189         lock_ReleaseWrite(&smb_globalLock);
2190
2191         /* now dispatch it */
2192         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2193             osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2194             code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2195         }
2196         else {
2197             osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2198             code = CM_ERROR_BADOP;
2199         }
2200
2201         /* if an error is returned, we're supposed to send an error packet,
2202          * otherwise the dispatched function already did the data sending.
2203          * We give dispatched proc the responsibility since it knows how much
2204          * space to allocate.
2205          */
2206         if (code != 0) {
2207             smb_SendTran2Error(vcp, asp, outp, code);
2208         }
2209
2210         /* free the input tran 2 packet */
2211         smb_FreeTran2Packet(asp);
2212     }
2213     else if (firstPacket) {
2214         /* the first packet in a multi-packet request, we need to send an
2215          * ack to get more data.
2216          */
2217         smb_SetSMBDataLength(outp, 0);
2218         smb_SendPacket(vcp, outp);
2219     }
2220
2221     return 0;
2222 }
2223
2224 /* TRANS2_OPEN2 */
2225 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2226 {
2227     clientchar_t *pathp;
2228     smb_tran2Packet_t *outp;
2229     long code = 0;
2230     cm_space_t *spacep;
2231     int excl;
2232     cm_user_t *userp;
2233     cm_scache_t *dscp;          /* dir we're dealing with */
2234     cm_scache_t *scp;           /* file we're creating */
2235     cm_attr_t setAttr;
2236     int initialModeBits;
2237     smb_fid_t *fidp;
2238     int attributes;
2239     clientchar_t *lastNamep;
2240     afs_uint32 dosTime;
2241     int openFun;
2242     int trunc;
2243     int openMode;
2244     int extraInfo;
2245     int openAction;
2246     int parmSlot;                       /* which parm we're dealing with */
2247     long returnEALength;
2248     clientchar_t *tidPathp;
2249     cm_req_t req;
2250     int created = 0;
2251
2252     smb_InitReq(&req);
2253
2254     scp = NULL;
2255         
2256     extraInfo = (p->parmsp[0] & 1);     /* return extra info */
2257     returnEALength = (p->parmsp[0] & 8);        /* return extended attr length */
2258
2259     openFun = p->parmsp[6];             /* open function */
2260     excl = ((openFun & 3) == 0);
2261     trunc = ((openFun & 3) == 2);       /* truncate it */
2262     openMode = (p->parmsp[1] & 0x7);
2263     openAction = 0;                     /* tracks what we did */
2264
2265     attributes = p->parmsp[3];
2266     dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2267         
2268     /* compute initial mode bits based on read-only flag in attributes */
2269     initialModeBits = 0666;
2270     if (attributes & SMB_ATTR_READONLY) 
2271         initialModeBits &= ~0222;
2272         
2273     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2274                                   SMB_STRF_ANSIPATH);
2275     
2276     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2277
2278     spacep = cm_GetSpace();
2279     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2280
2281     if (lastNamep && 
2282         (cm_ClientStrCmpI(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
2283          cm_ClientStrCmpI(lastNamep,  _C("\\srvsvc")) == 0 ||
2284          cm_ClientStrCmpI(lastNamep,  _C("\\wkssvc")) == 0 ||
2285          cm_ClientStrCmpI(lastNamep,  _C("\\ipc$")) == 0)) {
2286         /* special case magic file name for receiving IOCTL requests
2287          * (since IOCTL calls themselves aren't getting through).
2288          */
2289         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2290         smb_SetupIoctlFid(fidp, spacep);
2291
2292         /* copy out remainder of the parms */
2293         parmSlot = 0;
2294         outp->parmsp[parmSlot++] = fidp->fid;
2295         if (extraInfo) {
2296             outp->parmsp[parmSlot++] = 0;       /* attrs */
2297             outp->parmsp[parmSlot++] = 0;       /* mod time */
2298             outp->parmsp[parmSlot++] = 0; 
2299             outp->parmsp[parmSlot++] = 0;       /* len */
2300             outp->parmsp[parmSlot++] = 0x7fff;
2301             outp->parmsp[parmSlot++] = openMode;
2302             outp->parmsp[parmSlot++] = 0;       /* file type 0 ==> normal file or dir */
2303             outp->parmsp[parmSlot++] = 0;       /* IPC junk */
2304         }   
2305         /* and the final "always present" stuff */
2306         outp->parmsp[parmSlot++] = 1;           /* openAction found existing file */
2307         /* next write out the "unique" ID */
2308         outp->parmsp[parmSlot++] = 0x1234;
2309         outp->parmsp[parmSlot++] = 0x5678;
2310         outp->parmsp[parmSlot++] = 0;
2311         if (returnEALength) {
2312             outp->parmsp[parmSlot++] = 0;
2313             outp->parmsp[parmSlot++] = 0;
2314         }       
2315                 
2316         outp->totalData = 0;
2317         outp->totalParms = parmSlot * 2;
2318                 
2319         smb_SendTran2Packet(vcp, outp, op);
2320                 
2321         smb_FreeTran2Packet(outp);
2322
2323         /* and clean up fid reference */
2324         smb_ReleaseFID(fidp);
2325         return 0;
2326     }
2327
2328 #ifdef DEBUG_VERBOSE
2329     {
2330         char *hexp, *asciip;
2331         asciip = (lastNamep ? lastNamep : pathp);
2332         hexp = osi_HexifyString( asciip );
2333         DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2334         free(hexp);
2335     }       
2336 #endif
2337
2338     userp = smb_GetTran2User(vcp, p);
2339     /* In the off chance that userp is NULL, we log and abandon */
2340     if (!userp) {
2341         osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2342         smb_FreeTran2Packet(outp);
2343         return CM_ERROR_BADSMB;
2344     }
2345
2346     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2347     if (code == CM_ERROR_TIDIPC) {
2348         /* Attempt to use a TID allocated for IPC.  The client
2349          * is probably looking for DCE RPC end points which we
2350          * don't support OR it could be looking to make a DFS
2351          * referral request. 
2352          */
2353         osi_Log0(smb_logp, "Tran2Open received IPC TID");
2354 #ifndef DFS_SUPPORT
2355         cm_ReleaseUser(userp);
2356         smb_FreeTran2Packet(outp);
2357         return CM_ERROR_NOSUCHPATH;
2358 #endif
2359     }
2360
2361     dscp = NULL;
2362     code = cm_NameI(cm_data.rootSCachep, pathp,
2363                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2364                      userp, tidPathp, &req, &scp);
2365     if (code != 0) {
2366         code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2367                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2368                          userp, tidPathp, &req, &dscp);
2369         cm_FreeSpace(spacep);
2370
2371         if (code) {
2372             cm_ReleaseUser(userp);
2373             smb_FreeTran2Packet(outp);
2374             return code;
2375         }
2376         
2377 #ifdef DFS_SUPPORT
2378         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2379             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2380                                                       (clientchar_t*) spacep->data);
2381             cm_ReleaseSCache(dscp);
2382             cm_ReleaseUser(userp);
2383             smb_FreeTran2Packet(outp);
2384             if ( WANTS_DFS_PATHNAMES(p) || pnc )
2385                 return CM_ERROR_PATH_NOT_COVERED;
2386             else
2387                 return CM_ERROR_BADSHARENAME;
2388         }
2389 #endif /* DFS_SUPPORT */
2390
2391         /* otherwise, scp points to the parent directory.  Do a lookup,
2392          * and truncate the file if we find it, otherwise we create the
2393          * file.
2394          */
2395         if (!lastNamep) 
2396             lastNamep = pathp;
2397         else 
2398             lastNamep++;
2399         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2400                          &req, &scp);
2401         if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2402             cm_ReleaseSCache(dscp);
2403             cm_ReleaseUser(userp);
2404             smb_FreeTran2Packet(outp);
2405             return code;
2406         }
2407     } else {
2408 #ifdef DFS_SUPPORT
2409         if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2410             int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2411             cm_ReleaseSCache(scp);
2412             cm_ReleaseUser(userp);
2413             smb_FreeTran2Packet(outp);
2414             if ( WANTS_DFS_PATHNAMES(p) || pnc )
2415                 return CM_ERROR_PATH_NOT_COVERED;
2416             else
2417                 return CM_ERROR_BADSHARENAME;
2418         }
2419 #endif /* DFS_SUPPORT */
2420
2421         /* macintosh is expensive to program for it */
2422         cm_FreeSpace(spacep);
2423     }
2424         
2425     /* if we get here, if code is 0, the file exists and is represented by
2426      * scp.  Otherwise, we have to create it.
2427      */
2428     if (code == 0) {
2429         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2430         if (code) {
2431             if (dscp) 
2432                 cm_ReleaseSCache(dscp);
2433             cm_ReleaseSCache(scp);
2434             cm_ReleaseUser(userp);
2435             smb_FreeTran2Packet(outp);
2436             return code;
2437         }
2438
2439         if (excl) {
2440             /* oops, file shouldn't be there */
2441             if (dscp) 
2442                 cm_ReleaseSCache(dscp);
2443             cm_ReleaseSCache(scp);
2444             cm_ReleaseUser(userp);
2445             smb_FreeTran2Packet(outp);
2446             return CM_ERROR_EXISTS;
2447         }
2448
2449         if (trunc) {
2450             setAttr.mask = CM_ATTRMASK_LENGTH;
2451             setAttr.length.LowPart = 0;
2452             setAttr.length.HighPart = 0;
2453             code = cm_SetAttr(scp, &setAttr, userp, &req);
2454             openAction = 3;     /* truncated existing file */
2455         }   
2456         else 
2457             openAction = 1;     /* found existing file */
2458     }
2459     else if (!(openFun & 0x10)) {
2460         /* don't create if not found */
2461         if (dscp) 
2462             cm_ReleaseSCache(dscp);
2463         osi_assertx(scp == NULL, "null cm_scache_t");
2464         cm_ReleaseUser(userp);
2465         smb_FreeTran2Packet(outp);
2466         return CM_ERROR_NOSUCHFILE;
2467     }
2468     else {
2469         osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2470         openAction = 2; /* created file */
2471         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2472         smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2473         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2474                           &req);
2475         if (code == 0) {
2476             created = 1;
2477             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2478                 smb_NotifyChange(FILE_ACTION_ADDED,
2479                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,  
2480                                   dscp, lastNamep, NULL, TRUE);
2481         } else if (!excl && code == CM_ERROR_EXISTS) {
2482             /* not an exclusive create, and someone else tried
2483              * creating it already, then we open it anyway.  We
2484              * don't bother retrying after this, since if this next
2485              * fails, that means that the file was deleted after we
2486              * started this call.
2487              */
2488             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2489                               userp, &req, &scp);
2490             if (code == 0) {
2491                 if (trunc) {
2492                     setAttr.mask = CM_ATTRMASK_LENGTH;
2493                     setAttr.length.LowPart = 0;
2494                     setAttr.length.HighPart = 0;
2495                     code = cm_SetAttr(scp, &setAttr, userp,
2496                                        &req);
2497                 }   
2498             }   /* lookup succeeded */
2499         }
2500     }
2501         
2502     /* we don't need this any longer */
2503     if (dscp) 
2504         cm_ReleaseSCache(dscp);
2505
2506     if (code) {
2507         /* something went wrong creating or truncating the file */
2508         if (scp) 
2509             cm_ReleaseSCache(scp);
2510         cm_ReleaseUser(userp);
2511         smb_FreeTran2Packet(outp);
2512         return code;
2513     }
2514         
2515     /* make sure we're about to open a file */
2516     if (scp->fileType != CM_SCACHETYPE_FILE) {
2517         code = 0;
2518         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2519             cm_scache_t * targetScp = 0;
2520             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2521             if (code == 0) {
2522                 /* we have a more accurate file to use (the
2523                  * target of the symbolic link).  Otherwise,
2524                  * we'll just use the symlink anyway.
2525                  */
2526                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2527                           scp, targetScp);
2528                 cm_ReleaseSCache(scp);
2529                 scp = targetScp;
2530             }
2531         }
2532         if (scp->fileType != CM_SCACHETYPE_FILE) {
2533             cm_ReleaseSCache(scp);
2534             cm_ReleaseUser(userp);
2535             smb_FreeTran2Packet(outp);
2536             return CM_ERROR_ISDIR;
2537         }
2538     }
2539
2540     /* now all we have to do is open the file itself */
2541     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2542     osi_assertx(fidp, "null smb_fid_t");
2543         
2544     cm_HoldUser(userp);
2545     lock_ObtainMutex(&fidp->mx);
2546     /* save a pointer to the vnode */
2547     osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2548     fidp->scp = scp;
2549     lock_ObtainWrite(&scp->rw);
2550     scp->flags |= CM_SCACHEFLAG_SMB_FID;
2551     lock_ReleaseWrite(&scp->rw);
2552     
2553     /* and the user */
2554     fidp->userp = userp;
2555         
2556     /* compute open mode */
2557     if (openMode != 1) 
2558         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2559     if (openMode == 1 || openMode == 2)
2560         fidp->flags |= SMB_FID_OPENWRITE;
2561
2562     /* remember that the file was newly created */
2563     if (created)
2564         fidp->flags |= SMB_FID_CREATED;
2565
2566     lock_ReleaseMutex(&fidp->mx);
2567
2568     smb_ReleaseFID(fidp);
2569         
2570     cm_Open(scp, 0, userp);
2571
2572     /* copy out remainder of the parms */
2573     parmSlot = 0;
2574     outp->parmsp[parmSlot++] = fidp->fid;
2575     lock_ObtainRead(&scp->rw);
2576     if (extraInfo) {
2577         outp->parmsp[parmSlot++] = smb_Attributes(scp);
2578         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2579         outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2580         outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2581         outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2582         outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2583         outp->parmsp[parmSlot++] = openMode;
2584         outp->parmsp[parmSlot++] = 0;   /* file type 0 ==> normal file or dir */
2585         outp->parmsp[parmSlot++] = 0;   /* IPC junk */
2586     }   
2587     /* and the final "always present" stuff */
2588     outp->parmsp[parmSlot++] = openAction;
2589     /* next write out the "unique" ID */
2590     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff); 
2591     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff); 
2592     outp->parmsp[parmSlot++] = 0; 
2593     if (returnEALength) {
2594         outp->parmsp[parmSlot++] = 0; 
2595         outp->parmsp[parmSlot++] = 0; 
2596     }   
2597     lock_ReleaseRead(&scp->rw);
2598     outp->totalData = 0;                /* total # of data bytes */
2599     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
2600
2601     smb_SendTran2Packet(vcp, outp, op);
2602
2603     smb_FreeTran2Packet(outp);
2604
2605     cm_ReleaseUser(userp);
2606     /* leave scp held since we put it in fidp->scp */
2607     return 0;
2608 }   
2609
2610 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2611 {
2612     unsigned short fid;
2613     unsigned short infolevel;
2614
2615     infolevel = p->parmsp[0];
2616     fid = p->parmsp[1];
2617     osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2618     
2619     return CM_ERROR_BAD_LEVEL;
2620 }
2621
2622 /* TRANS2_QUERY_FS_INFORMATION */
2623 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2624 {
2625     smb_tran2Packet_t *outp;
2626     smb_tran2QFSInfo_t qi;
2627     int responseSize;
2628     size_t sz = 0;
2629         
2630     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2631
2632     switch (p->parmsp[0]) {
2633     case SMB_INFO_ALLOCATION: 
2634         /* alloc info */
2635         responseSize = sizeof(qi.u.allocInfo); 
2636
2637         qi.u.allocInfo.FSID = 0;
2638         qi.u.allocInfo.sectorsPerAllocUnit = 1;
2639         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2640         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2641         qi.u.allocInfo.bytesPerSector = 1024;
2642         break;
2643
2644     case SMB_INFO_VOLUME: 
2645         /* volume info */
2646         qi.u.volumeInfo.vsn = 1234;  /* Volume serial number */
2647         qi.u.volumeInfo.vnCount = 4; /* Number of characters in label (AFS\0)*/
2648
2649         /* we're supposed to pad it out with zeroes to the end */
2650         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2651         smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2652
2653         responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2654         break;
2655
2656     case SMB_QUERY_FS_VOLUME_INFO: 
2657         /* FS volume info */
2658         responseSize = sizeof(qi.u.FSvolumeInfo);
2659
2660         {
2661             FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2662             memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2663         }
2664
2665         qi.u.FSvolumeInfo.vsn = 1234;
2666         qi.u.FSvolumeInfo.vnCount = 8; /* This is always in Unicode */
2667         memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2668         break;
2669
2670     case SMB_QUERY_FS_SIZE_INFO: 
2671         /* FS size info */
2672         responseSize = sizeof(qi.u.FSsizeInfo); 
2673
2674         qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2675         qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2676         qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2677         qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2678         qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2679         qi.u.FSsizeInfo.bytesPerSector = 1024;
2680         break;
2681
2682     case SMB_QUERY_FS_DEVICE_INFO: 
2683         /* FS device info */
2684         responseSize = sizeof(qi.u.FSdeviceInfo); 
2685
2686         qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2687         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2688         break;
2689
2690     case SMB_QUERY_FS_ATTRIBUTE_INFO: 
2691         /* FS attribute info */
2692
2693         /* attributes, defined in WINNT.H:
2694          *      FILE_CASE_SENSITIVE_SEARCH      0x1
2695          *      FILE_CASE_PRESERVED_NAMES       0x2
2696          *      FILE_VOLUME_QUOTAS              0x10
2697          *      <no name defined>               0x4000
2698          *         If bit 0x4000 is not set, Windows 95 thinks
2699          *         we can't handle long (non-8.3) names,
2700          *         despite our protestations to the contrary.
2701          */
2702         qi.u.FSattributeInfo.attributes = 0x4003;
2703         /* The maxCompLength is supposed to be in bytes */
2704 #ifdef SMB_UNICODE
2705         if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2706             qi.u.FSattributeInfo.maxCompLength = MAX_PATH * sizeof(wchar_t);
2707         else {
2708 #endif
2709         qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2710 #ifdef SMB_UNICODE
2711         }
2712 #endif
2713         smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2714         qi.u.FSattributeInfo.FSnameLength = sz;
2715
2716         responseSize =
2717             sizeof(qi.u.FSattributeInfo.attributes) +
2718             sizeof(qi.u.FSattributeInfo.maxCompLength) +
2719             sizeof(qi.u.FSattributeInfo.FSnameLength) +
2720             sz;
2721
2722         break;
2723
2724     case SMB_INFO_UNIX:         /* CIFS Unix Info */
2725     case SMB_INFO_MACOS:        /* Mac FS Info */
2726     default: 
2727         return CM_ERROR_BADOP;
2728     }   
2729         
2730     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2731         
2732     /* copy out return data, and set corresponding sizes */
2733     outp->totalParms = 0;
2734     outp->totalData = responseSize;
2735     memcpy(outp->datap, &qi, responseSize);
2736
2737     /* send and free the packets */
2738     smb_SendTran2Packet(vcp, outp, op);
2739     smb_FreeTran2Packet(outp);
2740
2741     return 0;
2742 }
2743
2744 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2745 {
2746     osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2747     return CM_ERROR_BADOP;
2748 }
2749
2750 struct smb_ShortNameRock {
2751     clientchar_t *maskp;
2752     unsigned int vnode;
2753     clientchar_t *shortName;
2754     size_t shortNameLen;
2755 };      
2756
2757 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2758                          osi_hyper_t *offp)
2759 {       
2760     struct smb_ShortNameRock *rockp;
2761     normchar_t normName[MAX_PATH];
2762     clientchar_t *shortNameEnd;
2763
2764     rockp = vrockp;
2765
2766     cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t));
2767
2768     /* compare both names and vnodes, though probably just comparing vnodes
2769      * would be safe enough.
2770      */
2771     if (cm_NormStrCmpI(normName,  rockp->maskp) != 0)
2772         return 0;
2773     if (ntohl(dep->fid.vnode) != rockp->vnode)
2774         return 0;
2775
2776     /* This is the entry */
2777     cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2778     rockp->shortNameLen = shortNameEnd - rockp->shortName;
2779
2780     return CM_ERROR_STOPNOW;
2781 }
2782
2783 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
2784         clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
2785 {
2786     struct smb_ShortNameRock rock;
2787     clientchar_t *lastNamep;
2788     cm_space_t *spacep;
2789     cm_scache_t *dscp;
2790     int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2791     long code = 0;
2792     osi_hyper_t thyper;
2793
2794     spacep = cm_GetSpace();
2795     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2796
2797     code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2798                     caseFold, userp, tidPathp,
2799                     reqp, &dscp);
2800     cm_FreeSpace(spacep);
2801     if (code) 
2802         return code;
2803
2804 #ifdef DFS_SUPPORT
2805     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2806         cm_ReleaseSCache(dscp);
2807         cm_ReleaseUser(userp);
2808 #ifdef DEBUG
2809         DebugBreak();
2810 #endif
2811         return CM_ERROR_PATH_NOT_COVERED;
2812     }
2813 #endif /* DFS_SUPPORT */
2814
2815     if (!lastNamep) lastNamep = pathp;
2816     else lastNamep++;
2817     thyper.LowPart = 0;
2818     thyper.HighPart = 0;
2819     rock.shortName = shortName;
2820     rock.vnode = vnode;
2821     rock.maskp = lastNamep;
2822     code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2823
2824     cm_ReleaseSCache(dscp);
2825
2826     if (code == 0)
2827         return CM_ERROR_NOSUCHFILE;
2828     if (code == CM_ERROR_STOPNOW) {
2829         *shortNameLenp = rock.shortNameLen;
2830         return 0;
2831     }
2832     return code;
2833 }
2834
2835 /* TRANS2_QUERY_PATH_INFORMATION */
2836 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2837 {
2838     smb_tran2Packet_t *outp;
2839     afs_uint32 dosTime;
2840     FILETIME ft;
2841     unsigned short infoLevel;
2842     smb_tran2QPathInfo_t qpi;
2843     int responseSize;
2844     unsigned short attributes;
2845     unsigned long extAttributes;
2846     clientchar_t shortName[13];
2847     size_t len;
2848     cm_user_t *userp;
2849     cm_space_t *spacep;
2850     cm_scache_t *scp, *dscp;
2851     int scp_rw_held = 0;
2852     int delonclose = 0;
2853     long code = 0;
2854     clientchar_t *pathp;
2855     clientchar_t *tidPathp;
2856     clientchar_t *lastComp;
2857     cm_req_t req;
2858
2859     smb_InitReq(&req);
2860
2861     infoLevel = p->parmsp[0];
2862     if (infoLevel == SMB_INFO_IS_NAME_VALID) 
2863         responseSize = 0;
2864     else if (infoLevel == SMB_INFO_STANDARD) 
2865         responseSize = sizeof(qpi.u.QPstandardInfo);
2866     else if (infoLevel == SMB_INFO_QUERY_EA_SIZE) 
2867         responseSize = sizeof(qpi.u.QPeaSizeInfo);
2868     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2869         responseSize = sizeof(qpi.u.QPfileBasicInfo);
2870     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2871         responseSize = sizeof(qpi.u.QPfileStandardInfo);
2872     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2873         responseSize = sizeof(qpi.u.QPfileEaInfo);
2874     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
2875         responseSize = sizeof(qpi.u.QPfileNameInfo);
2876     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) 
2877         responseSize = sizeof(qpi.u.QPfileAllInfo);
2878     else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) 
2879         responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2880     else {
2881         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2882                   p->opcode, infoLevel);
2883         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2884         return 0;
2885     }
2886
2887     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
2888     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
2889               osi_LogSaveClientString(smb_logp, pathp));
2890
2891     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2892
2893     if (infoLevel > 0x100)
2894         outp->totalParms = 2;
2895     else
2896         outp->totalParms = 0;
2897     outp->totalData = responseSize;
2898         
2899     /* now, if we're at infoLevel 6, we're only being asked to check
2900      * the syntax, so we just OK things now.  In particular, we're *not*
2901      * being asked to verify anything about the state of any parent dirs.
2902      */
2903     if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2904         smb_SendTran2Packet(vcp, outp, opx);
2905         smb_FreeTran2Packet(outp);
2906         return 0;
2907     }   
2908         
2909     userp = smb_GetTran2User(vcp, p);
2910     if (!userp) {
2911         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2912         smb_FreeTran2Packet(outp);
2913         return CM_ERROR_BADSMB;
2914     }
2915
2916     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2917     if(code) {
2918         cm_ReleaseUser(userp);
2919         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2920         smb_FreeTran2Packet(outp);
2921         return 0;
2922     }
2923
2924     /*
2925      * XXX Strange hack XXX
2926      *
2927      * As of Patch 7 (13 January 98), we are having the following problem:
2928      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2929      * requests to look up "desktop.ini" in all the subdirectories.
2930      * This can cause zillions of timeouts looking up non-existent cells
2931      * and volumes, especially in the top-level directory.
2932      *
2933      * We have not found any way to avoid this or work around it except
2934      * to explicitly ignore the requests for mount points that haven't
2935      * yet been evaluated and for directories that haven't yet been
2936      * fetched.
2937      */
2938     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2939         spacep = cm_GetSpace();
2940         smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
2941 #ifndef SPECIAL_FOLDERS
2942         /* Make sure that lastComp is not NULL */
2943         if (lastComp) {
2944             if (cm_ClientStrCmpIA(lastComp,  _C("\\desktop.ini")) == 0) {
2945                 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2946                                  CM_FLAG_CASEFOLD
2947                                  | CM_FLAG_DIRSEARCH
2948                                  | CM_FLAG_FOLLOW,
2949                                  userp, tidPathp, &req, &dscp);
2950                 if (code == 0) {
2951 #ifdef DFS_SUPPORT
2952                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2953                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2954                                                                   spacep->wdata);
2955                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
2956                             code = CM_ERROR_PATH_NOT_COVERED;
2957                         else
2958                             code = CM_ERROR_BADSHARENAME;
2959                     } else
2960 #endif /* DFS_SUPPORT */
2961                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2962                         code = CM_ERROR_NOSUCHFILE;
2963                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2964                         cm_buf_t *bp = buf_Find(dscp, &hzero);
2965                         if (bp) {
2966                             buf_Release(bp);
2967                             bp = NULL;
2968                         }
2969                         else
2970                             code = CM_ERROR_NOSUCHFILE;
2971                     }
2972                     cm_ReleaseSCache(dscp);
2973                     if (code) {
2974                         cm_FreeSpace(spacep);
2975                         cm_ReleaseUser(userp);
2976                         smb_SendTran2Error(vcp, p, opx, code);
2977                         smb_FreeTran2Packet(outp);
2978                         return 0;
2979                     }
2980                 }
2981             }
2982         }
2983 #endif /* SPECIAL_FOLDERS */
2984
2985         cm_FreeSpace(spacep);
2986     }
2987
2988     /* now do namei and stat, and copy out the info */
2989     code = cm_NameI(cm_data.rootSCachep, pathp,
2990                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2991
2992     if (code) {
2993         cm_ReleaseUser(userp);
2994         smb_SendTran2Error(vcp, p, opx, code);
2995         smb_FreeTran2Packet(outp);
2996         return 0;
2997     }
2998
2999 #ifdef DFS_SUPPORT
3000     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3001         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3002         cm_ReleaseSCache(scp);
3003         cm_ReleaseUser(userp);
3004         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3005             code = CM_ERROR_PATH_NOT_COVERED;
3006         else
3007             code = CM_ERROR_BADSHARENAME;
3008         smb_SendTran2Error(vcp, p, opx, code);
3009         smb_FreeTran2Packet(outp);
3010         return 0;
3011     }
3012 #endif /* DFS_SUPPORT */
3013
3014     lock_ObtainWrite(&scp->rw);
3015     scp_rw_held = 2;
3016     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3017                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3018     if (code)
3019         goto done;
3020
3021     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3022         
3023     lock_ConvertWToR(&scp->rw);
3024     scp_rw_held = 1;
3025
3026     len = 0;
3027
3028     /* now we have the status in the cache entry, and everything is locked.
3029      * Marshall the output data.
3030      */
3031     /* for info level 108, figure out short name */
3032     if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3033         code = cm_GetShortName(pathp, userp, &req,
3034                                 tidPathp, scp->fid.vnode, shortName,
3035                                &len);
3036         if (code) {
3037             goto done;
3038         }
3039
3040         smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3041         qpi.u.QPfileAltNameInfo.fileNameLength = len;
3042
3043         goto done;
3044     }
3045     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3046         smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3047         qpi.u.QPfileNameInfo.fileNameLength = len;
3048
3049         goto done;
3050     }
3051     else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3052         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3053         qpi.u.QPstandardInfo.creationDateTime = dosTime;
3054         qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3055         qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3056         qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3057         qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3058         attributes = smb_Attributes(scp);
3059         qpi.u.QPstandardInfo.attributes = attributes;
3060         qpi.u.QPstandardInfo.eaSize = 0;
3061     }
3062     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3063         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3064         qpi.u.QPfileBasicInfo.creationTime = ft;
3065         qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3066         qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3067         qpi.u.QPfileBasicInfo.changeTime = ft;
3068         extAttributes = smb_ExtAttributes(scp);
3069         qpi.u.QPfileBasicInfo.attributes = extAttributes;
3070         qpi.u.QPfileBasicInfo.reserved = 0;
3071     }
3072     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3073         smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
3074
3075         qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3076         qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3077         qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3078         qpi.u.QPfileStandardInfo.directory = 
3079             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3080               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3081               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3082         qpi.u.QPfileStandardInfo.reserved = 0;
3083
3084         if (fidp) {
3085             lock_ReleaseRead(&scp->rw);
3086             scp_rw_held = 0;
3087             lock_ObtainMutex(&fidp->mx);
3088             delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3089             lock_ReleaseMutex(&fidp->mx);
3090             smb_ReleaseFID(fidp);
3091         }
3092         qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3093     }
3094     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3095         qpi.u.QPfileEaInfo.eaSize = 0;
3096     }
3097     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3098         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3099         qpi.u.QPfileAllInfo.creationTime = ft;
3100         qpi.u.QPfileAllInfo.lastAccessTime = ft;
3101         qpi.u.QPfileAllInfo.lastWriteTime = ft;
3102         qpi.u.QPfileAllInfo.changeTime = ft;
3103         extAttributes = smb_ExtAttributes(scp);
3104         qpi.u.QPfileAllInfo.attributes = extAttributes;
3105         qpi.u.QPfileAllInfo.allocationSize = scp->length;
3106         qpi.u.QPfileAllInfo.endOfFile = scp->length;
3107         qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3108         qpi.u.QPfileAllInfo.deletePending = 0;
3109         qpi.u.QPfileAllInfo.directory = 
3110             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3111               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3112               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3113         qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3114         qpi.u.QPfileAllInfo.indexNumber.LowPart  = scp->fid.volume;
3115         qpi.u.QPfileAllInfo.eaSize = 0;
3116         qpi.u.QPfileAllInfo.accessFlags = 0;
3117         qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3118         qpi.u.QPfileAllInfo.indexNumber2.LowPart  = scp->fid.unique;
3119         qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3120         qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3121         qpi.u.QPfileAllInfo.mode = 0;
3122         qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3123
3124         smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3125         qpi.u.QPfileAllInfo.fileNameLength = len;
3126     }
3127
3128     /* send and free the packets */
3129   done:
3130     switch (scp_rw_held) {
3131     case 1:
3132         lock_ReleaseRead(&scp->rw);
3133         break;
3134     case 2:
3135         lock_ReleaseWrite(&scp->rw);
3136         break;
3137     }
3138     scp_rw_held = 0;
3139     cm_ReleaseSCache(scp);
3140     cm_ReleaseUser(userp);
3141     if (code == 0) {
3142         memcpy(outp->datap, &qpi, responseSize);
3143         smb_SendTran2Packet(vcp, outp, opx);
3144     } else {
3145         smb_SendTran2Error(vcp, p, opx, code);
3146     }
3147     smb_FreeTran2Packet(outp);
3148
3149     return 0;
3150 }
3151
3152 /* TRANS2_SET_PATH_INFORMATION */
3153 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3154 {
3155 #if 0
3156     osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3157     return CM_ERROR_BADOP;
3158 #else
3159     long code = 0;
3160     smb_fid_t *fidp;
3161     unsigned short infoLevel;
3162     clientchar_t * pathp;
3163     smb_tran2Packet_t *outp;
3164     smb_tran2QPathInfo_t *spi;
3165     cm_user_t *userp;
3166     cm_scache_t *scp, *dscp;
3167     cm_req_t req;
3168     cm_space_t *spacep;
3169     clientchar_t *tidPathp;
3170     clientchar_t *lastComp;
3171
3172     smb_InitReq(&req);
3173
3174     infoLevel = p->parmsp[0];
3175     osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3176     if (infoLevel != SMB_INFO_STANDARD && 
3177         infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3178         infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3179         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3180                   p->opcode, infoLevel);
3181         smb_SendTran2Error(vcp, p, opx, 
3182                            infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3183         return 0;
3184     }
3185
3186     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3187
3188     osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3189               osi_LogSaveClientString(smb_logp, pathp));
3190
3191     userp = smb_GetTran2User(vcp, p);
3192     if (!userp) {
3193         osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3194         code = CM_ERROR_BADSMB;
3195         goto done;
3196     }   
3197
3198     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3199     if (code == CM_ERROR_TIDIPC) {
3200         /* Attempt to use a TID allocated for IPC.  The client
3201          * is probably looking for DCE RPC end points which we
3202          * don't support OR it could be looking to make a DFS
3203          * referral request. 
3204          */
3205         osi_Log0(smb_logp, "Tran2Open received IPC TID");
3206         cm_ReleaseUser(userp);
3207         return CM_ERROR_NOSUCHPATH;
3208     }
3209
3210     /*
3211     * XXX Strange hack XXX
3212     *
3213     * As of Patch 7 (13 January 98), we are having the following problem:
3214     * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3215     * requests to look up "desktop.ini" in all the subdirectories.
3216     * This can cause zillions of timeouts looking up non-existent cells
3217     * and volumes, especially in the top-level directory.
3218     *
3219     * We have not found any way to avoid this or work around it except
3220     * to explicitly ignore the requests for mount points that haven't
3221     * yet been evaluated and for directories that haven't yet been
3222     * fetched.
3223     */
3224     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3225         spacep = cm_GetSpace();
3226         smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3227 #ifndef SPECIAL_FOLDERS
3228         /* Make sure that lastComp is not NULL */
3229         if (lastComp) {
3230             if (cm_ClientStrCmpI(lastComp,  _C("\\desktop.ini")) == 0) {
3231                 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3232                                  CM_FLAG_CASEFOLD
3233                                  | CM_FLAG_DIRSEARCH
3234                                  | CM_FLAG_FOLLOW,
3235                                  userp, tidPathp, &req, &dscp);
3236                 if (code == 0) {
3237 #ifdef DFS_SUPPORT
3238                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3239                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3240                                                                   spacep->wdata);
3241                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3242                             code = CM_ERROR_PATH_NOT_COVERED;
3243                         else
3244                             code = CM_ERROR_BADSHARENAME;
3245                     } else
3246 #endif /* DFS_SUPPORT */
3247                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3248                         code = CM_ERROR_NOSUCHFILE;
3249                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3250                         cm_buf_t *bp = buf_Find(dscp, &hzero);
3251                         if (bp) {
3252                             buf_Release(bp);
3253                             bp = NULL;
3254                         }
3255                         else
3256                             code = CM_ERROR_NOSUCHFILE;
3257                     }
3258                     cm_ReleaseSCache(dscp);
3259                     if (code) {
3260                         cm_FreeSpace(spacep);
3261                         cm_ReleaseUser(userp);
3262                         smb_SendTran2Error(vcp, p, opx, code);
3263                         return 0;
3264                     }
3265                 }
3266             }
3267         }
3268 #endif /* SPECIAL_FOLDERS */
3269
3270         cm_FreeSpace(spacep);
3271     }
3272
3273     /* now do namei and stat, and copy out the info */
3274     code = cm_NameI(cm_data.rootSCachep, pathp,
3275                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3276     if (code) {
3277         cm_ReleaseUser(userp);
3278         smb_SendTran2Error(vcp, p, opx, code);
3279         return 0;
3280     }
3281
3282     fidp = smb_FindFIDByScache(vcp, scp);
3283     if (!fidp) {
3284         cm_ReleaseSCache(scp);
3285         cm_ReleaseUser(userp);
3286         smb_SendTran2Error(vcp, p, opx, code);
3287         return 0;
3288     }
3289
3290     lock_ObtainMutex(&fidp->mx);
3291     if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3292         lock_ReleaseMutex(&fidp->mx);
3293         cm_ReleaseSCache(scp);
3294         smb_ReleaseFID(fidp);
3295         cm_ReleaseUser(userp);
3296         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3297         return 0;
3298     }
3299     lock_ReleaseMutex(&fidp->mx);
3300
3301     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3302
3303     outp->totalParms = 2;
3304     outp->totalData = 0;
3305
3306     spi = (smb_tran2QPathInfo_t *)p->datap;
3307     if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3308         cm_attr_t attr;
3309
3310         /* lock the vnode with a callback; we need the current status
3311          * to determine what the new status is, in some cases.
3312          */
3313         lock_ObtainWrite(&scp->rw);
3314         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3315                           CM_SCACHESYNC_GETSTATUS
3316                          | CM_SCACHESYNC_NEEDCALLBACK);
3317         if (code) {
3318             lock_ReleaseWrite(&scp->rw);
3319             goto done;
3320         }
3321         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3322
3323         lock_ReleaseWrite(&scp->rw);
3324         lock_ObtainMutex(&fidp->mx);
3325         lock_ObtainRead(&scp->rw);
3326
3327         /* prepare for setattr call */
3328         attr.mask = CM_ATTRMASK_LENGTH;
3329         attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3330         attr.length.HighPart = 0;
3331
3332         if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3333             smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3334             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3335             fidp->flags |= SMB_FID_MTIMESETDONE;
3336         }
3337                 
3338         if (spi->u.QPstandardInfo.attributes != 0) {
3339             if ((scp->unixModeBits & 0222)
3340                  && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3341                 /* make a writable file read-only */
3342                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3343                 attr.unixModeBits = scp->unixModeBits & ~0222;
3344             }
3345             else if ((scp->unixModeBits & 0222) == 0
3346                       && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3347                 /* make a read-only file writable */
3348                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3349                 attr.unixModeBits = scp->unixModeBits | 0222;
3350             }
3351         }
3352         lock_ReleaseRead(&scp->rw);
3353         lock_ReleaseMutex(&fidp->mx);
3354
3355         /* call setattr */
3356         if (attr.mask)
3357             code = cm_SetAttr(scp, &attr, userp, &req);
3358         else
3359             code = 0;
3360     }               
3361     else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3362         /* we don't support EAs */
3363         code = CM_ERROR_EAS_NOT_SUPPORTED;
3364     }       
3365
3366   done:
3367     cm_ReleaseSCache(scp);
3368     cm_ReleaseUser(userp);
3369     smb_ReleaseFID(fidp);
3370     if (code == 0) 
3371         smb_SendTran2Packet(vcp, outp, opx);
3372     else 
3373         smb_SendTran2Error(vcp, p, opx, code);
3374     smb_FreeTran2Packet(outp);
3375
3376     return 0;
3377 #endif
3378 }
3379
3380 /* TRANS2_QUERY_FILE_INFORMATION */
3381 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3382 {
3383     smb_tran2Packet_t *outp;
3384     FILETIME ft;
3385     unsigned long attributes;
3386     unsigned short infoLevel;
3387     int responseSize;
3388     unsigned short fid;
3389     int delonclose = 0;
3390     cm_user_t *userp;
3391     smb_fid_t *fidp;
3392     cm_scache_t *scp;
3393     smb_tran2QFileInfo_t qfi;
3394     long code = 0;
3395     int  readlock = 0;
3396     cm_req_t req;
3397
3398     smb_InitReq(&req);
3399
3400     fid = p->parmsp[0];
3401     fidp = smb_FindFID(vcp, fid, 0);
3402
3403     if (fidp == NULL) {
3404         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3405         return 0;
3406     }
3407
3408     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3409         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3410         smb_CloseFID(vcp, fidp, NULL, 0);
3411         smb_ReleaseFID(fidp);
3412         return 0;
3413     }
3414
3415     infoLevel = p->parmsp[1];
3416     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) 
3417         responseSize = sizeof(qfi.u.QFbasicInfo);
3418     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) 
3419         responseSize = sizeof(qfi.u.QFstandardInfo);
3420     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3421         responseSize = sizeof(qfi.u.QFeaInfo);
3422     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
3423         responseSize = sizeof(qfi.u.QFfileNameInfo);
3424     else {
3425         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3426                   p->opcode, infoLevel);
3427         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3428         smb_ReleaseFID(fidp);
3429         return 0;
3430     }
3431     osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3432
3433     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3434
3435     if (infoLevel > 0x100)
3436         outp->totalParms = 2;
3437     else
3438         outp->totalParms = 0;
3439     outp->totalData = responseSize;
3440
3441     userp = smb_GetTran2User(vcp, p);
3442     if (!userp) {
3443         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3444         code = CM_ERROR_BADSMB;
3445         goto done;
3446     }   
3447
3448     lock_ObtainMutex(&fidp->mx);
3449     delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3450     scp = fidp->scp;
3451     osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3452     cm_HoldSCache(scp);
3453     lock_ReleaseMutex(&fidp->mx);
3454     lock_ObtainWrite(&scp->rw);
3455     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3456                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3457     if (code) 
3458         goto done;
3459
3460     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3461
3462     lock_ConvertWToR(&scp->rw);
3463     readlock = 1;
3464
3465     /* now we have the status in the cache entry, and everything is locked.
3466      * Marshall the output data.
3467      */
3468     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3469         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3470         qfi.u.QFbasicInfo.creationTime = ft;
3471         qfi.u.QFbasicInfo.lastAccessTime = ft;
3472         qfi.u.QFbasicInfo.lastWriteTime = ft;
3473         qfi.u.QFbasicInfo.lastChangeTime = ft;
3474         attributes = smb_ExtAttributes(scp);
3475         qfi.u.QFbasicInfo.attributes = attributes;
3476     }
3477     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3478         qfi.u.QFstandardInfo.allocationSize = scp->length;
3479         qfi.u.QFstandardInfo.endOfFile = scp->length;
3480         qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3481         qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3482         qfi.u.QFstandardInfo.directory = 
3483             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3484               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3485               scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3486     }
3487     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3488         qfi.u.QFeaInfo.eaSize = 0;
3489     }
3490     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3491         size_t len = 0;
3492         clientchar_t *name;
3493
3494         lock_ReleaseRead(&scp->rw);
3495         lock_ObtainMutex(&fidp->mx);
3496         lock_ObtainRead(&scp->rw);
3497         if (fidp->NTopen_wholepathp)
3498             name = fidp->NTopen_wholepathp;
3499         else
3500             name = _C("\\");    /* probably can't happen */
3501         lock_ReleaseMutex(&fidp->mx);
3502
3503         smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3504         outp->totalData = len + 4;      /* this is actually what we want to return */
3505         qfi.u.QFfileNameInfo.fileNameLength = len;
3506     }
3507
3508     /* send and free the packets */
3509   done:
3510     if (readlock)
3511         lock_ReleaseRead(&scp->rw);
3512     else
3513         lock_ReleaseWrite(&scp->rw);
3514     cm_ReleaseSCache(scp);
3515     cm_ReleaseUser(userp);
3516     smb_ReleaseFID(fidp);
3517     if (code == 0) {
3518         memcpy(outp->datap, &qfi, responseSize);
3519         smb_SendTran2Packet(vcp, outp, opx);
3520     } else {
3521         smb_SendTran2Error(vcp, p, opx, code);
3522     }
3523     smb_FreeTran2Packet(outp);
3524
3525     return 0;
3526 }       
3527
3528
3529 /* TRANS2_SET_FILE_INFORMATION */
3530 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3531 {
3532     long code = 0;
3533     unsigned short fid;
3534     smb_fid_t *fidp;
3535     unsigned short infoLevel;
3536     smb_tran2Packet_t *outp;
3537     cm_user_t *userp = NULL;
3538     cm_scache_t *scp = NULL;
3539     cm_req_t req;
3540
3541     smb_InitReq(&req);
3542
3543     fid = p->parmsp[0];
3544     fidp = smb_FindFID(vcp, fid, 0);
3545
3546     if (fidp == NULL) {
3547         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3548         return 0;
3549     }
3550
3551     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3552         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3553         smb_CloseFID(vcp, fidp, NULL, 0);
3554         smb_ReleaseFID(fidp);
3555         return 0;
3556     }
3557
3558     infoLevel = p->parmsp[1];
3559     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3560     if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3561         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3562                   p->opcode, infoLevel);
3563         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3564         smb_ReleaseFID(fidp);
3565         return 0;
3566     }
3567
3568     lock_ObtainMutex(&fidp->mx);
3569     if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && 
3570         !(fidp->flags & SMB_FID_OPENDELETE)) {
3571         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x", 
3572                   fidp, fidp->scp, fidp->flags);
3573         lock_ReleaseMutex(&fidp->mx);
3574         smb_ReleaseFID(fidp);
3575         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3576         return 0;
3577     }
3578     if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO || 
3579          infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3580          && !(fidp->flags & SMB_FID_OPENWRITE)) {
3581         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x", 
3582                   fidp, fidp->scp, fidp->flags);
3583         lock_ReleaseMutex(&fidp->mx);
3584         smb_ReleaseFID(fidp);
3585         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3586         return 0;
3587     }
3588
3589     scp = fidp->scp;
3590     osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3591     cm_HoldSCache(scp);
3592     lock_ReleaseMutex(&fidp->mx);
3593
3594     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3595
3596     outp->totalParms = 2;
3597     outp->totalData = 0;
3598
3599     userp = smb_GetTran2User(vcp, p);
3600     if (!userp) {
3601         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3602         code = CM_ERROR_BADSMB;
3603         goto done;
3604     }   
3605
3606     if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3607         FILETIME lastMod;
3608         unsigned int attribute;
3609         cm_attr_t attr;
3610         smb_tran2QFileInfo_t *sfi;
3611
3612         sfi = (smb_tran2QFileInfo_t *)p->datap;
3613
3614         /* lock the vnode with a callback; we need the current status
3615          * to determine what the new status is, in some cases.
3616          */
3617         lock_ObtainWrite(&scp->rw);
3618         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3619                           CM_SCACHESYNC_GETSTATUS
3620                          | CM_SCACHESYNC_NEEDCALLBACK);
3621         if (code) {
3622             lock_ReleaseWrite(&scp->rw);
3623             goto done;
3624         }
3625
3626         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3627
3628         lock_ReleaseWrite(&scp->rw);
3629         lock_ObtainMutex(&fidp->mx);
3630         lock_ObtainRead(&scp->rw);
3631
3632         /* prepare for setattr call */
3633         attr.mask = 0;
3634
3635         lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3636         /* when called as result of move a b, lastMod is (-1, -1). 
3637          * If the check for -1 is not present, timestamp
3638          * of the resulting file will be 1969 (-1)
3639          */
3640         if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
3641              lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3642             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3643             smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3644             fidp->flags |= SMB_FID_MTIMESETDONE;
3645         }
3646                 
3647         attribute = sfi->u.QFbasicInfo.attributes;
3648         if (attribute != 0) {
3649             if ((scp->unixModeBits & 0222)
3650                  && (attribute & SMB_ATTR_READONLY) != 0) {
3651                 /* make a writable file read-only */
3652                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3653                 attr.unixModeBits = scp->unixModeBits & ~0222;
3654             }
3655             else if ((scp->unixModeBits & 0222) == 0
3656                       && (attribute & SMB_ATTR_READONLY) == 0) {
3657                 /* make a read-only file writable */
3658                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3659                 attr.unixModeBits = scp->unixModeBits | 0222;
3660             }
3661         }
3662         lock_ReleaseRead(&scp->rw);
3663         lock_ReleaseMutex(&fidp->mx);
3664
3665         /* call setattr */
3666         if (attr.mask)
3667             code = cm_SetAttr(scp, &attr, userp, &req);
3668         else
3669             code = 0;
3670     }
3671     else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3672         int delflag = *((char *)(p->datap));
3673         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p", 
3674                  delflag, fidp, scp);
3675         if (*((char *)(p->datap))) {    /* File is Deleted */
3676             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3677                                      &req);
3678             if (code == 0) {
3679                 lock_ObtainMutex(&fidp->mx);
3680                 fidp->flags |= SMB_FID_DELONCLOSE;
3681                 lock_ReleaseMutex(&fidp->mx);
3682             } else {
3683                 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x", 
3684                          fidp, scp, code);
3685             }
3686         }               
3687         else {  
3688             code = 0;
3689             lock_ObtainMutex(&fidp->mx);
3690             fidp->flags &= ~SMB_FID_DELONCLOSE;
3691             lock_ReleaseMutex(&fidp->mx);
3692         }
3693     }       
3694     else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3695              infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3696         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3697         cm_attr_t attr;
3698
3699         attr.mask = CM_ATTRMASK_LENGTH;
3700         attr.length.LowPart = size.LowPart;
3701         attr.length.HighPart = size.HighPart;
3702         code = cm_SetAttr(scp, &attr, userp, &req);
3703     }       
3704
3705   done:
3706     cm_ReleaseSCache(scp);
3707     cm_ReleaseUser(userp);
3708     smb_ReleaseFID(fidp);
3709     if (code == 0) 
3710         smb_SendTran2Packet(vcp, outp, opx);
3711     else 
3712         smb_SendTran2Error(vcp, p, opx, code);
3713     smb_FreeTran2Packet(outp);
3714
3715     return 0;
3716 }
3717
3718 /* TRANS2_FSCTL */
3719 long 
3720 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3721 {
3722     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3723     return CM_ERROR_BADOP;
3724 }
3725
3726 /* TRANS2_IOCTL2 */
3727 long 
3728 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3729 {
3730     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3731     return CM_ERROR_BADOP;
3732 }
3733
3734 /* TRANS2_FIND_NOTIFY_FIRST */
3735 long 
3736 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3737 {
3738     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3739     return CM_ERROR_BADOP;
3740 }
3741
3742 /* TRANS2_FIND_NOTIFY_NEXT */
3743 long 
3744 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3745 {
3746     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3747     return CM_ERROR_BADOP;
3748 }
3749
3750 /* TRANS2_CREATE_DIRECTORY */
3751 long 
3752 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3753 {
3754     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3755     return CM_ERROR_BADOP;
3756 }
3757
3758 /* TRANS2_SESSION_SETUP */
3759 long 
3760 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3761 {
3762     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3763     return CM_ERROR_BADOP;
3764 }
3765
3766 struct smb_v2_referral {
3767     USHORT ServerType;
3768     USHORT ReferralFlags;
3769     ULONG  Proximity;
3770     ULONG  TimeToLive;
3771     USHORT DfsPathOffset;
3772     USHORT DfsAlternativePathOffset;
3773     USHORT NetworkAddressOffset;
3774 };
3775
3776 /* TRANS2_GET_DFS_REFERRAL */
3777 long 
3778 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3779 {
3780     /* This is a UNICODE only request (bit15 of Flags2) */
3781     /* The TID must be IPC$ */
3782
3783     /* The documentation for the Flags response field is contradictory */
3784
3785     /* Use Version 1 Referral Element Format */
3786     /* ServerType = 0; indicates the next server should be queried for the file */
3787     /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3788     /* Node = UnicodeString of UNC path of the next share name */
3789 #ifdef DFS_SUPPORT
3790     long code = 0;
3791     int maxReferralLevel = 0;
3792     clientchar_t requestFileName[1024] = _C("");
3793     clientchar_t referralPath[1024] = _C("");
3794     smb_tran2Packet_t *outp = 0;
3795     cm_user_t *userp = 0;
3796     cm_scache_t *scp = 0;
3797     cm_scache_t *dscp = 0;
3798     cm_req_t req;
3799     CPINFO CodePageInfo;
3800     int i, nbnLen, reqLen, refLen;
3801     int idx;
3802
3803     smb_InitReq(&req);
3804
3805     maxReferralLevel = p->parmsp[0];
3806
3807     GetCPInfo(CP_ACP, &CodePageInfo);
3808     cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
3809
3810     osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]", 
3811              maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
3812
3813     nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
3814     reqLen = (int)cm_ClientStrLen(requestFileName);
3815
3816     if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
3817         !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
3818         requestFileName[nbnLen+1] == '\\') 
3819     {
3820         int found = 0;
3821
3822         if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
3823             !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
3824             found = 1;
3825             cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3826             refLen = reqLen;
3827         } else {
3828             userp = smb_GetTran2User(vcp, p);
3829             if (!userp) {
3830                 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3831                 code = CM_ERROR_BADSMB;
3832                 goto done;
3833             }   
3834             
3835             /* 
3836              * We have a requested path.  Check to see if it is something 
3837              * we know about.
3838                          *
3839                          * But be careful because the name that we might be searching
3840                          * for might be a known name with the final character stripped
3841                          * off.  If we 
3842              */
3843             code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
3844                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
3845                             userp, NULL, &req, &scp);
3846             if (code == 0) {
3847                 /* Yes it is. */
3848                 found = 1;
3849                 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
3850                 refLen = reqLen;
3851             } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
3852                 clientchar_t temp[1024];
3853                 clientchar_t pathName[1024];
3854                 clientchar_t *lastComponent;
3855                 /* 
3856                  * we have a msdfs link somewhere in the path
3857                  * we should figure out where in the path the link is.
3858                  * and return it.
3859                  */
3860                 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
3861
3862                 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
3863
3864                 do {
3865                     if (dscp) {
3866                         cm_ReleaseSCache(dscp);
3867                         dscp = 0;
3868                     }
3869                     if (scp) {
3870                         cm_ReleaseSCache(scp);
3871                         scp = 0;
3872                     }
3873                     smb_StripLastComponent(pathName, &lastComponent, temp);
3874
3875                     code = cm_NameI(cm_data.rootSCachep, pathName,
3876                                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3877                                     userp, NULL, &req, &dscp);
3878                     if (code == 0) {
3879                         code = cm_NameI(dscp, ++lastComponent,
3880                                         CM_FLAG_CASEFOLD,
3881                                         userp, NULL, &req, &scp);
3882                         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
3883                             break;
3884                     }
3885                 } while (code == CM_ERROR_PATH_NOT_COVERED);
3886
3887                 /* scp should now be the DfsLink we are looking for */
3888                 if (scp) {
3889                     /* figure out how much of the input path was used */
3890                     reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
3891
3892                     cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
3893                                               referralPath, lengthof(referralPath));
3894                     refLen = (int)cm_ClientStrLen(referralPath);
3895                     found = 1;
3896                 }
3897             } else {
3898                 clientchar_t shareName[MAX_PATH + 1];
3899                 clientchar_t *p, *q;
3900                 /* we may have a sharename that is a volume reference */
3901
3902                 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
3903                 {
3904                     *q = *p;
3905                 }
3906                 *q = '\0';
3907                 
3908                 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
3909                     code = cm_NameI(cm_data.rootSCachep, _C(""), 
3910                                     CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
3911                                     userp, p, &req, &scp);
3912                     free(p);
3913
3914                     if (code == 0) {
3915                         found = 1;
3916                         cm_ClientStrCpy(referralPath, lengthof(referralPath),
3917                                         requestFileName);
3918                         refLen = reqLen;
3919                     }
3920                 }
3921             }
3922         }
3923         
3924         if (found)
3925         {
3926             USHORT * sp;
3927             struct smb_v2_referral * v2ref;
3928             outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
3929
3930             sp = (USHORT *)outp->datap;
3931             idx = 0;
3932             sp[idx++] = reqLen;   /* path consumed */
3933             sp[idx++] = 1;        /* number of referrals */
3934             sp[idx++] = 0x03;     /* flags */
3935 #ifdef DFS_VERSION_1
3936             sp[idx++] = 1;        /* Version Number */
3937             sp[idx++] = refLen + 4;  /* Referral Size */ 
3938             sp[idx++] = 1;        /* Type = SMB Server */
3939             sp[idx++] = 0;        /* Do not strip path consumed */
3940             for ( i=0;i<=refLen; i++ )
3941                 sp[i+idx] = referralPath[i];
3942 #else /* DFS_VERSION_2 */
3943             sp[idx++] = 2;      /* Version Number */
3944             sp[idx++] = sizeof(struct smb_v2_referral);     /* Referral Size */
3945             idx += (sizeof(struct smb_v2_referral) / 2);
3946             v2ref = (struct smb_v2_referral *) &sp[5];
3947             v2ref->ServerType = 1;  /* SMB Server */
3948             v2ref->ReferralFlags = 0x03;
3949             v2ref->Proximity = 0;   /* closest */
3950             v2ref->TimeToLive = 3600; /* seconds */
3951             v2ref->DfsPathOffset = idx * 2;
3952             v2ref->DfsAlternativePathOffset = idx * 2;
3953             v2ref->NetworkAddressOffset = 0;
3954             for ( i=0;i<=refLen; i++ )
3955                 sp[i+idx] = referralPath[i];
3956 #endif
3957         } 
3958     } else {
3959         code = CM_ERROR_NOSUCHPATH;
3960     }
3961          
3962   done:
3963     if (dscp)
3964         cm_ReleaseSCache(dscp);
3965     if (scp)
3966         cm_ReleaseSCache(scp);
3967     if (userp)
3968         cm_ReleaseUser(userp);
3969     if (code == 0) 
3970         smb_SendTran2Packet(vcp, outp, op);
3971     else 
3972         smb_SendTran2Error(vcp, p, op, code);
3973     if (outp)
3974         smb_FreeTran2Packet(outp);
3975  
3976     return 0;
3977 #else /* DFS_SUPPORT */
3978     osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED"); 
3979     return CM_ERROR_NOSUCHDEVICE;
3980 #endif /* DFS_SUPPORT */
3981 }
3982
3983 /* TRANS2_REPORT_DFS_INCONSISTENCY */
3984 long 
3985 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3986 {
3987     /* This is a UNICODE only request (bit15 of Flags2) */
3988
3989     /* There is nothing we can do about this operation.  The client is going to
3990      * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3991      * Unfortunately, there is really nothing we can do about it other then log it 
3992      * somewhere.  Even then I don't think there is anything for us to do.
3993      * So let's return an error value.
3994      */
3995
3996     osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3997     return CM_ERROR_BADOP;
3998 }
3999
4000 static long 
4001 smb_ApplyV3DirListPatches(cm_scache_t *dscp, smb_dirListPatch_t **dirPatchespp, 
4002                           clientchar_t * tidPathp, clientchar_t * relPathp, 
4003                           int infoLevel, cm_user_t *userp, cm_req_t *reqp)
4004 {
4005     long code = 0;
4006     cm_scache_t *scp;
4007     cm_scache_t *targetScp;                     /* target if scp is a symlink */
4008     afs_uint32 dosTime;
4009     FILETIME ft;
4010     unsigned short attr;
4011     unsigned long lattr;
4012     smb_dirListPatch_t *patchp;
4013     smb_dirListPatch_t *npatchp;
4014     afs_uint32 rights;
4015     afs_int32 mustFake = 0;
4016     clientchar_t path[AFSPATHMAX];
4017
4018     code = cm_FindACLCache(dscp, userp, &rights);
4019     if (code == -1) {
4020         lock_ObtainWrite(&dscp->rw);
4021         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4022                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4023         if (code == 0) 
4024             cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4025         lock_ReleaseWrite(&dscp->rw);
4026         if (code == CM_ERROR_NOACCESS) {
4027             mustFake = 1;
4028             code = 0;
4029         }
4030     }
4031     if (code)
4032         goto cleanup;
4033
4034     if (!mustFake) {    /* Bulk Stat */
4035         afs_uint32 count;
4036         cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4037
4038         memset(bsp, 0, sizeof(cm_bulkStat_t));
4039
4040         for (patchp = *dirPatchespp, count=0; 
4041              patchp; 
4042              patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4043             cm_scache_t *tscp = NULL;
4044             int i;
4045             
4046             code = cm_GetSCache(&patchp->fid, &tscp, userp, reqp);
4047             if (code == 0) {
4048                 if (lock_TryWrite(&tscp->rw)) {
4049                     /* we have an entry that we can look at */
4050 #ifdef AFS_FREELANCE_CLIENT
4051                     if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
4052                         code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4053                                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4054                         if (code == 0) 
4055                             cm_SyncOpDone(tscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4056
4057                         lock_ReleaseWrite(&tscp->rw);
4058                         cm_ReleaseSCache(tscp);
4059                         continue;
4060                     }
4061 #endif /* AFS_FREELANCE_CLIENT */
4062                     if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4063                         /* we have a callback on it.  Don't bother
4064                         * fetching this stat entry, since we're happy
4065                         * with the info we have.
4066                         */
4067                         lock_ReleaseWrite(&tscp->rw);
4068                         cm_ReleaseSCache(tscp);
4069                         continue;
4070                     }
4071                     lock_ReleaseWrite(&tscp->rw);
4072                 } /* got lock */
4073                 cm_ReleaseSCache(tscp);
4074             }   /* found entry */
4075
4076             i = bsp->counter++;
4077             bsp->fids[i].Volume = patchp->fid.volume;
4078             bsp->fids[i].Vnode = patchp->fid.vnode;
4079             bsp->fids[i].Unique = patchp->fid.unique;
4080
4081             if (bsp->counter == AFSCBMAX) {
4082                 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4083                 memset(bsp, 0, sizeof(cm_bulkStat_t));
4084             }
4085         }
4086
4087         if (bsp->counter > 0)
4088             code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4089
4090         free(bsp);
4091     }
4092
4093     for( patchp = *dirPatchespp; 
4094          patchp; 
4095          patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4096         cm_ClientStrPrintfN(path, lengthof(path),_C("%s\\%S"),
4097                             relPathp ? relPathp : _C(""), patchp->dep->name);
4098         reqp->relPathp = path;
4099         reqp->tidPathp = tidPathp;
4100
4101         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4102         reqp->relPathp = reqp->tidPathp = NULL;
4103         if (code) 
4104             continue;
4105
4106         lock_ObtainWrite(&scp->rw);
4107         if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4108             lock_ReleaseWrite(&scp->rw);
4109
4110             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
4111                errors in the client. */
4112             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4113                 smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4114
4115                 /* 1969-12-31 23:59:59 +00 */
4116                 ft.dwHighDateTime = 0x19DB200;
4117                 ft.dwLowDateTime = 0x5BB78980;
4118
4119                 /* copy to Creation Time */
4120                 fa->creationTime = ft;
4121                 fa->lastAccessTime = ft;
4122                 fa->lastWriteTime = ft;
4123                 fa->lastChangeTime = ft;
4124
4125                 switch (scp->fileType) {
4126                 case CM_SCACHETYPE_DIRECTORY:
4127                 case CM_SCACHETYPE_MOUNTPOINT:
4128                 case CM_SCACHETYPE_SYMLINK:
4129                 case CM_SCACHETYPE_INVALID:
4130                     fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4131                     break;
4132                 default:
4133                     /* if we get here we either have a normal file
4134                      * or we have a file for which we have never 
4135                      * received status info.  In this case, we can
4136                      * check the even/odd value of the entry's vnode.
4137                      * even means it is to be treated as a directory
4138                      * and odd means it is to be treated as a file.
4139                      */
4140                     if (mustFake && (scp->fid.vnode & 0x1))
4141                         fa->extFileAttributes = SMB_ATTR_DIRECTORY;
4142                     else
4143                         fa->extFileAttributes = SMB_ATTR_NORMAL;
4144                 }
4145                 /* merge in hidden attribute */
4146                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4147                     fa->extFileAttributes |= SMB_ATTR_HIDDEN;
4148                 }
4149             } else {
4150                 smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4151
4152                 /* 1969-12-31 23:59:58 +00*/
4153                 dosTime = 0xEBBFBF7D;
4154
4155                 fa->creationDateTime = MAKELONG(HIWORD(dosTime),LOWORD(dosTime));
4156                 fa->lastAccessDateTime = fa->creationDateTime;
4157                 fa->lastWriteDateTime = fa->creationDateTime;
4158
4159                 /* set the attribute */
4160                 switch (scp->fileType) {
4161                 case CM_SCACHETYPE_DIRECTORY:
4162                 case CM_SCACHETYPE_MOUNTPOINT:
4163                 case CM_SCACHETYPE_SYMLINK:
4164                 case CM_SCACHETYPE_INVALID:
4165                     fa->attributes = SMB_ATTR_DIRECTORY;
4166                     break;
4167                 default:
4168                     /* if we get here we either have a normal file
4169                      * or we have a file for which we have never 
4170                      * received status info.  In this case, we can
4171                      * check the even/odd value of the entry's vnode.
4172                      * even means it is to be treated as a directory
4173                      * and odd means it is to be treated as a file.
4174                      */
4175                     if (mustFake && (scp->fid.vnode & 0x1))
4176                         fa->attributes = SMB_ATTR_DIRECTORY;
4177                     else
4178                         fa->attributes = SMB_ATTR_NORMAL;
4179                 }
4180
4181                 /* merge in hidden (dot file) attribute */
4182                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4183                     fa->attributes |= SMB_ATTR_HIDDEN;
4184                 }       
4185             }
4186             
4187             cm_ReleaseSCache(scp);
4188             continue;
4189         }
4190         
4191         /* now watch for a symlink */
4192         code = 0;
4193         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
4194             lock_ReleaseWrite(&scp->rw);
4195             cm_ClientStrPrintfN(path, lengthof(path), _C("%s\\%S"),
4196                                 relPathp ? relPathp : _C(""), patchp->dep->name);
4197             reqp->relPathp = path;
4198             reqp->tidPathp = tidPathp;
4199             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
4200             reqp->relPathp = reqp->tidPathp = NULL;
4201             if (code == 0) {
4202                 /* we have a more accurate file to use (the
4203                  * target of the symbolic link).  Otherwise,
4204                  * we'll just use the symlink anyway.
4205                  */
4206                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
4207                           scp, targetScp);
4208                 cm_ReleaseSCache(scp);
4209                 scp = targetScp;
4210             }
4211             lock_ObtainWrite(&scp->rw);
4212         }
4213
4214         lock_ConvertWToR(&scp->rw);
4215
4216         if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4217             smb_V3FileAttrsLong * fa = (smb_V3FileAttrsLong *) patchp->dptr;
4218
4219             /* get filetime */
4220             smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
4221
4222             fa->creationTime = ft;
4223             fa->lastAccessTime = ft;
4224             fa->lastWriteTime = ft;
4225             fa->lastChangeTime = ft;
4226
4227             /* Use length for both file length and alloc length */
4228             fa->endOfFile = scp->length;
4229             fa->allocationSize = scp->length;
4230
4231             /* Copy attributes */
4232             lattr = smb_ExtAttributes(scp);
4233             if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK ||
4234                 code == CM_ERROR_PATH_NOT_COVERED && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4235                 if (lattr == SMB_ATTR_NORMAL)
4236                     lattr = SMB_ATTR_DIRECTORY;
4237                 else
4238                     lattr |= SMB_ATTR_DIRECTORY;
4239             }
4240             /* merge in hidden (dot file) attribute */
4241             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4242                 if (lattr == SMB_ATTR_NORMAL)
4243                     lattr = SMB_ATTR_HIDDEN;
4244                 else
4245                     lattr |= SMB_ATTR_HIDDEN;
4246             }
4247
4248             fa->extFileAttributes = lattr;
4249         } else {
4250             smb_V3FileAttrsShort * fa = (smb_V3FileAttrsShort *) patchp->dptr;
4251
4252             /* get dos time */
4253             smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4254
4255             fa->creationDateTime = MAKELONG(HIWORD(dosTime), LOWORD(dosTime));
4256             fa->lastAccessDateTime = fa->creationDateTime;
4257             fa->lastWriteDateTime = fa->creationDateTime;
4258
4259             /* copy out file length and alloc length,
4260              * using the same for both
4261              */
4262             fa->dataSize = scp->length.LowPart;
4263             fa->allocationSize = scp->length.LowPart;
4264
4265             /* finally copy out attributes as short */
4266             attr = smb_Attributes(scp);
4267             /* merge in hidden (dot file) attribute */
4268             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
4269                 if (lattr == SMB_ATTR_NORMAL)
4270                     lattr = SMB_ATTR_HIDDEN;
4271                 else
4272                     lattr |= SMB_ATTR_HIDDEN;
4273             }
4274             fa->attributes = attr;
4275         }
4276
4277         lock_ReleaseRead(&scp->rw);
4278         cm_ReleaseSCache(scp);
4279     }
4280         
4281     /* now free the patches */
4282     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4283         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4284         free(patchp);
4285     }
4286         
4287     /* and mark the list as empty */
4288     *dirPatchespp = NULL;
4289
4290   cleanup:
4291     return code;
4292 }
4293
4294 /* smb_ReceiveTran2SearchDir implements both 
4295  * Tran2_Find_First and Tran2_Find_Next
4296  */
4297 #define TRAN2_FIND_FLAG_CLOSE_SEARCH            0x01
4298 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END     0x02
4299 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS      0x04
4300 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH         0x08
4301 #define TRAN2_FIND_FLAG_BACKUP_INTENT           0x10
4302
4303 /* this is an optimized handler for T2SearchDir that handles the case
4304    where there are no wildcards in the search path.  I.e. an
4305    application is using FindFirst(Ex) to get information about a
4306    single file or directory.  It will attempt to do a single lookup.
4307    If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4308    the usual mechanism. 
4309    
4310    This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4311
4312    TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
4313    */
4314 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4315 {
4316     int attribute;
4317     long nextCookie;
4318     long code = 0, code2 = 0;
4319     clientchar_t *pathp = 0;
4320     int maxCount;
4321     smb_dirListPatch_t *dirListPatchesp;
4322     smb_dirListPatch_t *curPatchp;
4323     size_t orbytes;                     /* # of bytes in this output record */
4324     size_t ohbytes;                     /* # of bytes, except file name */
4325     size_t onbytes;                     /* # of bytes in name, incl. term. null */
4326     cm_scache_t *scp = NULL;
4327     cm_scache_t *targetscp = NULL;
4328     cm_user_t *userp = NULL;
4329     char *op;                           /* output data ptr */
4330     char *origOp;                       /* original value of op */
4331     cm_space_t *spacep;                 /* for pathname buffer */
4332     unsigned long maxReturnData;        /* max # of return data */
4333     long maxReturnParms;                /* max # of return parms */
4334     long bytesInBuffer;                 /* # data bytes in the output buffer */
4335     clientchar_t *maskp;                        /* mask part of path */
4336     int infoLevel;
4337     int searchFlags;
4338     int eos;
4339     smb_tran2Packet_t *outp;            /* response packet */
4340     clientchar_t *tidPathp = 0;
4341     int align;
4342     clientchar_t shortName[13];                 /* 8.3 name if needed */
4343     int NeedShortName;
4344     clientchar_t *shortNameEnd;
4345     cm_dirEntry_t * dep = NULL;
4346     cm_req_t req;
4347     char * s;
4348     void * attrp = NULL;
4349     smb_tran2Find_t * fp;
4350
4351     smb_InitReq(&req);
4352
4353     eos = 0;
4354     osi_assertx(p->opcode == 1, "invalid opcode");
4355
4356     /* find first; obtain basic parameters from request */
4357
4358     /* note that since we are going to failover to regular
4359      * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4360      * modify any of the input parameters here. */
4361     attribute = p->parmsp[0];
4362     maxCount = p->parmsp[1];
4363     infoLevel = p->parmsp[3];
4364     searchFlags = p->parmsp[2];
4365     pathp = smb_ParseStringT2Parm(p, (char *) &(p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4366     nextCookie = 0;
4367     maskp = cm_ClientStrRChr(pathp,  '\\');
4368     if (maskp == NULL) 
4369         maskp = pathp;
4370     else 
4371         maskp++;        /* skip over backslash */
4372     /* track if this is likely to match a lot of entries */
4373
4374     osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%S], mask[%S]",
4375              osi_LogSaveClientString(smb_logp, pathp),
4376              osi_LogSaveClientString(smb_logp, maskp));
4377
4378     switch ( infoLevel ) {
4379     case SMB_INFO_STANDARD:
4380         s = "InfoStandard";
4381         ohbytes = sizeof(fp->u.FstandardInfo);
4382         break;
4383
4384     case SMB_INFO_QUERY_EA_SIZE:
4385         ohbytes = sizeof(fp->u.FeaSizeInfo);
4386         s = "InfoQueryEaSize";
4387         break;
4388
4389     case SMB_INFO_QUERY_EAS_FROM_LIST:
4390         ohbytes = sizeof(fp->u.FeasFromListInfo);
4391         s = "InfoQueryEasFromList";
4392         break;
4393
4394     case SMB_FIND_FILE_DIRECTORY_INFO:
4395         s = "FindFileDirectoryInfo";
4396         ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4397         break;
4398
4399     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4400         s = "FindFileFullDirectoryInfo";
4401         ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4402         break;
4403
4404     case SMB_FIND_FILE_NAMES_INFO:
4405         s = "FindFileNamesInfo";
4406         ohbytes = sizeof(fp->u.FfileNamesInfo);
4407         break;
4408
4409     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4410         s = "FindFileBothDirectoryInfo";
4411         ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4412         break;
4413
4414     default:
4415         s = "unknownInfoLevel";
4416         ohbytes = 0;
4417     }
4418
4419     osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4420
4421     osi_Log4(smb_logp,
4422              "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4423              attribute, infoLevel, maxCount, searchFlags);
4424     
4425     if (ohbytes == 0) {
4426         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4427         return CM_ERROR_INVAL;
4428     }
4429
4430     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4431         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;     /* no resume keys */
4432
4433     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4434         ohbytes += 4;
4435
4436     dirListPatchesp = NULL;
4437
4438     maxReturnData = p->maxReturnData;
4439     maxReturnParms = 10;        /* return params for findfirst, which
4440                                    is the only one we handle.*/
4441
4442     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4443                                       maxReturnData);
4444
4445     osi_Log2(smb_logp, "T2SDSingle search dir count %d [%S]",
4446              maxCount, osi_LogSaveClientString(smb_logp, pathp));
4447         
4448     /* bail out if request looks bad */
4449     if (!pathp) {
4450         smb_FreeTran2Packet(outp);
4451         return CM_ERROR_BADSMB;
4452     }
4453         
4454     userp = smb_GetTran2User(vcp, p);
4455     if (!userp) {
4456         osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4457         smb_FreeTran2Packet(outp);
4458         return CM_ERROR_BADSMB;
4459     }
4460
4461     /* try to get the vnode for the path name next */
4462     spacep = cm_GetSpace();
4463     smb_StripLastComponent(spacep->wdata, NULL, pathp);
4464     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4465     if (code) {
4466         cm_ReleaseUser(userp);
4467         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4468         smb_FreeTran2Packet(outp);
4469         return 0;
4470     }
4471
4472     code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4473                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4474                     userp, tidPathp, &req, &scp);
4475     cm_FreeSpace(spacep);
4476
4477     if (code) {
4478         cm_ReleaseUser(userp);
4479         smb_SendTran2Error(vcp, p, opx, code);
4480         smb_FreeTran2Packet(outp);
4481         return 0;
4482     }
4483
4484 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4485     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4486         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4487         cm_ReleaseSCache(scp);
4488         cm_ReleaseUser(userp);
4489         if ( WANTS_DFS_PATHNAMES(p) || pnc )
4490             code = CM_ERROR_PATH_NOT_COVERED;
4491         else
4492             code = CM_ERROR_BADSHARENAME;
4493         smb_SendTran2Error(vcp, p, opx, code);
4494         smb_FreeTran2Packet(outp);
4495         return 0;
4496     }
4497 #endif /* DFS_SUPPORT */
4498     osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4499
4500     /* now do a single case sensitive lookup for the file in question */
4501     code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4502
4503     /* if a case sensitive match failed, we try a case insensitive one
4504        next. */
4505     if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4506         code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4507     }
4508
4509     if (code == 0 && targetscp->fid.vnode == 0) {
4510         cm_ReleaseSCache(targetscp);
4511         code = CM_ERROR_NOSUCHFILE;
4512     }
4513
4514     if (code) {
4515         /* if we can't find the directory entry, this block will
4516            return CM_ERROR_NOSUCHFILE, which we will pass on to
4517            smb_ReceiveTran2SearchDir(). */
4518         cm_ReleaseSCache(scp);
4519         cm_ReleaseUser(userp);
4520         if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4521             smb_SendTran2Error(vcp, p, opx, code);
4522             code = 0;
4523         }
4524         smb_FreeTran2Packet(outp);
4525         return code;
4526     }
4527
4528     /* now that we have the target in sight, we proceed with filling
4529        up the return data. */
4530
4531     op = origOp = outp->datap;
4532     bytesInBuffer = 0;
4533
4534     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4535         /* skip over resume key */
4536         op += 4;
4537     }
4538
4539     fp = (smb_tran2Find_t *) op;
4540
4541     if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4542         && targetscp->fid.vnode != 0
4543         && !cm_Is8Dot3(maskp)) {
4544
4545         cm_dirFid_t dfid;
4546         dfid.vnode = htonl(targetscp->fid.vnode);
4547         dfid.unique = htonl(targetscp->fid.unique);
4548
4549         cm_Gen8Dot3NameIntW(maskp, &dfid, shortName, &shortNameEnd);
4550         NeedShortName = 1;
4551     } else {
4552         NeedShortName = 0;
4553     }
4554
4555     osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %S (%S)",
4556              htonl(targetscp->fid.vnode),
4557              htonl(targetscp->fid.unique),
4558              osi_LogSaveClientString(smb_logp, pathp),
4559              (NeedShortName)? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
4560
4561     /* Eliminate entries that don't match requested attributes */
4562     if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4563         smb_IsDotFile(maskp)) {
4564
4565         code = CM_ERROR_NOSUCHFILE;
4566         osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4567         goto skip_file;
4568
4569     }
4570
4571     if (!(attribute & SMB_ATTR_DIRECTORY) &&
4572         (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4573          targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4574          targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4575          targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4576
4577         code = CM_ERROR_NOSUCHFILE;
4578         osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4579         goto skip_file;
4580
4581     }
4582
4583     /* add header to name & term. null */
4584     onbytes = 0;
4585     smb_UnparseString(opx, NULL, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4586     orbytes = ohbytes + onbytes;
4587
4588     /* now, we round up the record to a 4 byte alignment, and we make
4589      * sure that we have enough room here for even the aligned version
4590      * (so we don't have to worry about an * overflow when we pad
4591      * things out below).  That's the reason for the alignment
4592      * arithmetic below.
4593      */
4594     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4595         align = (4 - (orbytes & 3)) & 3;
4596     else
4597         align = 0;
4598
4599     if (orbytes + align > maxReturnData) {
4600
4601         /* even though this request is unlikely to succeed with a
4602            failover, we do it anyway. */
4603         code = CM_ERROR_NOSUCHFILE;
4604         osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4605                  maxReturnData);
4606         goto skip_file;
4607     }
4608
4609     /* this is one of the entries to use: it is not deleted and it
4610      * matches the star pattern we're looking for.  Put out the name,
4611      * preceded by its length.
4612      */
4613     /* First zero everything else */
4614     memset(origOp, 0, orbytes);
4615
4616     onbytes = 0;
4617     smb_UnparseString(opx, origOp + ohbytes, maskp, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
4618
4619     switch (infoLevel) {
4620     case SMB_INFO_STANDARD:
4621         fp->u.FstandardInfo.fileNameLength = onbytes;
4622         attrp = &fp->u.FstandardInfo.fileAttrs;
4623         break;
4624
4625     case SMB_INFO_QUERY_EA_SIZE:
4626         fp->u.FeaSizeInfo.fileNameLength = onbytes;
4627         attrp = &fp->u.FeaSizeInfo.fileAttrs;
4628         fp->u.FeaSizeInfo.eaSize = 0;
4629         break;
4630
4631     case SMB_INFO_QUERY_EAS_FROM_LIST:
4632         fp->u.FeasFromListInfo.fileNameLength = onbytes;
4633         attrp = &fp->u.FeasFromListInfo.fileAttrs;
4634         fp->u.FeasFromListInfo.eaSize = 0;
4635         break;
4636
4637     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4638         if (NeedShortName) {
4639 #ifdef SMB_UNICODE
4640             int nchars;
4641
4642             nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
4643                                             fp->u.FfileBothDirectoryInfo.shortName,
4644                                             sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
4645             if (nchars > 0)
4646                 fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
4647             else
4648                 fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
4649             fp->u.FfileBothDirectoryInfo.reserved = 0;
4650 #else
4651             strcpy(fp->u.FfileBothDirectoryInfo.shortName,
4652                    shortName);
4653             fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
4654 #endif
4655     }
4656         /* Fallthrough */
4657
4658     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4659         fp->u.FfileFullDirectoryInfo.eaSize = 0;
4660         /* Fallthrough */
4661
4662     case SMB_FIND_FILE_DIRECTORY_INFO:
4663         fp->u.FfileDirectoryInfo.nextEntryOffset = 0;
4664         fp->u.FfileDirectoryInfo.fileIndex = 0;
4665         attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
4666         fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
4667         break;
4668
4669     case SMB_FIND_FILE_NAMES_INFO:
4670         fp->u.FfileNamesInfo.nextEntryOffset = 0;
4671         fp->u.FfileNamesInfo.fileIndex = 0;
4672         fp->u.FfileNamesInfo.fileNameLength = onbytes;
4673         break;
4674
4675     default:
4676         /* we shouldn't hit this case */
4677         osi_assertx(FALSE, "Unknown query type");
4678     }
4679
4680     if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4681         osi_assert(attrp != NULL);
4682
4683         curPatchp = malloc(sizeof(*curPatchp));
4684         osi_QAdd((osi_queue_t **) &dirListPatchesp,
4685                  &curPatchp->q);
4686         curPatchp->dptr = attrp;
4687
4688         if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4689             curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4690         } else {
4691             curPatchp->flags = 0;
4692         }
4693
4694         cm_SetFid(&curPatchp->fid, targetscp->fid.cell, targetscp->fid.volume, targetscp->fid.vnode, targetscp->fid.unique);
4695
4696         /* temp */
4697         {
4698             int namelen = cm_ClientStringToFsString(maskp, -1, NULL, 0);
4699             dep = (cm_dirEntry_t *)malloc(sizeof(cm_dirEntry_t)+namelen);
4700             cm_ClientStringToFsString(maskp, -1, dep->name, namelen);
4701         }
4702         dep->fid.vnode = targetscp->fid.vnode;
4703         dep->fid.unique = targetscp->fid.unique;
4704         curPatchp->dep = dep;
4705     }   
4706
4707     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4708         /* put out resume key */
4709         *((u_long *)origOp) = 0;
4710     }
4711
4712     /* Adjust byte ptr and count */
4713     origOp += orbytes;  /* skip entire record */
4714     bytesInBuffer += orbytes;
4715
4716     /* and pad the record out */
4717     while (--align >= 0) {
4718         *origOp++ = 0;
4719         bytesInBuffer++;
4720     }
4721
4722     /* apply the patches */
4723     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, tidPathp, spacep->wdata, infoLevel, userp, &req);
4724
4725     outp->parmsp[0] = 0;
4726     outp->parmsp[1] = 1;        /* number of names returned */
4727     outp->parmsp[2] = 1;        /* end of search */
4728     outp->parmsp[3] = 0;        /* nothing wrong with EAS */
4729     outp->parmsp[4] = 0;
4730
4731     outp->totalParms = 10;      /* in bytes */
4732
4733     outp->totalData = bytesInBuffer;
4734
4735     osi_Log0(smb_logp, "T2SDSingle done.");
4736
4737     if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4738         if (code)
4739             smb_SendTran2Error(vcp, p, opx, code);
4740         else
4741             smb_SendTran2Packet(vcp, outp, opx);
4742         code = 0;
4743     }
4744
4745  skip_file:
4746     smb_FreeTran2Packet(outp);
4747     if (dep)
4748         free(dep);
4749     if (scp)
4750     cm_ReleaseSCache(scp);
4751     cm_ReleaseSCache(targetscp);
4752     cm_ReleaseUser(userp);
4753
4754     return code;
4755 }
4756
4757
4758 /* TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 */
4759 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4760 {
4761     int attribute;
4762     long nextCookie;
4763     char *tp;
4764     long code = 0, code2 = 0;
4765     clientchar_t *pathp;
4766     cm_dirEntry_t *dep = 0;
4767     int maxCount;
4768     smb_dirListPatch_t *dirListPatchesp = 0;
4769     smb_dirListPatch_t *curPatchp = 0;
4770     cm_buf_t *bufferp;
4771     long temp;
4772     size_t orbytes;                     /* # of bytes in this output record */
4773     size_t ohbytes;                     /* # of bytes, except file name */
4774     size_t onbytes;                     /* # of bytes in name, incl. term. null */
4775     osi_hyper_t dirLength;
4776     osi_hyper_t bufferOffset;
4777     osi_hyper_t curOffset;
4778     osi_hyper_t thyper;
4779     smb_dirSearch_t *dsp;
4780     cm_scache_t *scp;
4781     long entryInDir;
4782     long entryInBuffer;
4783     cm_pageHeader_t *pageHeaderp;
4784     cm_user_t *userp = NULL;
4785     int slotInPage;
4786     int returnedNames;
4787     long nextEntryCookie;
4788     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
4789     char *op;                   /* output data ptr */
4790     char *origOp;                       /* original value of op */
4791     cm_space_t *spacep;         /* for pathname buffer */
4792     unsigned long maxReturnData;                /* max # of return data */
4793     unsigned long maxReturnParms;               /* max # of return parms */
4794     long bytesInBuffer;         /* # data bytes in the output buffer */
4795     int starPattern;
4796     clientchar_t *maskp;                        /* mask part of path */
4797     int infoLevel;
4798     int searchFlags;
4799     int eos;
4800     smb_tran2Packet_t *outp;    /* response packet */
4801     clientchar_t *tidPathp;
4802     unsigned int align;
4803     clientchar_t shortName[13];         /* 8.3 name if needed */
4804     int NeedShortName;
4805     int foundInexact;
4806     clientchar_t *shortNameEnd;
4807     int fileType;
4808     cm_fid_t fid;
4809     cm_req_t req;
4810     void * attrp;
4811     char * s;
4812     smb_tran2Find_t * fp;
4813
4814     smb_InitReq(&req);
4815
4816     eos = 0;
4817     if (p->opcode == 1) {
4818         /* find first; obtain basic parameters from request */
4819         attribute = p->parmsp[0];
4820         maxCount = p->parmsp[1];
4821         infoLevel = p->parmsp[3];
4822         searchFlags = p->parmsp[2];
4823         pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[6]), NULL, SMB_STRF_ANSIPATH);
4824         nextCookie = 0;
4825         maskp = cm_ClientStrRChr(pathp,  '\\');
4826         if (maskp == NULL) 
4827             maskp = pathp;
4828         else 
4829             maskp++;    /* skip over backslash */
4830
4831         /* track if this is likely to match a lot of entries */
4832         starPattern = smb_V3IsStarMask(maskp);
4833
4834 #ifndef NOFINDFIRSTOPTIMIZE
4835         if (!starPattern) {
4836             /* if this is for a single directory or file, we let the
4837                optimized routine handle it.  The only error it 
4838                returns is CM_ERROR_NOSUCHFILE.  The  */
4839             code = smb_T2SearchDirSingle(vcp, p, opx);
4840
4841             /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4842             if (code != CM_ERROR_NOSUCHFILE) {
4843 #ifdef USE_BPLUS
4844                 /* unless we are using the BPlusTree */
4845                 if (code == CM_ERROR_BPLUS_NOMATCH)
4846                     code = CM_ERROR_NOSUCHFILE;
4847 #endif /* USE_BPLUS */
4848                 return code;
4849             }
4850         }
4851 #endif  /* NOFINDFIRSTOPTIMIZE */
4852         dir_enums++;
4853
4854         dsp = smb_NewDirSearch(1);
4855         dsp->attribute = attribute;
4856         cm_ClientStrCpy(dsp->mask, lengthof(dsp->mask),  maskp);        /* and save mask */
4857     }
4858     else {
4859         osi_assertx(p->opcode == 2, "invalid opcode");
4860         /* find next; obtain basic parameters from request or open dir file */
4861         dsp = smb_FindDirSearch(p->parmsp[0]);
4862         maxCount = p->parmsp[1];
4863         infoLevel = p->parmsp[2];
4864         nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4865         searchFlags = p->parmsp[5];
4866         if (!dsp) {
4867             osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4868                      p->parmsp[0], nextCookie);
4869             return CM_ERROR_BADFD;
4870         }
4871         attribute = dsp->attribute;
4872         pathp = NULL;
4873         maskp = dsp->mask;
4874         starPattern = 1;        /* assume, since required a Find Next */
4875     }
4876
4877     switch ( infoLevel ) {
4878     case SMB_INFO_STANDARD:
4879         s = "InfoStandard";
4880         ohbytes = sizeof(fp->u.FstandardInfo);
4881         break;
4882
4883     case SMB_INFO_QUERY_EA_SIZE:
4884         ohbytes = sizeof(fp->u.FeaSizeInfo);
4885         s = "InfoQueryEaSize";
4886         break;
4887
4888     case SMB_INFO_QUERY_EAS_FROM_LIST:
4889         ohbytes = sizeof(fp->u.FeasFromListInfo);
4890         s = "InfoQueryEasFromList";
4891         break;
4892
4893     case SMB_FIND_FILE_DIRECTORY_INFO:
4894         s = "FindFileDirectoryInfo";
4895         ohbytes = sizeof(fp->u.FfileDirectoryInfo);
4896         break;
4897
4898     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4899         s = "FindFileFullDirectoryInfo";
4900         ohbytes = sizeof(fp->u.FfileFullDirectoryInfo);
4901         break;
4902
4903     case SMB_FIND_FILE_NAMES_INFO:
4904         s = "FindFileNamesInfo";
4905         ohbytes = sizeof(fp->u.FfileNamesInfo);
4906         break;
4907
4908     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4909         s = "FindFileBothDirectoryInfo";
4910         ohbytes = sizeof(fp->u.FfileBothDirectoryInfo);
4911         break;
4912
4913     default:
4914         s = "unknownInfoLevel";
4915         ohbytes = 0;
4916     }
4917
4918     osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4919
4920     osi_Log4(smb_logp,
4921               "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4922               attribute, infoLevel, maxCount, searchFlags);
4923
4924     osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4925               p->opcode, dsp->cookie, nextCookie);
4926
4927     if (ohbytes == 0) {
4928         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4929         smb_ReleaseDirSearch(dsp);
4930         return CM_ERROR_INVAL;
4931     }
4932
4933     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4934         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;     /* no resume keys */
4935
4936     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4937         ohbytes += 4;
4938
4939     dirListPatchesp = NULL;
4940
4941     maxReturnData = p->maxReturnData;
4942     if (p->opcode == 1) /* find first */
4943         maxReturnParms = 10;    /* bytes */
4944     else    
4945         maxReturnParms = 8;     /* bytes */
4946
4947     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4948                                       maxReturnData);
4949
4950     if (maxCount > 500)
4951         maxCount = 500;
4952
4953     osi_Log2(smb_logp, "T2 receive search dir count %d [%S]",
4954              maxCount, osi_LogSaveClientString(smb_logp, pathp));
4955         
4956     /* bail out if request looks bad */
4957     if (p->opcode == 1 && !pathp) {
4958         smb_ReleaseDirSearch(dsp);
4959         smb_FreeTran2Packet(outp);
4960         return CM_ERROR_BADSMB;
4961     }
4962         
4963     osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4964              dsp->cookie, nextCookie, attribute);
4965
4966     userp = smb_GetTran2User(vcp, p);
4967     if (!userp) {
4968         osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4969         smb_ReleaseDirSearch(dsp);
4970         smb_FreeTran2Packet(outp);
4971         return CM_ERROR_BADSMB;
4972     }
4973
4974     /* try to get the vnode for the path name next */
4975     lock_ObtainMutex(&dsp->mx);
4976     if (dsp->scp) {
4977         scp = dsp->scp;
4978         osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4979         cm_HoldSCache(scp);
4980         code = 0;
4981     } else {
4982         spacep = cm_GetSpace();
4983         smb_StripLastComponent(spacep->wdata, NULL, pathp);
4984         code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4985         if (code) {
4986             cm_ReleaseUser(userp);
4987             smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4988             smb_FreeTran2Packet(outp);
4989             lock_ReleaseMutex(&dsp->mx);
4990             smb_DeleteDirSearch(dsp);
4991             smb_ReleaseDirSearch(dsp);
4992             return 0;
4993         }
4994
4995         cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4996         cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4997
4998         code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4999                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5000                         userp, tidPathp, &req, &scp);
5001         cm_FreeSpace(spacep);
5002
5003         if (code == 0) {
5004 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
5005             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5006                 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
5007                 cm_ReleaseSCache(scp);
5008                 cm_ReleaseUser(userp);
5009                 if ( WANTS_DFS_PATHNAMES(p) || pnc )
5010                     code = CM_ERROR_PATH_NOT_COVERED;
5011                 else
5012                     code = CM_ERROR_BADSHARENAME;
5013                 smb_SendTran2Error(vcp, p, opx, code);
5014                 smb_FreeTran2Packet(outp);
5015                 lock_ReleaseMutex(&dsp->mx);
5016                 smb_DeleteDirSearch(dsp);
5017                 smb_ReleaseDirSearch(dsp);
5018                 return 0;
5019             }
5020 #endif /* DFS_SUPPORT */
5021             dsp->scp = scp;
5022             osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
5023             /* we need one hold for the entry we just stored into,
5024              * and one for our own processing.  When we're done
5025              * with this function, we'll drop the one for our own
5026              * processing.  We held it once from the namei call,
5027              * and so we do another hold now.
5028              */
5029             cm_HoldSCache(scp);
5030             dsp->flags |= SMB_DIRSEARCH_BULKST;
5031         } 
5032     }
5033     lock_ReleaseMutex(&dsp->mx);
5034     if (code) {
5035         cm_ReleaseUser(userp);
5036         smb_FreeTran2Packet(outp);
5037         smb_DeleteDirSearch(dsp);
5038         smb_ReleaseDirSearch(dsp);
5039         return code;
5040     }
5041
5042     /* get the directory size */
5043     lock_ObtainWrite(&scp->rw);
5044     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5045                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5046     if (code) {
5047         lock_ReleaseWrite(&scp->rw);
5048         cm_ReleaseSCache(scp);
5049         cm_ReleaseUser(userp);
5050         smb_FreeTran2Packet(outp);
5051         smb_DeleteDirSearch(dsp);
5052         smb_ReleaseDirSearch(dsp);
5053         return code;
5054     }
5055
5056     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5057
5058   startsearch:
5059     dirLength = scp->length;
5060     bufferp = NULL;
5061     bufferOffset.LowPart = bufferOffset.HighPart = 0;
5062     curOffset.HighPart = 0;
5063     curOffset.LowPart = nextCookie;
5064     origOp = outp->datap;
5065
5066     foundInexact = 0;
5067     code = 0;
5068     returnedNames = 0;
5069     bytesInBuffer = 0;
5070     while (1) {
5071         normchar_t normName[MAX_PATH]; /* Normalized name */
5072         clientchar_t cfileName[MAX_PATH]; /* Non-normalized name */
5073
5074         op = origOp;
5075         if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5076             /* skip over resume key */
5077             op += 4;
5078
5079         fp = (smb_tran2Find_t *) op;
5080
5081         /* make sure that curOffset.LowPart doesn't point to the first
5082          * 32 bytes in the 2nd through last dir page, and that it doesn't
5083          * point at the first 13 32-byte chunks in the first dir page,
5084          * since those are dir and page headers, and don't contain useful
5085          * information.
5086          */
5087         temp = curOffset.LowPart & (2048-1);
5088         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5089             /* we're in the first page */
5090             if (temp < 13*32) temp = 13*32;
5091         }
5092         else {
5093             /* we're in a later dir page */
5094             if (temp < 32) temp = 32;
5095         }
5096                 
5097         /* make sure the low order 5 bits are zero */
5098         temp &= ~(32-1);
5099                 
5100         /* now put temp bits back ito curOffset.LowPart */
5101         curOffset.LowPart &= ~(2048-1);
5102         curOffset.LowPart |= temp;
5103
5104         /* check if we've passed the dir's EOF */
5105         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
5106             osi_Log0(smb_logp, "T2 search dir passed eof");
5107             eos = 1;
5108             break;
5109         }
5110
5111         /* check if we've returned all the names that will fit in the
5112          * response packet; we check return count as well as the number
5113          * of bytes requested.  We check the # of bytes after we find
5114          * the dir entry, since we'll need to check its size.
5115          */
5116         if (returnedNames >= maxCount) {
5117             osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
5118                       returnedNames, maxCount);
5119             break;
5120         }
5121
5122         /* when we have obtained as many entries as can be processed in 
5123          * a single Bulk Status call to the file server, apply the dir listing
5124          * patches.
5125          */
5126         if (returnedNames > 0 && returnedNames % AFSCBMAX == 0) {
5127             lock_ReleaseWrite(&scp->rw);
5128             code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5129                                                dsp->relPath, infoLevel, userp, &req);
5130             lock_ObtainWrite(&scp->rw);
5131         }
5132         /* Then check to see if we have time left to process more entries */
5133         if (GetTickCount() - req.startTime > (RDRtimeout - 15) * 1000) {
5134             osi_Log0(smb_logp, "T2 search dir RDRtimeout exceeded");
5135             break;
5136         }
5137
5138         /* see if we can use the bufferp we have now; compute in which
5139          * page the current offset would be, and check whether that's
5140          * the offset of the buffer we have.  If not, get the buffer.
5141          */
5142         thyper.HighPart = curOffset.HighPart;
5143         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5144         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5145             /* wrong buffer */
5146             if (bufferp) {
5147                 buf_Release(bufferp);
5148                 bufferp = NULL;
5149             }       
5150             lock_ReleaseWrite(&scp->rw);
5151             code = buf_Get(scp, &thyper, &bufferp);
5152             lock_ObtainWrite(&scp->rw);
5153             if (code) {
5154                 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
5155                 break;
5156             }
5157
5158             bufferOffset = thyper;
5159
5160             /* now get the data in the cache */
5161             while (1) {
5162                 code = cm_SyncOp(scp, bufferp, userp, &req,
5163                                  PRSFS_LOOKUP,
5164                                  CM_SCACHESYNC_NEEDCALLBACK
5165                                  | CM_SCACHESYNC_READ);
5166                 if (code) {
5167                     osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5168                     break;
5169                 }
5170                        
5171                 if (cm_HaveBuffer(scp, bufferp, 0)) {
5172                     osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5173                     cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5174                     break;
5175                 }
5176
5177                 /* otherwise, load the buffer and try again */
5178                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5179                                     &req);
5180                 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5181                 if (code) {
5182                     osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d", 
5183                               scp, bufferp, code);
5184                     break;
5185                 }
5186             }
5187             if (code) {
5188                 buf_Release(bufferp);
5189                 bufferp = NULL;
5190                 break;
5191             }
5192         }       /* if (wrong buffer) ... */
5193                 
5194         /* now we have the buffer containing the entry we're interested
5195          * in; copy it out if it represents a non-deleted entry.
5196          */
5197         entryInDir = curOffset.LowPart & (2048-1);
5198         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5199
5200         /* page header will help tell us which entries are free.  Page
5201          * header can change more often than once per buffer, since
5202          * AFS 3 dir page size may be less than (but not more than)
5203          * a buffer package buffer.
5204          */
5205         /* only look intra-buffer */
5206         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5207         temp &= ~(2048 - 1);    /* turn off intra-page bits */
5208         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5209
5210         /* now determine which entry we're looking at in the page.
5211          * If it is free (there's a free bitmap at the start of the
5212          * dir), we should skip these 32 bytes.
5213          */
5214         slotInPage = (entryInDir & 0x7e0) >> 5;
5215         if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5216             (1 << (slotInPage & 0x7)))) {
5217             /* this entry is free */
5218             numDirChunks = 1;   /* only skip this guy */
5219             goto nextEntry;
5220         }
5221
5222         tp = bufferp->datap + entryInBuffer;
5223         dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
5224
5225         /* while we're here, compute the next entry's location, too,
5226          * since we'll need it when writing out the cookie into the dir
5227          * listing stream.
5228          *
5229          * XXXX Probably should do more sanity checking.
5230          */
5231         numDirChunks = cm_NameEntries(dep->name, &onbytes);
5232                 
5233         /* compute offset of cookie representing next entry */
5234         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5235
5236         if (dep->fid.vnode == 0) 
5237             goto nextEntry;             /* This entry is not in use */
5238
5239         cm_FsStringToClientString(dep->name, -1, cfileName, lengthof(cfileName));
5240         cm_ClientStringToNormString(cfileName, -1, normName, lengthof(normName));
5241
5242         /* Need 8.3 name? */
5243         NeedShortName = 0;
5244         if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO && 
5245             !cm_Is8Dot3(cfileName)) {
5246             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5247             NeedShortName = 1;
5248         }
5249
5250         osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %S (%S)",
5251                  dep->fid.vnode, dep->fid.unique, 
5252                  osi_LogSaveClientString(smb_logp, cfileName),
5253                  NeedShortName ? osi_LogSaveClientString(smb_logp, shortName) : _C(""));
5254
5255         /* When matching, we are using doing a case fold if we have a wildcard mask.
5256          * If we get a non-wildcard match, it's a lookup for a specific file. 
5257          */
5258         if (cm_MatchMask(normName, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5259             (NeedShortName && cm_MatchMask(shortName, maskp, CM_FLAG_CASEFOLD))) 
5260         {
5261             /* Eliminate entries that don't match requested attributes */
5262             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
5263                 smb_IsDotFile(cfileName)) {
5264                 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5265                 goto nextEntry; /* no hidden files */
5266             }
5267         
5268             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
5269             {
5270                 /* We have already done the cm_TryBulkStat above */
5271                 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume,
5272                           ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5273                 fileType = cm_FindFileType(&fid);
5274                 /* osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5275                  * "has filetype %d", dep->name, fileType);
5276                  */
5277                 if ( fileType == CM_SCACHETYPE_DIRECTORY ||
5278                      fileType == CM_SCACHETYPE_MOUNTPOINT ||
5279                      fileType == CM_SCACHETYPE_DFSLINK ||
5280                      fileType == CM_SCACHETYPE_INVALID)
5281                     osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5282                 goto nextEntry;
5283             }
5284
5285             /* finally check if this name will fit */
5286             onbytes = 0;
5287             smb_UnparseString(opx, NULL, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5288             orbytes = ohbytes + onbytes;
5289
5290             /* now, we round up the record to a 4 byte alignment,
5291              * and we make sure that we have enough room here for
5292              * even the aligned version (so we don't have to worry
5293              * about an overflow when we pad things out below).
5294              * That's the reason for the alignment arithmetic below.
5295              */
5296             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5297                 align = (4 - (orbytes & 3)) & 3;
5298             else
5299                 align = 0;
5300
5301             if (orbytes + bytesInBuffer + align > maxReturnData) {
5302                 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5303                          maxReturnData);
5304                 break;      
5305             }       
5306
5307             /* this is one of the entries to use: it is not deleted
5308              * and it matches the star pattern we're looking for.
5309              * Put out the name, preceded by its length.
5310              */
5311             /* First zero everything else */
5312             memset(origOp, 0, orbytes);
5313
5314             onbytes = 0;
5315             smb_UnparseString(opx, origOp + ohbytes, cfileName, &onbytes, SMB_STRF_ANSIPATH|SMB_STRF_IGNORENUL);
5316
5317             switch (infoLevel) {
5318             case SMB_INFO_STANDARD:
5319                 fp->u.FstandardInfo.fileNameLength = onbytes;
5320                 attrp = &fp->u.FstandardInfo.fileAttrs;
5321                 break;
5322
5323             case SMB_INFO_QUERY_EA_SIZE:
5324                 fp->u.FeaSizeInfo.fileNameLength = onbytes;
5325                 attrp = &fp->u.FeaSizeInfo.fileAttrs;
5326                 fp->u.FeaSizeInfo.eaSize = 0;
5327                 break;
5328
5329             case SMB_INFO_QUERY_EAS_FROM_LIST:
5330                 fp->u.FeasFromListInfo.fileNameLength = onbytes;
5331                 attrp = &fp->u.FeasFromListInfo.fileAttrs;
5332                 fp->u.FeasFromListInfo.eaSize = 0;
5333                 break;
5334
5335             case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
5336                 if (NeedShortName) {
5337 #ifdef SMB_UNICODE
5338                     int nchars;
5339
5340                     nchars = cm_ClientStringToUtf16(shortName, cm_ClientStrLen(shortName),
5341                                                     fp->u.FfileBothDirectoryInfo.shortName,
5342                                                     sizeof(fp->u.FfileBothDirectoryInfo.shortName)/sizeof(wchar_t));
5343                     if (nchars > 0)
5344                         fp->u.FfileBothDirectoryInfo.shortNameLength = nchars*sizeof(wchar_t);
5345                     else
5346                         fp->u.FfileBothDirectoryInfo.shortNameLength = 0;
5347                     fp->u.FfileBothDirectoryInfo.reserved = 0;
5348 #else
5349                     cm_ClientStrCpy(fp->u.FfileBothDirectoryInfo.shortName,
5350                                     lengthof(fp->u.FfileBothDirectoryInfo.shortName),
5351                                     shortName);
5352                     fp->u.FfileBothDirectoryInfo.shortNameLength = cm_ClientStrLen(shortName);
5353 #endif
5354                 }
5355                 /* Fallthrough */
5356
5357             case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
5358                 fp->u.FfileFullDirectoryInfo.eaSize = 0;
5359                 /* Fallthrough */
5360
5361             case SMB_FIND_FILE_DIRECTORY_INFO:
5362                 fp->u.FfileDirectoryInfo.nextEntryOffset = orbytes + align;
5363                 fp->u.FfileDirectoryInfo.fileIndex = nextEntryCookie;
5364                 attrp = &fp->u.FfileDirectoryInfo.fileAttrs;
5365                 fp->u.FfileDirectoryInfo.fileNameLength = onbytes;
5366                 break;
5367
5368             case SMB_FIND_FILE_NAMES_INFO:
5369                 fp->u.FfileNamesInfo.nextEntryOffset = orbytes + align;
5370                 fp->u.FfileNamesInfo.fileIndex = nextEntryCookie;
5371                 fp->u.FfileNamesInfo.fileNameLength = onbytes;
5372                 attrp = NULL;
5373                 break;
5374
5375             default:
5376                 /* we shouldn't hit this case */
5377                 osi_assertx(FALSE, "Unknown query type");
5378             }
5379
5380             /* now, adjust the # of entries copied */
5381             returnedNames++;
5382
5383             /* now we emit the attribute.  This is tricky, since
5384              * we need to really stat the file to find out what
5385              * type of entry we've got.  Right now, we're copying
5386              * out data from a buffer, while holding the scp
5387              * locked, so it isn't really convenient to stat
5388              * something now.  We'll put in a place holder
5389              * now, and make a second pass before returning this
5390              * to get the real attributes.  So, we just skip the
5391              * data for now, and adjust it later.  We allocate a
5392              * patch record to make it easy to find this point
5393              * later.  The replay will happen at a time when it is
5394              * safe to unlock the directory.
5395              */
5396             if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5397                 osi_assert(attrp != NULL);
5398                 curPatchp = malloc(sizeof(*curPatchp));
5399                 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5400                 curPatchp->dptr = attrp;
5401
5402                 if (smb_hideDotFiles && smb_IsDotFile(cfileName)) {
5403                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5404                 } else {
5405                     curPatchp->flags = 0;
5406                 }
5407
5408                 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5409
5410                 /* temp */
5411                 curPatchp->dep = dep;
5412             }   
5413
5414             if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5415                 /* put out resume key */
5416                 *((u_long *)origOp) = nextEntryCookie;
5417
5418             /* Adjust byte ptr and count */
5419             origOp += orbytes;  /* skip entire record */
5420             bytesInBuffer += orbytes;
5421
5422             /* and pad the record out */
5423             while (align-- > 0) {
5424                 *origOp++ = 0;
5425                 bytesInBuffer++;
5426             }
5427         }       /* if we're including this name */
5428         else if (!starPattern &&
5429                  !foundInexact &&
5430                  cm_MatchMask(normName, maskp, CM_FLAG_CASEFOLD)) {
5431             /* We were looking for exact matches, but here's an inexact one*/
5432             foundInexact = 1;
5433         }
5434
5435       nextEntry:
5436         /* and adjust curOffset to be where the new cookie is */
5437         thyper.HighPart = 0;
5438         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5439         curOffset = LargeIntegerAdd(thyper, curOffset);
5440     } /* while copying data for dir listing */
5441
5442     /* If we didn't get a star pattern, we did an exact match during the first pass. 
5443      * If there were no exact matches found, we fail over to inexact matches by
5444      * marking the query as a star pattern (matches all case permutations), and
5445      * re-running the query. 
5446      */
5447     if (returnedNames == 0 && !starPattern && foundInexact) {
5448         osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5449         starPattern = 1;
5450         goto startsearch;
5451     }
5452
5453     /* release the mutex */
5454     lock_ReleaseWrite(&scp->rw);
5455     if (bufferp) {
5456         buf_Release(bufferp);
5457         bufferp = NULL;
5458     }
5459
5460     /* 
5461      * Finally, process whatever entries we have left.
5462      */
5463     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, dsp->tidPath,
5464                                       dsp->relPath, infoLevel, userp, &req);
5465
5466     /* now put out the final parameters */
5467     if (returnedNames == 0) 
5468         eos = 1;
5469     if (p->opcode == 1) {
5470         /* find first */
5471         outp->parmsp[0] = (unsigned short) dsp->cookie;
5472         outp->parmsp[1] = returnedNames;
5473         outp->parmsp[2] = eos;
5474         outp->parmsp[3] = 0;            /* nothing wrong with EAS */
5475         outp->parmsp[4] = 0;    
5476         /* don't need last name to continue
5477          * search, cookie is enough.  Normally,
5478          * this is the offset of the file name
5479          * of the last entry returned.
5480          */
5481         outp->totalParms = 10;  /* in bytes */
5482     }
5483     else {
5484         /* find next */
5485         outp->parmsp[0] = returnedNames;
5486         outp->parmsp[1] = eos;
5487         outp->parmsp[2] = 0;    /* EAS error */
5488         outp->parmsp[3] = 0;    /* last name, as above */
5489         outp->totalParms = 8;   /* in bytes */
5490     }   
5491
5492     /* return # of bytes in the buffer */
5493     outp->totalData = bytesInBuffer;
5494
5495     /* Return error code if unsuccessful on first request */
5496     if (code == 0 && p->opcode == 1 && returnedNames == 0)
5497         code = CM_ERROR_NOSUCHFILE;
5498
5499     osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5500              p->opcode, dsp->cookie, returnedNames, code);
5501
5502     /* if we're supposed to close the search after this request, or if
5503      * we're supposed to close the search if we're done, and we're done,
5504      * or if something went wrong, close the search.
5505      */
5506     if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) || 
5507         (returnedNames == 0) ||
5508         ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) || 
5509         code != 0)
5510         smb_DeleteDirSearch(dsp);
5511
5512     if (code)
5513         smb_SendTran2Error(vcp, p, opx, code);
5514     else
5515         smb_SendTran2Packet(vcp, outp, opx);
5516
5517     smb_FreeTran2Packet(outp);
5518     smb_ReleaseDirSearch(dsp);
5519     cm_ReleaseSCache(scp);
5520     cm_ReleaseUser(userp);
5521     return 0;
5522 }
5523
5524 /* SMB_COM_FIND_CLOSE2 */
5525 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5526 {
5527     int dirHandle;
5528     smb_dirSearch_t *dsp;
5529
5530     dirHandle = smb_GetSMBParm(inp, 0);
5531         
5532     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5533
5534     dsp = smb_FindDirSearch(dirHandle);
5535         
5536     if (!dsp)
5537         return CM_ERROR_BADFD;
5538         
5539     /* otherwise, we have an FD to destroy */
5540     smb_DeleteDirSearch(dsp);
5541     smb_ReleaseDirSearch(dsp);
5542         
5543     /* and return results */
5544     smb_SetSMBDataLength(outp, 0);
5545
5546     return 0;
5547 }
5548
5549
5550 /* SMB_COM_FIND_NOTIFY_CLOSE */
5551 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5552 {
5553     smb_SetSMBDataLength(outp, 0);
5554     return 0;
5555 }
5556
5557 /* SMB_COM_OPEN_ANDX */
5558 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5559 {
5560     clientchar_t *pathp;
5561     long code = 0;
5562     cm_space_t *spacep;
5563     int excl;
5564     cm_user_t *userp;
5565     cm_scache_t *dscp;          /* dir we're dealing with */
5566     cm_scache_t *scp;           /* file we're creating */
5567     cm_attr_t setAttr;
5568     int initialModeBits;
5569     smb_fid_t *fidp;
5570     int attributes;
5571     clientchar_t *lastNamep;
5572     unsigned long dosTime;
5573     int openFun;
5574     int trunc;
5575     int openMode;
5576     int extraInfo;
5577     int openAction;
5578     int parmSlot;                       /* which parm we're dealing with */
5579     clientchar_t *tidPathp;
5580     cm_req_t req;
5581     int created = 0;
5582
5583     smb_InitReq(&req);
5584
5585     scp = NULL;
5586         
5587     extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5588     openFun = smb_GetSMBParm(inp, 8); /* open function */
5589     excl = ((openFun & 3) == 0);
5590     trunc = ((openFun & 3) == 2); /* truncate it */
5591     openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5592     openAction = 0;             /* tracks what we did */
5593
5594     attributes = smb_GetSMBParm(inp, 5);
5595     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5596
5597                                 /* compute initial mode bits based on read-only flag in attributes */
5598     initialModeBits = 0666;
5599     if (attributes & SMB_ATTR_READONLY) 
5600         initialModeBits &= ~0222;
5601         
5602     pathp = smb_ParseASCIIBlock(inp, smb_GetSMBData(inp, NULL), NULL,
5603                                 SMB_STRF_ANSIPATH);
5604
5605     spacep = inp->spacep;
5606     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5607
5608     if (lastNamep && 
5609         (cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
5610          cm_ClientStrCmpIA(lastNamep,  _C("\\srvsvc")) == 0 ||
5611          cm_ClientStrCmpIA(lastNamep,  _C("\\wkssvc")) == 0 ||
5612          cm_ClientStrCmpIA(lastNamep,  _C("ipc$")) == 0)) {
5613         /* special case magic file name for receiving IOCTL requests
5614          * (since IOCTL calls themselves aren't getting through).
5615          */
5616 #ifdef NOTSERVICE
5617         osi_Log0(smb_logp, "IOCTL Open");
5618 #endif
5619
5620         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5621         smb_SetupIoctlFid(fidp, spacep);
5622
5623         /* set inp->fid so that later read calls in same msg can find fid */
5624         inp->fid = fidp->fid;
5625         
5626         /* copy out remainder of the parms */
5627         parmSlot = 2;
5628         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5629         if (extraInfo) {
5630             smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5631             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* mod time */
5632             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5633             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* len */
5634             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5635             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5636             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5637             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5638         }   
5639         /* and the final "always present" stuff */
5640         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5641         /* next write out the "unique" ID */
5642         smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5643         smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5644         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5645         smb_SetSMBDataLength(outp, 0);
5646
5647         /* and clean up fid reference */
5648         smb_ReleaseFID(fidp);
5649         return 0;
5650     }
5651
5652 #ifdef DEBUG_VERBOSE
5653     {
5654         char *hexp, *asciip;
5655         asciip = (lastNamep ? lastNamep : pathp );
5656         hexp = osi_HexifyString(asciip);
5657         DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5658         free(hexp);
5659     }
5660 #endif
5661     userp = smb_GetUserFromVCP(vcp, inp);
5662
5663     dscp = NULL;
5664     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5665     if (code) {
5666         cm_ReleaseUser(userp);
5667         return CM_ERROR_NOSUCHPATH;
5668     }
5669     code = cm_NameI(cm_data.rootSCachep, pathp,
5670                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5671                     userp, tidPathp, &req, &scp);
5672
5673 #ifdef DFS_SUPPORT
5674     if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5675         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5676         cm_ReleaseSCache(scp);
5677         cm_ReleaseUser(userp);
5678         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5679             return CM_ERROR_PATH_NOT_COVERED;
5680         else
5681             return CM_ERROR_BADSHARENAME;
5682     }
5683 #endif /* DFS_SUPPORT */
5684
5685     if (code != 0) {
5686         code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
5687                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5688                         userp, tidPathp, &req, &dscp);
5689         if (code) {
5690             cm_ReleaseUser(userp);
5691             return code;
5692         }
5693
5694 #ifdef DFS_SUPPORT
5695         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5696             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5697                                                       spacep->wdata);
5698             cm_ReleaseSCache(dscp);
5699             cm_ReleaseUser(userp);
5700             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5701                 return CM_ERROR_PATH_NOT_COVERED;
5702             else
5703                 return CM_ERROR_BADSHARENAME;
5704         }
5705 #endif /* DFS_SUPPORT */
5706         /* otherwise, scp points to the parent directory.  Do a lookup,
5707          * and truncate the file if we find it, otherwise we create the
5708          * file.
5709          */
5710         if (!lastNamep) 
5711             lastNamep = pathp;
5712         else 
5713             lastNamep++;
5714         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5715                           &req, &scp);
5716         if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5717             cm_ReleaseSCache(dscp);
5718             cm_ReleaseUser(userp);
5719             return code;
5720         }
5721     }
5722         
5723     /* if we get here, if code is 0, the file exists and is represented by
5724      * scp.  Otherwise, we have to create it.  The dir may be represented
5725      * by dscp, or we may have found the file directly.  If code is non-zero,
5726      * scp is NULL.
5727      */
5728     if (code == 0) {
5729         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5730         if (code) {
5731             if (dscp) cm_ReleaseSCache(dscp);
5732             cm_ReleaseSCache(scp);
5733             cm_ReleaseUser(userp);
5734             return code;
5735         }
5736
5737         if (excl) {
5738             /* oops, file shouldn't be there */
5739             if (dscp) 
5740                 cm_ReleaseSCache(dscp);
5741             cm_ReleaseSCache(scp);
5742             cm_ReleaseUser(userp);
5743             return CM_ERROR_EXISTS;
5744         }
5745
5746         if (trunc) {
5747             setAttr.mask = CM_ATTRMASK_LENGTH;
5748             setAttr.length.LowPart = 0;
5749             setAttr.length.HighPart = 0;
5750             code = cm_SetAttr(scp, &setAttr, userp, &req);
5751             openAction = 3;     /* truncated existing file */
5752         }
5753         else openAction = 1;    /* found existing file */
5754     }
5755     else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5756         /* don't create if not found */
5757         if (dscp) cm_ReleaseSCache(dscp);
5758         cm_ReleaseUser(userp);
5759         return CM_ERROR_NOSUCHFILE;
5760     }
5761     else {
5762         osi_assertx(dscp != NULL, "null cm_scache_t");
5763         osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %S",
5764                  osi_LogSaveClientString(smb_logp, lastNamep));
5765         openAction = 2; /* created file */
5766         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5767         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5768         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5769                          &req);
5770         if (code == 0) {
5771             created = 1;
5772             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5773                 smb_NotifyChange(FILE_ACTION_ADDED,
5774                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5775                                  dscp, lastNamep, NULL, TRUE);
5776         } else if (!excl && code == CM_ERROR_EXISTS) {
5777             /* not an exclusive create, and someone else tried
5778              * creating it already, then we open it anyway.  We
5779              * don't bother retrying after this, since if this next
5780              * fails, that means that the file was deleted after we
5781              * started this call.
5782              */
5783             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5784                              userp, &req, &scp);
5785             if (code == 0) {
5786                 if (trunc) {
5787                     setAttr.mask = CM_ATTRMASK_LENGTH;
5788                     setAttr.length.LowPart = 0;
5789                     setAttr.length.HighPart = 0;
5790                     code = cm_SetAttr(scp, &setAttr, userp, &req);
5791                 }   
5792             }   /* lookup succeeded */
5793         }
5794     }
5795         
5796     /* we don't need this any longer */
5797     if (dscp) 
5798         cm_ReleaseSCache(dscp);
5799
5800     if (code) {
5801         /* something went wrong creating or truncating the file */
5802         if (scp) 
5803             cm_ReleaseSCache(scp);
5804         cm_ReleaseUser(userp);
5805         return code;
5806     }
5807         
5808     /* make sure we're about to open a file */
5809     if (scp->fileType != CM_SCACHETYPE_FILE) {
5810         cm_ReleaseSCache(scp);
5811         cm_ReleaseUser(userp);
5812         return CM_ERROR_ISDIR;
5813     }
5814
5815     /* now all we have to do is open the file itself */
5816     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5817     osi_assertx(fidp, "null smb_fid_t");
5818         
5819     cm_HoldUser(userp);
5820     lock_ObtainMutex(&fidp->mx);
5821     /* save a pointer to the vnode */
5822     fidp->scp = scp;
5823     lock_ObtainWrite(&scp->rw);
5824     scp->flags |= CM_SCACHEFLAG_SMB_FID;
5825     lock_ReleaseWrite(&scp->rw);
5826     osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5827     /* also the user */
5828     fidp->userp = userp;
5829         
5830     /* compute open mode */
5831     if (openMode != 1) 
5832         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5833     if (openMode == 1 || openMode == 2)
5834         fidp->flags |= SMB_FID_OPENWRITE;
5835
5836     /* remember if the file was newly created */
5837     if (created)
5838         fidp->flags |= SMB_FID_CREATED;
5839
5840     lock_ReleaseMutex(&fidp->mx);
5841     smb_ReleaseFID(fidp);
5842         
5843     cm_Open(scp, 0, userp);
5844
5845     /* set inp->fid so that later read calls in same msg can find fid */
5846     inp->fid = fidp->fid;
5847         
5848     /* copy out remainder of the parms */
5849     parmSlot = 2;
5850     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5851     lock_ObtainRead(&scp->rw);
5852     if (extraInfo) {
5853         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5854         smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5855         smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5856         smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5857         smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5858         smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5859         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5860         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5861         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5862     }
5863     /* and the final "always present" stuff */
5864     smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5865     /* next write out the "unique" ID */
5866     smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5867     smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5868     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5869     lock_ReleaseRead(&scp->rw);
5870     smb_SetSMBDataLength(outp, 0);
5871
5872     osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5873
5874     cm_ReleaseUser(userp);
5875     /* leave scp held since we put it in fidp->scp */
5876     return 0;
5877 }       
5878
5879 static void smb_GetLockParams(unsigned char LockType, 
5880                               char ** buf, 
5881                               unsigned int * ppid, 
5882                               LARGE_INTEGER * pOffset, 
5883                               LARGE_INTEGER * pLength)
5884 {
5885     if (LockType & LOCKING_ANDX_LARGE_FILES) {
5886         /* Large Files */
5887         *ppid = *((USHORT *) *buf);
5888         pOffset->HighPart = *((LONG *)(*buf + 4));
5889         pOffset->LowPart = *((DWORD *)(*buf + 8));
5890         pLength->HighPart = *((LONG *)(*buf + 12));
5891         pLength->LowPart = *((DWORD *)(*buf + 16));
5892         *buf += 20;
5893     }
5894     else {
5895         /* Not Large Files */
5896         *ppid = *((USHORT *) *buf);
5897         pOffset->HighPart = 0;
5898         pOffset->LowPart = *((DWORD *)(*buf + 2));
5899         pLength->HighPart = 0;
5900         pLength->LowPart = *((DWORD *)(*buf + 6));
5901         *buf += 10;
5902     }
5903 }
5904
5905 /* SMB_COM_LOCKING_ANDX */
5906 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5907 {
5908     cm_req_t req;
5909     cm_user_t *userp;
5910     unsigned short fid;
5911     smb_fid_t *fidp;
5912     cm_scache_t *scp;
5913     unsigned char LockType;
5914     unsigned short NumberOfUnlocks, NumberOfLocks;
5915     afs_uint32 Timeout;
5916     char *op;
5917     char *op_locks;
5918     LARGE_INTEGER LOffset, LLength;
5919     smb_waitingLockRequest_t *wlRequest = NULL;
5920     cm_file_lock_t *lockp;
5921     long code = 0;
5922     int i;
5923     cm_key_t key;
5924     unsigned int pid;
5925
5926     smb_InitReq(&req);
5927
5928     fid = smb_GetSMBParm(inp, 2);
5929     fid = smb_ChainFID(fid, inp);
5930
5931     fidp = smb_FindFID(vcp, fid, 0);
5932     if (!fidp)
5933         return CM_ERROR_BADFD;
5934     
5935     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5936         smb_CloseFID(vcp, fidp, NULL, 0);
5937         smb_ReleaseFID(fidp);
5938         return CM_ERROR_NOSUCHFILE;
5939     }
5940
5941     lock_ObtainMutex(&fidp->mx);
5942     if (fidp->flags & SMB_FID_IOCTL) {
5943         osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5944         lock_ReleaseMutex(&fidp->mx);
5945         smb_ReleaseFID(fidp);
5946         return CM_ERROR_BADFD;
5947     }
5948     scp = fidp->scp;
5949     osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5950     cm_HoldSCache(scp);
5951     lock_ReleaseMutex(&fidp->mx);
5952
5953     /* set inp->fid so that later read calls in same msg can find fid */
5954     inp->fid = fid;
5955
5956     userp = smb_GetUserFromVCP(vcp, inp);
5957
5958
5959     lock_ObtainWrite(&scp->rw);
5960     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5961                       CM_SCACHESYNC_NEEDCALLBACK
5962                          | CM_SCACHESYNC_GETSTATUS
5963                          | CM_SCACHESYNC_LOCK);
5964     if (code) {
5965         osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5966         goto doneSync;
5967     }
5968
5969     LockType = smb_GetSMBParm(inp, 3) & 0xff;
5970     Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5971     NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5972     NumberOfLocks = smb_GetSMBParm(inp, 7);
5973
5974     if (!(fidp->flags & SMB_FID_OPENWRITE) &&
5975         !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
5976         /* somebody wants exclusive locks on a file that they only
5977            opened for reading.  We downgrade this to a shared lock. */
5978         osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
5979         LockType |= LOCKING_ANDX_SHARED_LOCK;
5980     }
5981
5982     if (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE) {
5983         /* AFS does not support atomic changes of lock types from read or write and vice-versa */
5984         osi_Log0(smb_logp, "smb_ReceiveV3Locking received unsupported request [LOCKING_ANDX_CHANGE_LOCKTYPE]"); 
5985         code = CM_ERROR_BADOP;
5986         goto done;
5987
5988     }
5989
5990     op = smb_GetSMBData(inp, NULL);
5991
5992     if (LockType & LOCKING_ANDX_CANCEL_LOCK) {
5993         /* Cancel outstanding lock requests */
5994         smb_waitingLock_t * wl;
5995
5996         for (i=0; i<NumberOfLocks; i++) {
5997             smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5998
5999             key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6000
6001             lock_ObtainWrite(&smb_globalLock);
6002             for (wlRequest = smb_allWaitingLocks; wlRequest; wlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q))
6003             {
6004                 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
6005                     if (wl->key == key && LargeIntegerEqualTo(wl->LOffset, LOffset) && 
6006                         LargeIntegerEqualTo(wl->LLength, LLength)) {
6007                         wl->state = SMB_WAITINGLOCKSTATE_CANCELLED;
6008                         goto found_lock_request;
6009                     }
6010                 }
6011             }
6012           found_lock_request:
6013             lock_ReleaseWrite(&smb_globalLock);
6014         }
6015         code = 0;
6016         smb_SetSMBDataLength(outp, 0);
6017         goto done;
6018     }
6019
6020
6021     for (i=0; i<NumberOfUnlocks; i++) {
6022         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6023
6024         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6025
6026         code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
6027
6028         if (code) 
6029             goto done;
6030     }
6031
6032     op_locks = op;
6033
6034     for (i=0; i<NumberOfLocks; i++) {
6035         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
6036
6037         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6038
6039         code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
6040                         userp, &req, &lockp);
6041
6042         if (code == CM_ERROR_NOACCESS && LockType == LockWrite && 
6043             (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
6044         {
6045             code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
6046                             userp, &req, &lockp);
6047         }
6048
6049         if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
6050             smb_waitingLock_t * wLock;
6051
6052             /* Put on waiting list */
6053             if(wlRequest == NULL) {
6054                 int j;
6055                 char * opt;
6056                 cm_key_t tkey;
6057                 LARGE_INTEGER tOffset, tLength;
6058
6059                 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
6060
6061                 osi_assertx(wlRequest != NULL, "null wlRequest");
6062
6063                 wlRequest->vcp = vcp;
6064                 smb_HoldVC(vcp);
6065                 wlRequest->scp = scp;
6066                 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
6067                 cm_HoldSCache(scp);
6068                 wlRequest->inp = smb_CopyPacket(inp);
6069                 wlRequest->outp = smb_CopyPacket(outp);
6070                 wlRequest->lockType = LockType;
6071                 wlRequest->msTimeout = Timeout;
6072                 wlRequest->start_t = osi_Time();
6073                 wlRequest->locks = NULL;
6074
6075                 /* The waiting lock request needs to have enough
6076                    information to undo all the locks in the request.
6077                    We do the following to store info about locks that
6078                    have already been granted.  Sure, we can get most
6079                    of the info from the packet, but the packet doesn't
6080                    hold the result of cm_Lock call.  In practice we
6081                    only receive packets with one or two locks, so we
6082                    are only wasting a few bytes here and there and
6083                    only for a limited period of time until the waiting
6084                    lock times out or is freed. */
6085
6086                 for(opt = op_locks, j=i; j > 0; j--) {
6087                     smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
6088
6089                     tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
6090
6091                     wLock = malloc(sizeof(smb_waitingLock_t));
6092
6093                     osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6094
6095                     wLock->key = tkey;
6096                     wLock->LOffset = tOffset;
6097                     wLock->LLength = tLength;
6098                     wLock->lockp = NULL;
6099                     wLock->state = SMB_WAITINGLOCKSTATE_DONE;
6100                     osi_QAdd((osi_queue_t **) &wlRequest->locks,
6101                              &wLock->q);
6102                 }
6103             }
6104
6105             wLock = malloc(sizeof(smb_waitingLock_t));
6106
6107             osi_assertx(wLock != NULL, "null smb_waitingLock_t");
6108
6109             wLock->key = key;
6110             wLock->LOffset = LOffset;
6111             wLock->LLength = LLength;
6112             wLock->lockp = lockp;
6113             wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
6114             osi_QAdd((osi_queue_t **) &wlRequest->locks,
6115                      &wLock->q);
6116
6117             osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
6118                      wLock);
6119
6120             code = 0;
6121             continue;
6122         }
6123
6124         if (code) {
6125             osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
6126             break;
6127         }
6128     }
6129
6130     if (code) {
6131
6132         /* Since something went wrong with the lock number i, we now
6133            have to go ahead and release any locks acquired before the
6134            failure.  All locks before lock number i (of which there
6135            are i of them) have either been successful or are waiting.
6136            Either case requires calling cm_Unlock(). */
6137
6138         /* And purge the waiting lock */
6139         if(wlRequest != NULL) {
6140             smb_waitingLock_t * wl;
6141             smb_waitingLock_t * wlNext;
6142             long ul_code;
6143
6144             for(wl = wlRequest->locks; wl; wl = wlNext) {
6145
6146                 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
6147
6148                 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
6149                 
6150                 if(ul_code != 0) {
6151                     osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
6152                 } else {
6153                     osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
6154                 }
6155
6156                 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
6157                 free(wl);
6158
6159             }
6160
6161             smb_ReleaseVC(wlRequest->vcp);
6162             cm_ReleaseSCache(wlRequest->scp);
6163             smb_FreePacket(wlRequest->inp);
6164             smb_FreePacket(wlRequest->outp);
6165
6166             free(wlRequest);
6167
6168             wlRequest = NULL;
6169         }
6170
6171     } else {
6172
6173         if (wlRequest != NULL) {
6174
6175             lock_ObtainWrite(&smb_globalLock);
6176             osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
6177                      &wlRequest->q);
6178             osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
6179             lock_ReleaseWrite(&smb_globalLock);
6180
6181             /* don't send reply immediately */
6182             outp->flags |= SMB_PACKETFLAG_NOSEND;
6183         }
6184
6185         smb_SetSMBDataLength(outp, 0);
6186     }
6187
6188   done:   
6189     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
6190
6191   doneSync:
6192     lock_ReleaseWrite(&scp->rw);
6193     cm_ReleaseSCache(scp);
6194     cm_ReleaseUser(userp);
6195     smb_ReleaseFID(fidp);
6196
6197     return code;
6198 }
6199
6200 /* SMB_COM_QUERY_INFORMATION2 */
6201 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6202 {
6203     unsigned short fid;
6204     smb_fid_t *fidp;
6205     cm_scache_t *scp;
6206     long code = 0;
6207     afs_uint32 searchTime;
6208     cm_user_t *userp;
6209     cm_req_t req;
6210     int readlock = 0;
6211
6212     smb_InitReq(&req);
6213
6214     fid = smb_GetSMBParm(inp, 0);
6215     fid = smb_ChainFID(fid, inp);
6216         
6217     fidp = smb_FindFID(vcp, fid, 0);
6218     if (!fidp)
6219         return CM_ERROR_BADFD;
6220     
6221     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6222         smb_CloseFID(vcp, fidp, NULL, 0);
6223         smb_ReleaseFID(fidp);
6224         return CM_ERROR_NOSUCHFILE;
6225     }
6226
6227     lock_ObtainMutex(&fidp->mx);
6228     if (fidp->flags & SMB_FID_IOCTL) {
6229         lock_ReleaseMutex(&fidp->mx);
6230         smb_ReleaseFID(fidp);
6231         return CM_ERROR_BADFD;
6232     }
6233     scp = fidp->scp;
6234     osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6235     cm_HoldSCache(scp);
6236     lock_ReleaseMutex(&fidp->mx);
6237         
6238     userp = smb_GetUserFromVCP(vcp, inp);
6239         
6240         
6241     /* otherwise, stat the file */
6242     lock_ObtainWrite(&scp->rw);
6243     code = cm_SyncOp(scp, NULL, userp, &req, 0,
6244                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6245     if (code) 
6246         goto done;
6247
6248     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6249
6250     lock_ConvertWToR(&scp->rw);
6251     readlock = 1;
6252
6253     /* decode times.  We need a search time, but the response to this
6254      * call provides the date first, not the time, as returned in the
6255      * searchTime variable.  So we take the high-order bits first.
6256      */
6257     smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6258     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);       /* ctime */
6259     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6260     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);       /* atime */
6261     smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6262     smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);       /* mtime */
6263     smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6264
6265     /* now handle file size and allocation size */
6266     smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);              /* file size */
6267     smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6268     smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);              /* alloc size */
6269     smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6270
6271     /* file attribute */
6272     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6273         
6274     /* and finalize stuff */
6275     smb_SetSMBDataLength(outp, 0);
6276     code = 0;
6277
6278   done:
6279     if (readlock) 
6280         lock_ReleaseRead(&scp->rw);
6281     else
6282         lock_ReleaseWrite(&scp->rw);
6283     cm_ReleaseSCache(scp);
6284     cm_ReleaseUser(userp);
6285     smb_ReleaseFID(fidp);
6286     return code;
6287 }       
6288
6289 /* SMB_COM_SET_INFORMATION2 */
6290 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6291 {
6292     unsigned short fid;
6293     smb_fid_t *fidp;
6294     cm_scache_t *scp;
6295     long code = 0;
6296     afs_uint32 searchTime;
6297     time_t unixTime;
6298     cm_user_t *userp;
6299     cm_attr_t attrs;
6300     cm_req_t req;
6301
6302     smb_InitReq(&req);
6303
6304     fid = smb_GetSMBParm(inp, 0);
6305     fid = smb_ChainFID(fid, inp);
6306         
6307     fidp = smb_FindFID(vcp, fid, 0);
6308     if (!fidp)
6309         return CM_ERROR_BADFD;
6310     
6311     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6312         smb_CloseFID(vcp, fidp, NULL, 0);
6313         smb_ReleaseFID(fidp);
6314         return CM_ERROR_NOSUCHFILE;
6315     }
6316
6317     lock_ObtainMutex(&fidp->mx);
6318     if (fidp->flags & SMB_FID_IOCTL) {
6319         lock_ReleaseMutex(&fidp->mx);
6320         smb_ReleaseFID(fidp);
6321         return CM_ERROR_BADFD;
6322     }
6323     scp = fidp->scp;
6324     osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6325     cm_HoldSCache(scp);
6326     lock_ReleaseMutex(&fidp->mx);
6327         
6328     userp = smb_GetUserFromVCP(vcp, inp);
6329         
6330         
6331     /* now prepare to call cm_setattr.  This message only sets various times,
6332      * and AFS only implements mtime, and we'll set the mtime if that's
6333      * requested.  The others we'll ignore.
6334      */
6335     searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6336         
6337     if (searchTime != 0) {
6338         smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6339
6340         if ( unixTime != -1 ) {
6341             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6342             attrs.clientModTime = unixTime;
6343             code = cm_SetAttr(scp, &attrs, userp, &req);
6344
6345             osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6346         } else {
6347             osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6348         }
6349     }
6350     else 
6351         code = 0;
6352
6353     cm_ReleaseSCache(scp);
6354     cm_ReleaseUser(userp);
6355     smb_ReleaseFID(fidp);
6356     return code;
6357 }
6358
6359 /* SMB_COM_WRITE_ANDX */
6360 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6361 {
6362     osi_hyper_t offset;
6363     long count, written = 0, total_written = 0;
6364     unsigned short fd;
6365     unsigned pid;
6366     smb_fid_t *fidp;
6367     smb_t *smbp = (smb_t*) inp;
6368     long code = 0;
6369     cm_user_t *userp;
6370     char *op;
6371     int inDataBlockCount;
6372
6373     fd = smb_GetSMBParm(inp, 2);
6374     count = smb_GetSMBParm(inp, 10);
6375
6376     offset.HighPart = 0;
6377     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6378
6379     if (*inp->wctp == 14) {
6380         /* we have a request with 64-bit file offsets */
6381 #ifdef AFS_LARGEFILES
6382         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6383 #else
6384         if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6385             /* uh oh */
6386             osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6387             /* we shouldn't have received this op if we didn't specify
6388                largefile support */
6389             return CM_ERROR_BADOP;
6390         }
6391 #endif
6392     }
6393
6394     op = inp->data + smb_GetSMBParm(inp, 11);
6395     inDataBlockCount = count;
6396
6397     osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6398              fd, offset.HighPart, offset.LowPart, count);
6399         
6400     fd = smb_ChainFID(fd, inp);
6401     fidp = smb_FindFID(vcp, fd, 0);
6402     if (!fidp)
6403         return CM_ERROR_BADFD;
6404         
6405     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6406         smb_CloseFID(vcp, fidp, NULL, 0);
6407         smb_ReleaseFID(fidp);
6408         return CM_ERROR_NOSUCHFILE;
6409     }
6410
6411     lock_ObtainMutex(&fidp->mx);
6412     if (fidp->flags & SMB_FID_IOCTL) {
6413         lock_ReleaseMutex(&fidp->mx);
6414         code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6415         smb_ReleaseFID(fidp);
6416         return code;
6417     }
6418     lock_ReleaseMutex(&fidp->mx);
6419     userp = smb_GetUserFromVCP(vcp, inp);
6420
6421     /* special case: 0 bytes transferred means there is no data
6422        transferred.  A slight departure from SMB_COM_WRITE where this
6423        means that we are supposed to truncate the file at this
6424        position. */
6425
6426     {
6427         cm_key_t key;
6428         LARGE_INTEGER LOffset;
6429         LARGE_INTEGER LLength;
6430         cm_scache_t * scp;
6431
6432         pid = smbp->pid;
6433         key = cm_GenerateKey(vcp->vcID, pid, fd);
6434
6435         LOffset.HighPart = offset.HighPart;
6436         LOffset.LowPart = offset.LowPart;
6437         LLength.HighPart = 0;
6438         LLength.LowPart = count;
6439
6440         scp = fidp->scp;
6441         lock_ObtainWrite(&scp->rw);
6442         code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6443         lock_ReleaseWrite(&scp->rw);
6444
6445         if (code)
6446             goto done;
6447     }
6448
6449     /*
6450      * Work around bug in NT client
6451      *
6452      * When copying a file, the NT client should first copy the data,
6453      * then copy the last write time.  But sometimes the NT client does
6454      * these in the wrong order, so the data copies would inadvertently
6455      * cause the last write time to be overwritten.  We try to detect this,
6456      * and don't set client mod time if we think that would go against the
6457      * intention.
6458      */
6459     lock_ObtainMutex(&fidp->mx);
6460     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6461         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6462         fidp->scp->clientModTime = time(NULL);
6463     }
6464     lock_ReleaseMutex(&fidp->mx);
6465
6466     code = 0;
6467     while ( code == 0 && count > 0 ) {
6468         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6469         if (code == 0 && written == 0)
6470             code = CM_ERROR_PARTIALWRITE;
6471
6472         offset = LargeIntegerAdd(offset,
6473                                  ConvertLongToLargeInteger(written));
6474         count -= written;
6475         total_written += written;
6476         written = 0;
6477     }
6478
6479     /* slots 0 and 1 are reserved for request chaining and will be
6480        filled in when we return. */
6481     smb_SetSMBParm(outp, 2, total_written);
6482     smb_SetSMBParm(outp, 3, 0); /* reserved */
6483     smb_SetSMBParm(outp, 4, 0); /* reserved */
6484     smb_SetSMBParm(outp, 5, 0); /* reserved */
6485     smb_SetSMBDataLength(outp, 0);
6486
6487  done:
6488     cm_ReleaseUser(userp);
6489     smb_ReleaseFID(fidp);
6490
6491     return code;
6492 }
6493
6494 /* SMB_COM_READ_ANDX */
6495 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6496 {
6497     osi_hyper_t offset;
6498     long count;
6499     long finalCount = 0;
6500     unsigned short fd;
6501     unsigned pid;
6502     smb_fid_t *fidp;
6503     smb_t *smbp = (smb_t*) inp;
6504     long code = 0;
6505     cm_user_t *userp;
6506     cm_key_t key;
6507     char *op;
6508         
6509     fd = smb_GetSMBParm(inp, 2);
6510     count = smb_GetSMBParm(inp, 5);
6511     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6512
6513     if (*inp->wctp == 12) {
6514         /* a request with 64-bit offsets */
6515 #ifdef AFS_LARGEFILES
6516         offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6517
6518         if (LargeIntegerLessThanZero(offset)) {
6519             osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6520                      offset.HighPart, offset.LowPart);
6521             return CM_ERROR_BADSMB;
6522         }
6523 #else
6524         if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6525             osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit.  Dropping");
6526             return CM_ERROR_BADSMB;
6527         } else {
6528             offset.HighPart = 0;
6529         }
6530 #endif
6531     } else {
6532         offset.HighPart = 0;
6533     }
6534
6535     osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6536              fd, offset.HighPart, offset.LowPart, count);
6537
6538     fd = smb_ChainFID(fd, inp);
6539     fidp = smb_FindFID(vcp, fd, 0);
6540     if (!fidp) {
6541         return CM_ERROR_BADFD;
6542     }
6543
6544     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6545         smb_CloseFID(vcp, fidp, NULL, 0);
6546         smb_ReleaseFID(fidp);
6547         return CM_ERROR_NOSUCHFILE;
6548     }
6549
6550     pid = smbp->pid;
6551     key = cm_GenerateKey(vcp->vcID, pid, fd);
6552     {
6553         LARGE_INTEGER LOffset, LLength;
6554         cm_scache_t *scp;
6555
6556         LOffset.HighPart = offset.HighPart;
6557         LOffset.LowPart = offset.LowPart;
6558         LLength.HighPart = 0;
6559         LLength.LowPart = count;
6560
6561         scp = fidp->scp;
6562         lock_ObtainWrite(&scp->rw);
6563         code = cm_LockCheckRead(scp, LOffset, LLength, key);
6564         lock_ReleaseWrite(&scp->rw);
6565     }
6566
6567     if (code) {
6568         smb_ReleaseFID(fidp);
6569         return code;
6570     }
6571
6572     /* set inp->fid so that later read calls in same msg can find fid */
6573     inp->fid = fd;
6574
6575     lock_ObtainMutex(&fidp->mx);
6576     if (fidp->flags & SMB_FID_IOCTL) {
6577         lock_ReleaseMutex(&fidp->mx);
6578         code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6579         smb_ReleaseFID(fidp);
6580         return code;
6581     }
6582     lock_ReleaseMutex(&fidp->mx);
6583
6584     userp = smb_GetUserFromVCP(vcp, inp);
6585
6586     /* 0 and 1 are reserved for request chaining, were setup by our caller,
6587      * and will be further filled in after we return.
6588      */
6589     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6590     smb_SetSMBParm(outp, 3, 0); /* resvd */
6591     smb_SetSMBParm(outp, 4, 0); /* resvd */
6592     smb_SetSMBParm(outp, 5, count);     /* # of bytes we're going to read */
6593     /* fill in #6 when we have all the parameters' space reserved */
6594     smb_SetSMBParm(outp, 7, 0); /* resv'd */
6595     smb_SetSMBParm(outp, 8, 0); /* resv'd */
6596     smb_SetSMBParm(outp, 9, 0); /* resv'd */
6597     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
6598     smb_SetSMBParm(outp, 11, 0);        /* reserved */
6599
6600     /* get op ptr after putting in the parms, since otherwise we don't
6601      * know where the data really is.
6602      */
6603     op = smb_GetSMBData(outp, NULL);
6604         
6605     /* now fill in offset from start of SMB header to first data byte (to op) */
6606     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6607
6608     /* set the packet data length the count of the # of bytes */
6609     smb_SetSMBDataLength(outp, count);
6610
6611     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6612
6613     /* fix some things up */
6614     smb_SetSMBParm(outp, 5, finalCount);
6615     smb_SetSMBDataLength(outp, finalCount);
6616
6617     cm_ReleaseUser(userp);
6618     smb_ReleaseFID(fidp);
6619     return code;
6620 }   
6621         
6622 /*
6623  * Values for createDisp, copied from NTDDK.H
6624  */
6625 #define  FILE_SUPERSEDE 0       // (???)
6626 #define  FILE_OPEN      1       // (open)
6627 #define  FILE_CREATE    2       // (exclusive)
6628 #define  FILE_OPEN_IF   3       // (non-exclusive)
6629 #define  FILE_OVERWRITE 4       // (open & truncate, but do not create)
6630 #define  FILE_OVERWRITE_IF 5    // (open & truncate, or create)
6631
6632 /* Flags field */
6633 #define REQUEST_OPLOCK 2
6634 #define REQUEST_BATCH_OPLOCK 4
6635 #define OPEN_DIRECTORY 8
6636 #define EXTENDED_RESPONSE_REQUIRED 0x10
6637
6638 /* CreateOptions field. */
6639 #define FILE_DIRECTORY_FILE       0x0001
6640 #define FILE_WRITE_THROUGH        0x0002
6641 #define FILE_SEQUENTIAL_ONLY      0x0004
6642 #define FILE_NON_DIRECTORY_FILE   0x0040
6643 #define FILE_NO_EA_KNOWLEDGE      0x0200
6644 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6645 #define FILE_RANDOM_ACCESS        0x0800
6646 #define FILE_DELETE_ON_CLOSE      0x1000
6647 #define FILE_OPEN_BY_FILE_ID      0x2000
6648
6649 /* SMB_COM_NT_CREATE_ANDX */
6650 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6651 {
6652     clientchar_t *pathp, *realPathp;
6653     long code = 0;
6654     cm_space_t *spacep;
6655     cm_user_t *userp;
6656     cm_scache_t *dscp;          /* parent dir */
6657     cm_scache_t *scp;           /* file to create or open */
6658     cm_scache_t *targetScp;     /* if scp is a symlink */
6659     cm_attr_t setAttr;
6660     clientchar_t *lastNamep;
6661     clientchar_t *treeStartp;
6662     unsigned short nameLength;
6663     unsigned int flags;
6664     unsigned int requestOpLock;
6665     unsigned int requestBatchOpLock;
6666     unsigned int mustBeDir;
6667     unsigned int extendedRespRequired;
6668     unsigned int treeCreate;
6669     int realDirFlag;
6670     unsigned int desiredAccess;
6671     unsigned int extAttributes;
6672     unsigned int createDisp;
6673     unsigned int createOptions;
6674     unsigned int shareAccess;
6675     int initialModeBits;
6676     unsigned short baseFid;
6677     smb_fid_t *baseFidp;
6678     smb_fid_t *fidp;
6679     cm_scache_t *baseDirp;
6680     unsigned short openAction;
6681     int parmSlot;
6682     long fidflags;
6683     FILETIME ft;
6684     LARGE_INTEGER sz;
6685     clientchar_t *tidPathp;
6686     BOOL foundscp;
6687     cm_req_t req;
6688     int created = 0;
6689     cm_lock_data_t *ldp = NULL;
6690
6691     smb_InitReq(&req);
6692
6693     /* This code is very long and has a lot of if-then-else clauses
6694      * scp and dscp get reused frequently and we need to ensure that 
6695      * we don't lose a reference.  Start by ensuring that they are NULL.
6696      */
6697     scp = NULL;
6698     dscp = NULL;
6699     treeCreate = FALSE;
6700     foundscp = FALSE;
6701
6702     nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6703     flags = smb_GetSMBOffsetParm(inp, 3, 1)
6704         | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6705     requestOpLock = flags & REQUEST_OPLOCK;
6706     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6707     mustBeDir = flags & OPEN_DIRECTORY;
6708     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6709
6710     /*
6711      * Why all of a sudden 32-bit FID?
6712      * We will reject all bits higher than 16.
6713      */
6714     if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6715         return CM_ERROR_INVAL;
6716     baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6717     desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6718         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6719     extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6720         | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6721     shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6722         | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6723     createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6724         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6725     createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6726         | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6727
6728     /* mustBeDir is never set; createOptions directory bit seems to be
6729      * more important
6730      */
6731     if (createOptions & FILE_DIRECTORY_FILE)
6732         realDirFlag = 1;
6733     else if (createOptions & FILE_NON_DIRECTORY_FILE)
6734         realDirFlag = 0;
6735     else
6736         realDirFlag = -1;
6737
6738     /*
6739      * compute initial mode bits based on read-only flag in
6740      * extended attributes
6741      */
6742     initialModeBits = 0666;
6743     if (extAttributes & SMB_ATTR_READONLY) 
6744         initialModeBits &= ~0222;
6745
6746     pathp = smb_ParseStringCb(inp, smb_GetSMBData(inp, NULL), nameLength,
6747                               NULL, SMB_STRF_ANSIPATH);
6748
6749     /* Sometimes path is not null-terminated, so we make a copy. */
6750     realPathp = malloc(nameLength+sizeof(clientchar_t));
6751     memcpy(realPathp, pathp, nameLength+sizeof(clientchar_t));
6752     realPathp[nameLength/sizeof(clientchar_t)] = 0;
6753
6754     spacep = inp->spacep;
6755     smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
6756
6757     osi_Log1(smb_logp,"NTCreateX for [%S]",osi_LogSaveClientString(smb_logp,realPathp));
6758     osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6759     osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%S]", shareAccess, flags, osi_LogSaveClientString(smb_logp,(lastNamep?lastNamep:_C("null"))));
6760
6761         if (lastNamep && 
6762             (cm_ClientStrCmpIA(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
6763              cm_ClientStrCmpIA(lastNamep,  _C("\\srvsvc")) == 0 ||
6764              cm_ClientStrCmpIA(lastNamep,  _C("\\wkssvc")) == 0 ||
6765              cm_ClientStrCmpIA(lastNamep,  _C("ipc$")) == 0)) {
6766         /* special case magic file name for receiving IOCTL requests
6767          * (since IOCTL calls themselves aren't getting through).
6768          */
6769         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6770         smb_SetupIoctlFid(fidp, spacep);
6771         osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6772
6773         /* set inp->fid so that later read calls in same msg can find fid */
6774         inp->fid = fidp->fid;
6775
6776         /* out parms */
6777         parmSlot = 2;
6778         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
6779         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6780         smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6781         /* times */
6782         memset(&ft, 0, sizeof(ft));
6783         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6784         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6785         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6786         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6787         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6788         sz.HighPart = 0x7fff; sz.LowPart = 0;
6789         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6790         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6791         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
6792         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
6793         smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
6794         smb_SetSMBDataLength(outp, 0);
6795
6796         /* clean up fid reference */
6797         smb_ReleaseFID(fidp);
6798         free(realPathp);
6799         return 0;
6800     }
6801
6802 #ifdef DEBUG_VERBOSE
6803     {
6804         char *hexp, *asciip;
6805         asciip = (lastNamep? lastNamep : realPathp);
6806         hexp = osi_HexifyString( asciip );
6807         DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6808         free(hexp);
6809     }
6810 #endif
6811
6812     userp = smb_GetUserFromVCP(vcp, inp);
6813     if (!userp) {
6814         osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6815         free(realPathp);
6816         return CM_ERROR_INVAL;
6817     }
6818
6819     if (baseFid == 0) {
6820         baseFidp = NULL;
6821         baseDirp = cm_data.rootSCachep;
6822         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6823         if (code == CM_ERROR_TIDIPC) {
6824             /* Attempt to use a TID allocated for IPC.  The client
6825              * is probably looking for DCE RPC end points which we
6826              * don't support OR it could be looking to make a DFS
6827              * referral request. 
6828              */
6829             osi_Log0(smb_logp, "NTCreateX received IPC TID");
6830 #ifndef DFS_SUPPORT
6831             free(realPathp);
6832             cm_ReleaseUser(userp);
6833             return CM_ERROR_NOSUCHFILE;
6834 #endif /* DFS_SUPPORT */
6835         }
6836     } else {
6837         baseFidp = smb_FindFID(vcp, baseFid, 0);
6838         if (!baseFidp) {
6839             osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6840             free(realPathp);
6841             cm_ReleaseUser(userp);
6842             return CM_ERROR_INVAL;
6843         }       
6844
6845         if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6846             free(realPathp);
6847             cm_ReleaseUser(userp);
6848             smb_CloseFID(vcp, baseFidp, NULL, 0);
6849             smb_ReleaseFID(baseFidp);
6850             return CM_ERROR_NOSUCHPATH;
6851         }
6852
6853         baseDirp = baseFidp->scp;
6854         tidPathp = NULL;
6855     }
6856
6857     osi_Log1(smb_logp, "NTCreateX tidPathp=[%S]", (tidPathp==NULL)?_C("null"): osi_LogSaveClientString(smb_logp,tidPathp));
6858
6859     /* compute open mode */
6860     fidflags = 0;
6861     if (desiredAccess & DELETE)
6862         fidflags |= SMB_FID_OPENDELETE;
6863     if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
6864         fidflags |= SMB_FID_OPENREAD_LISTDIR;
6865     if (desiredAccess & AFS_ACCESS_WRITE)
6866         fidflags |= SMB_FID_OPENWRITE;
6867     if (createOptions & FILE_DELETE_ON_CLOSE)
6868         fidflags |= SMB_FID_DELONCLOSE;
6869     if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6870         fidflags |= SMB_FID_SEQUENTIAL;
6871     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6872         fidflags |= SMB_FID_RANDOM;
6873     if (smb_IsExecutableFileName(lastNamep))
6874         fidflags |= SMB_FID_EXECUTABLE;
6875
6876     /* and the share mode */
6877     if (shareAccess & FILE_SHARE_READ)
6878         fidflags |= SMB_FID_SHARE_READ;
6879     if (shareAccess & FILE_SHARE_WRITE)
6880         fidflags |= SMB_FID_SHARE_WRITE;
6881
6882     osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6883     code = 0;
6884
6885     /* For an exclusive create, we want to do a case sensitive match for the last component. */
6886     if ( createDisp == FILE_CREATE || 
6887          createDisp == FILE_OVERWRITE ||
6888          createDisp == FILE_OVERWRITE_IF) {
6889         code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6890                         userp, tidPathp, &req, &dscp);
6891         if (code == 0) {
6892 #ifdef DFS_SUPPORT
6893             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6894                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6895                                                           spacep->wdata);
6896                 cm_ReleaseSCache(dscp);
6897                 cm_ReleaseUser(userp);
6898                 free(realPathp);
6899                 if (baseFidp) 
6900                     smb_ReleaseFID(baseFidp);
6901                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6902                     return CM_ERROR_PATH_NOT_COVERED;
6903                 else
6904                     return CM_ERROR_BADSHARENAME;
6905             }
6906 #endif /* DFS_SUPPORT */
6907             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6908                              userp, &req, &scp);
6909             if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
6910                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
6911                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6912                 if (code == 0 && realDirFlag == 1) {
6913                     cm_ReleaseSCache(scp);
6914                     cm_ReleaseSCache(dscp);
6915                     cm_ReleaseUser(userp);
6916                     free(realPathp);
6917                     if (baseFidp) 
6918                         smb_ReleaseFID(baseFidp);
6919                     return CM_ERROR_EXISTS;
6920                 }
6921             }
6922         }
6923         /* we have both scp and dscp */
6924     } else {
6925         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6926                         userp, tidPathp, &req, &scp);
6927 #ifdef DFS_SUPPORT
6928         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6929             int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
6930             cm_ReleaseSCache(scp);
6931             cm_ReleaseUser(userp);
6932             free(realPathp);
6933             if (baseFidp) 
6934                 smb_ReleaseFID(baseFidp);
6935             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6936                 return CM_ERROR_PATH_NOT_COVERED;
6937             else
6938                 return CM_ERROR_BADSHARENAME;
6939         }
6940 #endif /* DFS_SUPPORT */
6941         /* we might have scp but not dscp */
6942     }
6943
6944     if (scp)
6945         foundscp = TRUE;
6946     
6947     if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6948         /* look up parent directory */
6949         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6950          * the immediate parent.  We have to work our way up realPathp until we hit something that we
6951          * recognize.
6952          */
6953
6954         /* we might or might not have scp */
6955
6956         if (dscp == NULL) {
6957             do {
6958                 clientchar_t *tp;
6959
6960                 code = cm_NameI(baseDirp, spacep->wdata,
6961                                 CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6962                                 userp, tidPathp, &req, &dscp);
6963
6964 #ifdef DFS_SUPPORT
6965                 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6966                     int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
6967                                                               spacep->wdata);
6968                     if (scp)
6969                         cm_ReleaseSCache(scp);
6970                     cm_ReleaseSCache(dscp);
6971                     cm_ReleaseUser(userp);
6972                     free(realPathp);
6973                     if (baseFidp) 
6974                         smb_ReleaseFID(baseFidp);
6975                     if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6976                         return CM_ERROR_PATH_NOT_COVERED;
6977                     else
6978                         return CM_ERROR_BADSHARENAME;
6979                 }
6980 #endif /* DFS_SUPPORT */
6981
6982                 if (code &&
6983                     (tp = cm_ClientStrRChr(spacep->wdata, '\\')) &&
6984                     (createDisp == FILE_CREATE) &&
6985                     (realDirFlag == 1)) {
6986                     *tp++ = 0;
6987                     treeCreate = TRUE;
6988                     treeStartp = realPathp + (tp - spacep->wdata);
6989
6990                     if (*tp && !smb_IsLegalFilename(tp)) {
6991                         cm_ReleaseUser(userp);
6992                         if (baseFidp) 
6993                             smb_ReleaseFID(baseFidp);
6994                         free(realPathp);
6995                         if (scp)
6996                             cm_ReleaseSCache(scp);
6997                         return CM_ERROR_BADNTFILENAME;
6998                     }
6999                     code = 0;
7000                 }
7001             } while (dscp == NULL && code == 0);
7002         } else
7003             code = 0;
7004
7005         /* we might have scp and we might have dscp */
7006
7007         if (baseFidp)
7008             smb_ReleaseFID(baseFidp);
7009
7010         if (code) {
7011             osi_Log0(smb_logp,"NTCreateX parent not found");
7012             if (scp)
7013                 cm_ReleaseSCache(scp);
7014             if (dscp)
7015                 cm_ReleaseSCache(dscp);
7016             cm_ReleaseUser(userp);
7017             free(realPathp);
7018             return code;
7019         }
7020
7021         if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
7022             /* A file exists where we want a directory. */
7023             if (scp)
7024                 cm_ReleaseSCache(scp);
7025             cm_ReleaseSCache(dscp);
7026             cm_ReleaseUser(userp);
7027             free(realPathp);
7028             return CM_ERROR_EXISTS;
7029         }
7030
7031         if (!lastNamep) 
7032             lastNamep = realPathp;
7033         else 
7034             lastNamep++;
7035
7036         if (!smb_IsLegalFilename(lastNamep)) {
7037             if (scp)
7038                 cm_ReleaseSCache(scp);
7039             if (dscp)
7040                 cm_ReleaseSCache(dscp);
7041             cm_ReleaseUser(userp);
7042             free(realPathp);
7043             return CM_ERROR_BADNTFILENAME;
7044         }
7045
7046         if (!foundscp && !treeCreate) {
7047             if ( createDisp == FILE_CREATE || 
7048                  createDisp == FILE_OVERWRITE ||
7049                  createDisp == FILE_OVERWRITE_IF) 
7050             {
7051                 code = cm_Lookup(dscp, lastNamep,
7052                                   CM_FLAG_FOLLOW, userp, &req, &scp);
7053             } else {
7054                 code = cm_Lookup(dscp, lastNamep,
7055                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7056                                  userp, &req, &scp);
7057             }
7058             if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
7059                 if (dscp)
7060                     cm_ReleaseSCache(dscp);
7061                 cm_ReleaseUser(userp);
7062                 free(realPathp);
7063                 return code;
7064             }
7065         }
7066         /* we have scp and dscp */
7067     } else {
7068         /* we have scp but not dscp */
7069         if (baseFidp)
7070             smb_ReleaseFID(baseFidp);
7071     }
7072
7073     /* if we get here, if code is 0, the file exists and is represented by
7074      * scp.  Otherwise, we have to create it.  The dir may be represented
7075      * by dscp, or we may have found the file directly.  If code is non-zero,
7076      * scp is NULL.
7077      */
7078     if (code == 0 && !treeCreate) {
7079         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7080         if (code) {
7081             if (dscp)
7082                 cm_ReleaseSCache(dscp);
7083             if (scp)
7084                 cm_ReleaseSCache(scp);
7085             cm_ReleaseUser(userp);
7086             free(realPathp);
7087             return code;
7088         }
7089
7090         if (createDisp == FILE_CREATE) {
7091             /* oops, file shouldn't be there */
7092             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7093             if (dscp)
7094                 cm_ReleaseSCache(dscp);
7095             if (scp)
7096                 cm_ReleaseSCache(scp);
7097             cm_ReleaseUser(userp);
7098             free(realPathp);
7099             return CM_ERROR_EXISTS;
7100         }
7101
7102         if ( createDisp == FILE_OVERWRITE || 
7103              createDisp == FILE_OVERWRITE_IF) {
7104
7105             setAttr.mask = CM_ATTRMASK_LENGTH;
7106             setAttr.length.LowPart = 0;
7107             setAttr.length.HighPart = 0;
7108             /* now watch for a symlink */
7109             code = 0;
7110             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7111                 targetScp = 0;
7112                 osi_assertx(dscp != NULL, "null cm_scache_t");
7113                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7114                 if (code == 0) {
7115                     /* we have a more accurate file to use (the
7116                      * target of the symbolic link).  Otherwise,
7117                      * we'll just use the symlink anyway.
7118                      */
7119                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
7120                               scp, targetScp);
7121                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7122                     cm_ReleaseSCache(scp);
7123                     scp = targetScp;
7124                     code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7125                     if (code) {
7126                         if (dscp)
7127                             cm_ReleaseSCache(dscp);
7128                         if (scp)
7129                             cm_ReleaseSCache(scp);
7130                         cm_ReleaseUser(userp);
7131                         free(realPathp);
7132                         return code;
7133                     }
7134                 }
7135             }
7136             code = cm_SetAttr(scp, &setAttr, userp, &req);
7137             openAction = 3;     /* truncated existing file */
7138         }
7139         else 
7140             openAction = 1;     /* found existing file */
7141
7142     } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7143         /* don't create if not found */
7144         if (dscp)
7145             cm_ReleaseSCache(dscp);
7146         if (scp)
7147             cm_ReleaseSCache(scp);
7148         cm_ReleaseUser(userp);
7149         free(realPathp);
7150         return CM_ERROR_NOSUCHFILE;
7151     } else if (realDirFlag == 0 || realDirFlag == -1) {
7152         osi_assertx(dscp != NULL, "null cm_scache_t");
7153         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %S",
7154                   osi_LogSaveClientString(smb_logp, lastNamep));
7155         openAction = 2;         /* created file */
7156         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7157         setAttr.clientModTime = time(NULL);
7158         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
7159         if (code == 0) {
7160             created = 1;
7161             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7162                 smb_NotifyChange(FILE_ACTION_ADDED,
7163                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7164                                  dscp, lastNamep, NULL, TRUE);
7165         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7166             /* Not an exclusive create, and someone else tried
7167              * creating it already, then we open it anyway.  We
7168              * don't bother retrying after this, since if this next
7169              * fails, that means that the file was deleted after we
7170              * started this call.
7171              */
7172             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7173                               userp, &req, &scp);
7174             if (code == 0) {
7175                 if (createDisp == FILE_OVERWRITE_IF) {
7176                     setAttr.mask = CM_ATTRMASK_LENGTH;
7177                     setAttr.length.LowPart = 0;
7178                     setAttr.length.HighPart = 0;
7179
7180                     /* now watch for a symlink */
7181                     code = 0;
7182                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7183                         targetScp = 0;
7184                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7185                         if (code == 0) {
7186                             /* we have a more accurate file to use (the
7187                              * target of the symbolic link).  Otherwise,
7188                              * we'll just use the symlink anyway.
7189                              */
7190                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
7191                                       scp, targetScp);
7192                             cm_ReleaseSCache(scp);
7193                             scp = targetScp;
7194                         }
7195                     }
7196                     code = cm_SetAttr(scp, &setAttr, userp, &req);
7197                 }
7198             }   /* lookup succeeded */
7199         }
7200     } else {
7201         clientchar_t *tp, *pp;
7202         clientchar_t *cp; /* This component */
7203         int clen = 0; /* length of component */
7204         cm_scache_t *tscp1, *tscp2;
7205         int isLast = 0;
7206
7207         /* create directory */
7208         if ( !treeCreate ) 
7209             treeStartp = lastNamep;
7210         osi_assertx(dscp != NULL, "null cm_scache_t");
7211         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%S]",
7212                   osi_LogSaveClientString(smb_logp, treeStartp));
7213         openAction = 2;         /* created directory */
7214
7215         /* if the request is to create the root directory 
7216          * it will appear as a directory name of the nul-string
7217          * and a code of CM_ERROR_NOSUCHFILE
7218          */
7219         if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
7220             code = CM_ERROR_EXISTS;
7221
7222         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7223         setAttr.clientModTime = time(NULL);
7224
7225         pp = treeStartp;
7226         cp = spacep->wdata;
7227         tscp1 = dscp;
7228         cm_HoldSCache(tscp1);
7229         tscp2 = NULL;
7230
7231         while (pp && *pp) {
7232             tp = cm_ClientStrChr(pp, '\\');
7233             if (!tp) {
7234                 cm_ClientStrCpy(cp, lengthof(spacep->wdata) - (cp - spacep->wdata), pp);
7235                 clen = (int)cm_ClientStrLen(cp);
7236                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
7237             } else {
7238                 clen = (int)(tp - pp);
7239                 cm_ClientStrCpyN(cp, lengthof(spacep->wdata) - (cp - spacep->wdata),
7240                                  pp, clen);
7241                 *(cp + clen) = 0;
7242                 tp++;
7243             }
7244             pp = tp;
7245
7246             if (clen == 0) 
7247                 continue; /* the supplied path can't have consecutive slashes either , but */
7248
7249             /* cp is the next component to be created. */
7250             code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req, NULL);
7251             if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
7252                 smb_NotifyChange(FILE_ACTION_ADDED,
7253                                  FILE_NOTIFY_CHANGE_DIR_NAME,
7254                                  tscp1, cp, NULL, TRUE);
7255             if (code == 0 ||
7256                 (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7257                 /* Not an exclusive create, and someone else tried
7258                  * creating it already, then we open it anyway.  We
7259                  * don't bother retrying after this, since if this next
7260                  * fails, that means that the file was deleted after we
7261                  * started this call.
7262                  */
7263                 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
7264                                  userp, &req, &tscp2);
7265             }
7266             if (code) 
7267                 break;
7268
7269             if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
7270                 cm_ReleaseSCache(tscp1);
7271                 tscp1 = tscp2; /* Newly created directory will be next parent */
7272                 /* the hold is transfered to tscp1 from tscp2 */
7273             }
7274         }
7275
7276         if (dscp)
7277             cm_ReleaseSCache(dscp);
7278         dscp = tscp1;
7279         if (scp)
7280             cm_ReleaseSCache(scp);
7281         scp = tscp2;
7282         /* 
7283          * if we get here and code == 0, then scp is the last directory created, and dscp is the
7284          * parent of scp.
7285          */
7286     }
7287
7288     if (code) {
7289         /* something went wrong creating or truncating the file */
7290         if (ldp)
7291             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7292         if (scp) 
7293             cm_ReleaseSCache(scp);
7294         if (dscp) 
7295             cm_ReleaseSCache(dscp);
7296         cm_ReleaseUser(userp);
7297         free(realPathp);
7298         return code;
7299     }
7300
7301     /* make sure we have file vs. dir right (only applies for single component case) */
7302     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7303         /* now watch for a symlink */
7304         code = 0;
7305         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7306             cm_scache_t * targetScp = 0;
7307             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7308             if (code == 0) {
7309                 /* we have a more accurate file to use (the
7310                 * target of the symbolic link).  Otherwise,
7311                 * we'll just use the symlink anyway.
7312                 */
7313                 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7314                 if (ldp)
7315                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7316                 cm_ReleaseSCache(scp);
7317                 scp = targetScp;
7318             }
7319         }
7320
7321         if (scp->fileType != CM_SCACHETYPE_FILE) {
7322             if (ldp)
7323                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7324             if (dscp)
7325                 cm_ReleaseSCache(dscp);
7326             cm_ReleaseSCache(scp);
7327             cm_ReleaseUser(userp);
7328             free(realPathp);
7329             return CM_ERROR_ISDIR;
7330         }
7331     }
7332
7333     /* (only applies to single component case) */
7334     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7335         if (ldp)
7336             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7337         cm_ReleaseSCache(scp);
7338         if (dscp)
7339             cm_ReleaseSCache(dscp);
7340         cm_ReleaseUser(userp);
7341         free(realPathp);
7342         return CM_ERROR_NOTDIR;
7343     }
7344
7345     /* open the file itself */
7346     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7347     osi_assertx(fidp, "null smb_fid_t");
7348
7349     /* save a reference to the user */
7350     cm_HoldUser(userp);
7351     fidp->userp = userp;
7352
7353     /* If we are restricting sharing, we should do so with a suitable
7354        share lock. */
7355     if (scp->fileType == CM_SCACHETYPE_FILE &&
7356         !(fidflags & SMB_FID_SHARE_WRITE)) {
7357         cm_key_t key;
7358         LARGE_INTEGER LOffset, LLength;
7359         int sLockType;
7360
7361         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7362         LOffset.LowPart = SMB_FID_QLOCK_LOW;
7363         LLength.HighPart = 0;
7364         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7365
7366         /* If we are not opening the file for writing, then we don't
7367            try to get an exclusive lock.  No one else should be able to
7368            get an exclusive lock on the file anyway, although someone
7369            else can get a shared lock. */
7370         if ((fidflags & SMB_FID_SHARE_READ) ||
7371             !(fidflags & SMB_FID_OPENWRITE)) {
7372             sLockType = LOCKING_ANDX_SHARED_LOCK;
7373         } else {
7374             sLockType = 0;
7375         }
7376
7377         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7378         
7379         lock_ObtainWrite(&scp->rw);
7380         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7381         lock_ReleaseWrite(&scp->rw);
7382
7383         if (code) {
7384             if (ldp)
7385                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7386             cm_ReleaseSCache(scp);
7387             if (dscp)
7388                 cm_ReleaseSCache(dscp);
7389             cm_ReleaseUser(userp);
7390             /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
7391             smb_CloseFID(vcp, fidp, NULL, 0);
7392             smb_ReleaseFID(fidp);
7393             free(realPathp);
7394             return code;
7395         }
7396     }
7397
7398     /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7399     if (ldp)
7400         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7401
7402     lock_ObtainMutex(&fidp->mx);
7403     /* save a pointer to the vnode */
7404     fidp->scp = scp;    /* Hold transfered to fidp->scp and no longer needed */
7405     lock_ObtainWrite(&scp->rw);
7406     scp->flags |= CM_SCACHEFLAG_SMB_FID;
7407     lock_ReleaseWrite(&scp->rw);
7408     osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7409
7410     fidp->flags = fidflags;
7411
7412     /* remember if the file was newly created */
7413     if (created)
7414         fidp->flags |= SMB_FID_CREATED;
7415
7416     /* save parent dir and pathname for delete or change notification */
7417     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7418         osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7419         fidp->flags |= SMB_FID_NTOPEN;
7420         fidp->NTopen_dscp = dscp;
7421         dscp = NULL;
7422         fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
7423     }
7424     fidp->NTopen_wholepathp = realPathp;
7425     lock_ReleaseMutex(&fidp->mx);
7426
7427     /* we don't need this any longer */
7428     if (dscp) {
7429         cm_ReleaseSCache(dscp);
7430         dscp = NULL;
7431     }
7432
7433     cm_Open(scp, 0, userp);
7434
7435     /* set inp->fid so that later read calls in same msg can find fid */
7436     inp->fid = fidp->fid;
7437
7438     /* out parms */
7439     parmSlot = 2;
7440     lock_ObtainRead(&scp->rw);
7441     smb_SetSMBParmByte(outp, parmSlot, 0);      /* oplock */
7442     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7443     smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7444     smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7445     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7446     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7447     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7448     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7449     smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7450     parmSlot += 2;
7451     smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7452     smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7453     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* filetype */
7454     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* dev state */
7455     smb_SetSMBParmByte(outp, parmSlot,
7456                         (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7457                          scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7458                          scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7459     smb_SetSMBDataLength(outp, 0);
7460
7461     if ((fidp->flags & SMB_FID_EXECUTABLE) && 
7462         LargeIntegerGreaterThanZero(fidp->scp->length) && 
7463         !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
7464         cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
7465                            fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
7466                            userp);
7467     }
7468     lock_ReleaseRead(&scp->rw);
7469
7470     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %S", fidp->fid,
7471               osi_LogSaveClientString(smb_logp, realPathp));
7472
7473     cm_ReleaseUser(userp);
7474     smb_ReleaseFID(fidp);
7475
7476     /* Can't free realPathp if we get here since
7477        fidp->NTopen_wholepathp is pointing there */
7478
7479     /* leave scp held since we put it in fidp->scp */
7480     return 0;
7481 }       
7482
7483 /*
7484  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7485  * Instead, ultimately, would like to use a subroutine for common code.
7486  */
7487
7488 /* NT_TRANSACT_CREATE (SMB_COM_NT_TRANSACT) */
7489 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7490 {
7491     clientchar_t *pathp, *realPathp;
7492     long code = 0;
7493     cm_space_t *spacep;
7494     cm_user_t *userp;
7495     cm_scache_t *dscp;          /* parent dir */
7496     cm_scache_t *scp;           /* file to create or open */
7497     cm_scache_t *targetScp;     /* if scp is a symlink */
7498     cm_attr_t setAttr;
7499     clientchar_t *lastNamep;
7500     unsigned long nameLength;
7501     unsigned int flags;
7502     unsigned int requestOpLock;
7503     unsigned int requestBatchOpLock;
7504     unsigned int mustBeDir;
7505     unsigned int extendedRespRequired;
7506     int realDirFlag;
7507     unsigned int desiredAccess;
7508 #ifdef DEBUG_VERBOSE    
7509     unsigned int allocSize;
7510 #endif
7511     unsigned int shareAccess;
7512     unsigned int extAttributes;
7513     unsigned int createDisp;
7514 #ifdef DEBUG_VERBOSE
7515     unsigned int sdLen;
7516 #endif
7517     unsigned int createOptions;
7518     int initialModeBits;
7519     unsigned short baseFid;
7520     smb_fid_t *baseFidp;
7521     smb_fid_t *fidp;
7522     cm_scache_t *baseDirp;
7523     unsigned short openAction;
7524     int parmSlot;
7525     long fidflags;
7526     FILETIME ft;
7527     clientchar_t *tidPathp;
7528     BOOL foundscp;
7529     int parmOffset, dataOffset;
7530     char *parmp;
7531     ULONG *lparmp;
7532     char *outData;
7533     cm_req_t req;
7534     int created = 0;
7535     cm_lock_data_t *ldp = NULL;
7536
7537     smb_InitReq(&req);
7538
7539     foundscp = FALSE;
7540     scp = NULL;
7541
7542     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7543         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7544     parmp = inp->data + parmOffset;
7545     lparmp = (ULONG *) parmp;
7546
7547     flags = lparmp[0];
7548     requestOpLock = flags & REQUEST_OPLOCK;
7549     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7550     mustBeDir = flags & OPEN_DIRECTORY;
7551     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7552
7553     /*
7554      * Why all of a sudden 32-bit FID?
7555      * We will reject all bits higher than 16.
7556      */
7557     if (lparmp[1] & 0xFFFF0000)
7558         return CM_ERROR_INVAL;
7559     baseFid = (unsigned short)lparmp[1];
7560     desiredAccess = lparmp[2];
7561 #ifdef DEBUG_VERBOSE
7562     allocSize = lparmp[3];
7563 #endif /* DEBUG_VERSOSE */
7564     extAttributes = lparmp[5];
7565     shareAccess = lparmp[6];
7566     createDisp = lparmp[7];
7567     createOptions = lparmp[8];
7568 #ifdef DEBUG_VERBOSE
7569     sdLen = lparmp[9];
7570 #endif
7571     nameLength = lparmp[11];
7572
7573 #ifdef DEBUG_VERBOSE
7574     osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7575     osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7576     osi_Log1(smb_logp,"... flags[%x]",flags);
7577 #endif
7578
7579     /* mustBeDir is never set; createOptions directory bit seems to be
7580      * more important
7581      */
7582     if (createOptions & FILE_DIRECTORY_FILE)
7583         realDirFlag = 1;
7584     else if (createOptions & FILE_NON_DIRECTORY_FILE)
7585         realDirFlag = 0;
7586     else
7587         realDirFlag = -1;
7588
7589     /*
7590      * compute initial mode bits based on read-only flag in
7591      * extended attributes
7592      */
7593     initialModeBits = 0666;
7594     if (extAttributes & SMB_ATTR_READONLY) 
7595         initialModeBits &= ~0222;
7596
7597     pathp = smb_ParseStringCch(inp, (parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR)),
7598                                nameLength, NULL, SMB_STRF_ANSIPATH);
7599     /* Sometimes path is not null-terminated, so we make a copy. */
7600     realPathp = malloc((nameLength+1) * sizeof(clientchar_t));
7601     memcpy(realPathp, pathp, nameLength * sizeof(clientchar_t));
7602     realPathp[nameLength] = 0;
7603     spacep = cm_GetSpace();
7604     smb_StripLastComponent(spacep->wdata, &lastNamep, realPathp);
7605
7606     /*
7607      * Nothing here to handle SMB_IOCTL_FILENAME.
7608      * Will add it if necessary.
7609      */
7610
7611 #ifdef DEBUG_VERBOSE
7612     {
7613         char *hexp, *asciip;
7614         asciip = (lastNamep? lastNamep : realPathp);
7615         hexp = osi_HexifyString( asciip );
7616         DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7617         free(hexp);
7618     }
7619 #endif
7620
7621     userp = smb_GetUserFromVCP(vcp, inp);
7622     if (!userp) {
7623         osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7624         free(realPathp);
7625         return CM_ERROR_INVAL;
7626     }
7627
7628     if (baseFid == 0) {
7629         baseFidp = NULL;
7630         baseDirp = cm_data.rootSCachep;
7631         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7632         if (code == CM_ERROR_TIDIPC) {
7633             /* Attempt to use a TID allocated for IPC.  The client
7634              * is probably looking for DCE RPC end points which we
7635              * don't support OR it could be looking to make a DFS
7636              * referral request. 
7637              */
7638             osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7639 #ifndef DFS_SUPPORT
7640             free(realPathp);
7641             cm_ReleaseUser(userp);
7642             return CM_ERROR_NOSUCHPATH;
7643 #endif 
7644         }
7645     } else {
7646         baseFidp = smb_FindFID(vcp, baseFid, 0);
7647         if (!baseFidp) {
7648             osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7649             free(realPathp);
7650             cm_ReleaseUser(userp);
7651             return CM_ERROR_BADFD;
7652         }       
7653
7654         if (baseFidp->scp && (baseFidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7655             free(realPathp);
7656             cm_ReleaseUser(userp);
7657             smb_CloseFID(vcp, baseFidp, NULL, 0);
7658             smb_ReleaseFID(baseFidp);
7659             return CM_ERROR_NOSUCHPATH;
7660         }
7661
7662         baseDirp = baseFidp->scp;
7663         tidPathp = NULL;
7664     }
7665
7666     /* compute open mode */
7667     fidflags = 0;
7668     if (desiredAccess & DELETE)
7669         fidflags |= SMB_FID_OPENDELETE;
7670     if (desiredAccess & (AFS_ACCESS_READ|AFS_ACCESS_EXECUTE))
7671         fidflags |= SMB_FID_OPENREAD_LISTDIR;
7672     if (desiredAccess & AFS_ACCESS_WRITE)
7673         fidflags |= SMB_FID_OPENWRITE;
7674     if (createOptions & FILE_DELETE_ON_CLOSE)
7675         fidflags |= SMB_FID_DELONCLOSE;
7676     if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7677         fidflags |= SMB_FID_SEQUENTIAL;
7678     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7679         fidflags |= SMB_FID_RANDOM;
7680     if (smb_IsExecutableFileName(lastNamep))
7681         fidflags |= SMB_FID_EXECUTABLE;
7682
7683     /* And the share mode */
7684     if (shareAccess & FILE_SHARE_READ)
7685         fidflags |= SMB_FID_SHARE_READ;
7686     if (shareAccess & FILE_SHARE_WRITE)
7687         fidflags |= SMB_FID_SHARE_WRITE;
7688
7689     dscp = NULL;
7690     code = 0;
7691     if ( createDisp == FILE_OPEN || 
7692          createDisp == FILE_OVERWRITE ||
7693          createDisp == FILE_OVERWRITE_IF) {
7694         code = cm_NameI(baseDirp, spacep->wdata, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7695                         userp, tidPathp, &req, &dscp);
7696         if (code == 0) {
7697 #ifdef DFS_SUPPORT
7698             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7699                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7700                 cm_ReleaseSCache(dscp);
7701                 cm_ReleaseUser(userp);
7702                 free(realPathp);
7703                 if (baseFidp)
7704                     smb_ReleaseFID(baseFidp);
7705                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7706                     return CM_ERROR_PATH_NOT_COVERED;
7707                 else
7708                     return CM_ERROR_BADSHARENAME;
7709             }
7710 #endif /* DFS_SUPPORT */
7711             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7712                              userp, &req, &scp);
7713             if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7714                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
7715                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7716                 if (code == 0 && realDirFlag == 1) {
7717                     cm_ReleaseSCache(scp);
7718                     cm_ReleaseSCache(dscp);
7719                     cm_ReleaseUser(userp);
7720                     free(realPathp);
7721                     if (baseFidp)
7722                         smb_ReleaseFID(baseFidp);
7723                     return CM_ERROR_EXISTS;
7724                 }
7725             }
7726         } else 
7727             dscp = NULL;
7728     } else {
7729         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7730                         userp, tidPathp, &req, &scp);
7731 #ifdef DFS_SUPPORT
7732         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7733             int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, realPathp);
7734             cm_ReleaseSCache(scp);
7735             cm_ReleaseUser(userp);
7736             free(realPathp);
7737             if (baseFidp)
7738                 smb_ReleaseFID(baseFidp);
7739             if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7740                 return CM_ERROR_PATH_NOT_COVERED;
7741             else
7742                 return CM_ERROR_BADSHARENAME;
7743         }
7744 #endif /* DFS_SUPPORT */
7745     }
7746
7747     if (code == 0) 
7748         foundscp = TRUE;
7749
7750     if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7751         /* look up parent directory */
7752         if ( !dscp ) {
7753             code = cm_NameI(baseDirp, spacep->wdata,
7754                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7755                              userp, tidPathp, &req, &dscp);
7756 #ifdef DFS_SUPPORT
7757             if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7758                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7759                 cm_ReleaseSCache(dscp);
7760                 cm_ReleaseUser(userp);
7761                 free(realPathp);
7762                 if (baseFidp)
7763                     smb_ReleaseFID(baseFidp);
7764                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7765                     return CM_ERROR_PATH_NOT_COVERED;
7766                 else
7767                     return CM_ERROR_BADSHARENAME;
7768             }
7769 #endif /* DFS_SUPPORT */
7770         } else
7771             code = 0;
7772         
7773         cm_FreeSpace(spacep);
7774
7775         if (baseFidp)
7776             smb_ReleaseFID(baseFidp);
7777
7778         if (code) {
7779             cm_ReleaseUser(userp);
7780             free(realPathp);
7781             return code;
7782         }
7783
7784         if (!lastNamep)
7785             lastNamep = realPathp;
7786         else 
7787             lastNamep++;
7788
7789         if (!smb_IsLegalFilename(lastNamep))
7790             return CM_ERROR_BADNTFILENAME;
7791
7792         if (!foundscp) {
7793             if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7794                 code = cm_Lookup(dscp, lastNamep,
7795                                   CM_FLAG_FOLLOW, userp, &req, &scp);
7796             } else {
7797                 code = cm_Lookup(dscp, lastNamep,
7798                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7799                                  userp, &req, &scp);
7800             }
7801             if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7802                 cm_ReleaseSCache(dscp);
7803                 cm_ReleaseUser(userp);
7804                 free(realPathp);
7805                 return code;
7806             }
7807         }
7808     } else {
7809         if (baseFidp)
7810             smb_ReleaseFID(baseFidp);
7811         cm_FreeSpace(spacep);
7812     }
7813
7814     /* if we get here, if code is 0, the file exists and is represented by
7815      * scp.  Otherwise, we have to create it.  The dir may be represented
7816      * by dscp, or we may have found the file directly.  If code is non-zero,
7817      * scp is NULL.
7818      */
7819     if (code == 0) {
7820         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7821         if (code) {     
7822             if (dscp) 
7823                 cm_ReleaseSCache(dscp);
7824             cm_ReleaseSCache(scp);
7825             cm_ReleaseUser(userp);
7826             free(realPathp);
7827             return code;
7828         }
7829
7830         if (createDisp == FILE_CREATE) {
7831             /* oops, file shouldn't be there */
7832             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7833             if (dscp) 
7834                 cm_ReleaseSCache(dscp);
7835             cm_ReleaseSCache(scp);
7836             cm_ReleaseUser(userp);
7837             free(realPathp);
7838             return CM_ERROR_EXISTS;
7839         }
7840
7841         if (createDisp == FILE_OVERWRITE ||
7842             createDisp == FILE_OVERWRITE_IF) {
7843             setAttr.mask = CM_ATTRMASK_LENGTH;
7844             setAttr.length.LowPart = 0;
7845             setAttr.length.HighPart = 0;
7846
7847             /* now watch for a symlink */
7848             code = 0;
7849             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7850                 targetScp = 0;
7851                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7852                 if (code == 0) {
7853                     /* we have a more accurate file to use (the
7854                     * target of the symbolic link).  Otherwise,
7855                     * we'll just use the symlink anyway.
7856                     */
7857                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
7858                               scp, targetScp);
7859                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7860                     cm_ReleaseSCache(scp);
7861                     scp = targetScp;
7862                     code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7863                     if (code) {
7864                         if (dscp)
7865                             cm_ReleaseSCache(dscp);
7866                         if (scp)
7867                             cm_ReleaseSCache(scp);
7868                         cm_ReleaseUser(userp);
7869                         free(realPathp);
7870                         return code;
7871                     }
7872                 }
7873             }
7874             code = cm_SetAttr(scp, &setAttr, userp, &req);
7875             openAction = 3;     /* truncated existing file */
7876         }
7877         else openAction = 1;    /* found existing file */
7878     }
7879     else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7880         /* don't create if not found */
7881         if (dscp) 
7882             cm_ReleaseSCache(dscp);
7883         cm_ReleaseUser(userp);
7884         free(realPathp);
7885         return CM_ERROR_NOSUCHFILE;
7886     }
7887     else if (realDirFlag == 0 || realDirFlag == -1) {
7888         osi_assertx(dscp != NULL, "null cm_scache_t");
7889         osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %S",
7890                   osi_LogSaveClientString(smb_logp, lastNamep));
7891         openAction = 2;         /* created file */
7892         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7893         setAttr.clientModTime = time(NULL);
7894         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7895                           &req);
7896         if (code == 0) {
7897             created = 1;
7898             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7899                 smb_NotifyChange(FILE_ACTION_ADDED,
7900                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7901                                  dscp, lastNamep, NULL, TRUE);
7902         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7903             /* Not an exclusive create, and someone else tried
7904              * creating it already, then we open it anyway.  We
7905              * don't bother retrying after this, since if this next
7906              * fails, that means that the file was deleted after we
7907              * started this call.
7908              */
7909             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7910                               userp, &req, &scp);
7911             if (code == 0) {
7912                 if (createDisp == FILE_OVERWRITE_IF) {
7913                     setAttr.mask = CM_ATTRMASK_LENGTH;
7914                     setAttr.length.LowPart = 0;
7915                     setAttr.length.HighPart = 0;
7916
7917                     /* now watch for a symlink */
7918                     code = 0;
7919                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7920                         targetScp = 0;
7921                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7922                         if (code == 0) {
7923                             /* we have a more accurate file to use (the
7924                             * target of the symbolic link).  Otherwise,
7925                             * we'll just use the symlink anyway.
7926                             */
7927                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
7928                                       scp, targetScp);
7929                             cm_ReleaseSCache(scp);
7930                             scp = targetScp;
7931                         }
7932                     }
7933                     code = cm_SetAttr(scp, &setAttr, userp, &req);
7934                 }       
7935             }   /* lookup succeeded */
7936         }
7937     } else {
7938         /* create directory */
7939         osi_assertx(dscp != NULL, "null cm_scache_t");
7940         osi_Log1(smb_logp,
7941                   "smb_ReceiveNTTranCreate creating directory %S",
7942                   osi_LogSaveClientString(smb_logp, lastNamep));
7943         openAction = 2;         /* created directory */
7944         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7945         setAttr.clientModTime = time(NULL);
7946         code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7947         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7948             smb_NotifyChange(FILE_ACTION_ADDED,
7949                               FILE_NOTIFY_CHANGE_DIR_NAME,
7950                               dscp, lastNamep, NULL, TRUE);
7951         if (code == 0 ||
7952             (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7953             /* Not an exclusive create, and someone else tried
7954              * creating it already, then we open it anyway.  We
7955              * don't bother retrying after this, since if this next
7956              * fails, that means that the file was deleted after we
7957              * started this call.
7958              */
7959             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7960                               userp, &req, &scp);
7961         }       
7962     }
7963
7964     if (code) {
7965         /* something went wrong creating or truncating the file */
7966         if (ldp)
7967             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7968         if (scp) 
7969             cm_ReleaseSCache(scp);
7970         cm_ReleaseUser(userp);
7971         free(realPathp);
7972         return code;
7973     }
7974
7975     /* make sure we have file vs. dir right */
7976     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7977         /* now watch for a symlink */
7978         code = 0;
7979         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7980             targetScp = 0;
7981             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7982             if (code == 0) {
7983                 /* we have a more accurate file to use (the
7984                 * target of the symbolic link).  Otherwise,
7985                 * we'll just use the symlink anyway.
7986                 */
7987                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7988                           scp, targetScp);
7989                 if (ldp)
7990                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7991                 cm_ReleaseSCache(scp);
7992                 scp = targetScp;
7993             }
7994         }
7995
7996         if (scp->fileType != CM_SCACHETYPE_FILE) {
7997             if (ldp)
7998                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7999             cm_ReleaseSCache(scp);
8000             cm_ReleaseUser(userp);
8001             free(realPathp);
8002             return CM_ERROR_ISDIR;
8003         }
8004     }
8005
8006     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
8007         if (ldp)
8008             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8009         cm_ReleaseSCache(scp);
8010         cm_ReleaseUser(userp);
8011         free(realPathp);
8012         return CM_ERROR_NOTDIR;
8013     }
8014
8015     /* open the file itself */
8016     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8017     osi_assertx(fidp, "null smb_fid_t");
8018
8019     /* save a reference to the user */
8020     cm_HoldUser(userp);
8021     fidp->userp = userp;
8022
8023     /* If we are restricting sharing, we should do so with a suitable
8024        share lock. */
8025     if (scp->fileType == CM_SCACHETYPE_FILE &&
8026         !(fidflags & SMB_FID_SHARE_WRITE)) {
8027         cm_key_t key;
8028         LARGE_INTEGER LOffset, LLength;
8029         int sLockType;
8030
8031         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
8032         LOffset.LowPart = SMB_FID_QLOCK_LOW;
8033         LLength.HighPart = 0;
8034         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
8035
8036         /* Similar to what we do in handling NTCreateX.  We get a
8037            shared lock if we are only opening the file for reading. */
8038         if ((fidflags & SMB_FID_SHARE_READ) ||
8039             !(fidflags & SMB_FID_OPENWRITE)) {
8040             sLockType = LOCKING_ANDX_SHARED_LOCK;
8041         } else {
8042             sLockType = 0;
8043         }
8044
8045         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
8046         
8047         lock_ObtainWrite(&scp->rw);
8048         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
8049         lock_ReleaseWrite(&scp->rw);
8050
8051         if (code) {
8052             if (ldp)
8053                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8054             cm_ReleaseSCache(scp);
8055             cm_ReleaseUser(userp);
8056             /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
8057             smb_CloseFID(vcp, fidp, NULL, 0);
8058             smb_ReleaseFID(fidp);
8059             free(realPathp);
8060             return CM_ERROR_SHARING_VIOLATION;
8061         }
8062     }
8063
8064     /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
8065     if (ldp)
8066         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
8067
8068     lock_ObtainMutex(&fidp->mx);
8069     /* save a pointer to the vnode */
8070     fidp->scp = scp;
8071     lock_ObtainWrite(&scp->rw);
8072     scp->flags |= CM_SCACHEFLAG_SMB_FID;
8073     lock_ReleaseWrite(&scp->rw);
8074     osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
8075
8076     fidp->flags = fidflags;
8077
8078     /* remember if the file was newly created */
8079     if (created)
8080         fidp->flags |= SMB_FID_CREATED;
8081
8082     /* save parent dir and pathname for deletion or change notification */
8083     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
8084         fidp->flags |= SMB_FID_NTOPEN;
8085         fidp->NTopen_dscp = dscp;
8086         osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
8087         dscp = NULL;
8088         fidp->NTopen_pathp = cm_ClientStrDup(lastNamep);
8089     }
8090     fidp->NTopen_wholepathp = realPathp;
8091     lock_ReleaseMutex(&fidp->mx);
8092
8093     /* we don't need this any longer */
8094     if (dscp) 
8095         cm_ReleaseSCache(dscp);
8096
8097     cm_Open(scp, 0, userp);
8098
8099     /* set inp->fid so that later read calls in same msg can find fid */
8100     inp->fid = fidp->fid;
8101
8102     /* check whether we are required to send an extended response */
8103     if (!extendedRespRequired) {
8104         /* out parms */
8105         parmOffset = 8*4 + 39;
8106         parmOffset += 1;        /* pad to 4 */
8107         dataOffset = parmOffset + 70;
8108
8109         parmSlot = 1;
8110         outp->oddByte = 1;
8111         /* Total Parameter Count */
8112         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8113         /* Total Data Count */
8114         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8115         /* Parameter Count */
8116         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
8117         /* Parameter Offset */
8118         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8119         /* Parameter Displacement */
8120         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8121         /* Data Count */
8122         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8123         /* Data Offset */
8124         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8125         /* Data Displacement */
8126         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8127         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
8128         smb_SetSMBDataLength(outp, 70);
8129
8130         lock_ObtainRead(&scp->rw);
8131         outData = smb_GetSMBData(outp, NULL);
8132         outData++;                      /* round to get to parmOffset */
8133         *outData = 0; outData++;        /* oplock */
8134         *outData = 0; outData++;        /* reserved */
8135         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8136         *((ULONG *)outData) = openAction; outData += 4;
8137         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
8138         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8139         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
8140         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
8141         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
8142         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
8143         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8144         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8145         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8146         *((USHORT *)outData) = 0; outData += 2; /* filetype */
8147         *((USHORT *)outData) = 0; outData += 2; /* dev state */
8148         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8149                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8150                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8151         outData += 2;   /* is a dir? */
8152     } else {
8153         /* out parms */
8154         parmOffset = 8*4 + 39;
8155         parmOffset += 1;        /* pad to 4 */
8156         dataOffset = parmOffset + 104;
8157         
8158         parmSlot = 1;
8159         outp->oddByte = 1;
8160         /* Total Parameter Count */
8161         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8162         /* Total Data Count */
8163         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8164         /* Parameter Count */
8165         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
8166         /* Parameter Offset */
8167         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8168         /* Parameter Displacement */
8169         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8170         /* Data Count */
8171         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8172         /* Data Offset */
8173         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8174         /* Data Displacement */
8175         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8176         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
8177         smb_SetSMBDataLength(outp, 105);
8178         
8179         lock_ObtainRead(&scp->rw);
8180         outData = smb_GetSMBData(outp, NULL);
8181         outData++;                      /* round to get to parmOffset */
8182         *outData = 0; outData++;        /* oplock */
8183         *outData = 1; outData++;        /* response type */
8184         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
8185         *((ULONG *)outData) = openAction; outData += 4;
8186         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
8187         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
8188         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
8189         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
8190         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
8191         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
8192         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
8193         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
8194         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
8195         *((USHORT *)outData) = 0; outData += 2; /* filetype */
8196         *((USHORT *)outData) = 0; outData += 2; /* dev state */
8197         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
8198                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
8199                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
8200         outData += 1;   /* is a dir? */
8201         memset(outData,0,24); outData += 24; /* Volume ID and file ID */
8202         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
8203         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
8204     }
8205
8206     if ((fidp->flags & SMB_FID_EXECUTABLE) && 
8207          LargeIntegerGreaterThanZero(fidp->scp->length) && 
8208          !(scp->flags & CM_SCACHEFLAG_PREFETCHING)) {
8209         cm_QueueBKGRequest(fidp->scp, cm_BkgPrefetch, 0, 0,
8210                            fidp->scp->length.LowPart, fidp->scp->length.HighPart, 
8211                            userp);
8212     }
8213     lock_ReleaseRead(&scp->rw);
8214
8215     osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
8216
8217     cm_ReleaseUser(userp);
8218     smb_ReleaseFID(fidp);
8219
8220     /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
8221     /* leave scp held since we put it in fidp->scp */
8222     return 0;
8223 }
8224
8225 /* NT_TRANSACT_NOTIFY_CHANGE (SMB_COM_NT_TRANSACT) */
8226 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
8227         smb_packet_t *outp)
8228 {
8229     smb_packet_t *savedPacketp;
8230     ULONG filter; 
8231     USHORT fid, watchtree;
8232     smb_fid_t *fidp;
8233     cm_scache_t *scp;
8234         
8235     filter = smb_GetSMBParm(inp, 19) |
8236              (smb_GetSMBParm(inp, 20) << 16);
8237     fid = smb_GetSMBParm(inp, 21);
8238     watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
8239
8240     fidp = smb_FindFID(vcp, fid, 0);
8241     if (!fidp) {
8242         osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
8243         return CM_ERROR_BADFD;
8244     }
8245
8246     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
8247         smb_CloseFID(vcp, fidp, NULL, 0);
8248         smb_ReleaseFID(fidp);
8249         return CM_ERROR_NOSUCHFILE;
8250     }
8251
8252     /* Create a copy of the Directory Watch Packet to use when sending the
8253      * notification if in the future a matching change is detected.
8254      */
8255     savedPacketp = smb_CopyPacket(inp);
8256     if (vcp != savedPacketp->vcp) {
8257         smb_HoldVC(vcp);
8258         if (savedPacketp->vcp)
8259             smb_ReleaseVC(savedPacketp->vcp);
8260         savedPacketp->vcp = vcp;
8261     }
8262
8263     /* Add the watch to the list of events to send notifications for */
8264     lock_ObtainMutex(&smb_Dir_Watch_Lock);
8265     savedPacketp->nextp = smb_Directory_Watches;
8266     smb_Directory_Watches = savedPacketp;
8267     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8268
8269     scp = fidp->scp;
8270     osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%S\"", 
8271               fidp, scp, osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp));
8272     osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
8273              filter, fid, watchtree);
8274     if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8275         osi_Log0(smb_logp, "      Notify Change File Name");
8276     if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8277         osi_Log0(smb_logp, "      Notify Change Directory Name");
8278     if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8279         osi_Log0(smb_logp, "      Notify Change Attributes");
8280     if (filter & FILE_NOTIFY_CHANGE_SIZE)
8281         osi_Log0(smb_logp, "      Notify Change Size");
8282     if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8283         osi_Log0(smb_logp, "      Notify Change Last Write");
8284     if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8285         osi_Log0(smb_logp, "      Notify Change Last Access");
8286     if (filter & FILE_NOTIFY_CHANGE_CREATION)
8287         osi_Log0(smb_logp, "      Notify Change Creation");
8288     if (filter & FILE_NOTIFY_CHANGE_EA)
8289         osi_Log0(smb_logp, "      Notify Change Extended Attributes");
8290     if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8291         osi_Log0(smb_logp, "      Notify Change Security");
8292     if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8293         osi_Log0(smb_logp, "      Notify Change Stream Name");
8294     if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8295         osi_Log0(smb_logp, "      Notify Change Stream Size");
8296     if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8297         osi_Log0(smb_logp, "      Notify Change Stream Write");
8298
8299     lock_ObtainWrite(&scp->rw);
8300     if (watchtree)
8301         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
8302     else
8303         scp->flags |= CM_SCACHEFLAG_WATCHED;
8304     lock_ReleaseWrite(&scp->rw);
8305     smb_ReleaseFID(fidp);
8306
8307     outp->flags |= SMB_PACKETFLAG_NOSEND;
8308     return 0;
8309 }
8310
8311 unsigned char nullSecurityDesc[36] = {
8312     0x01,                               /* security descriptor revision */
8313     0x00,                               /* reserved, should be zero */
8314     0x00, 0x80,                         /* security descriptor control;
8315                                          * 0x8000 : self-relative format */
8316     0x14, 0x00, 0x00, 0x00,             /* offset of owner SID */
8317     0x1c, 0x00, 0x00, 0x00,             /* offset of group SID */
8318     0x00, 0x00, 0x00, 0x00,             /* offset of DACL would go here */
8319     0x00, 0x00, 0x00, 0x00,             /* offset of SACL would go here */
8320     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8321                                         /* "null SID" owner SID */
8322     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8323                                         /* "null SID" group SID */
8324 };      
8325
8326 /* NT_TRANSACT_QUERY_SECURITY_DESC (SMB_COM_NT_TRANSACT) */
8327 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8328 {
8329     int parmOffset, parmCount, dataOffset, dataCount;
8330     int parmSlot;
8331     int maxData;
8332     char *outData;
8333     char *parmp;
8334     USHORT *sparmp;
8335     ULONG *lparmp;
8336     USHORT fid;
8337     ULONG securityInformation;
8338
8339     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8340         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8341     parmp = inp->data + parmOffset;
8342     sparmp = (USHORT *) parmp;
8343     lparmp = (ULONG *) parmp;
8344
8345     fid = sparmp[0];
8346     securityInformation = lparmp[1];
8347
8348     maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8349         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8350
8351     if (maxData < 36)
8352         dataCount = 0;
8353     else
8354         dataCount = 36;
8355
8356     /* out parms */
8357     parmOffset = 8*4 + 39;
8358     parmOffset += 1;    /* pad to 4 */
8359     parmCount = 4;
8360     dataOffset = parmOffset + parmCount;
8361
8362     parmSlot = 1;
8363     outp->oddByte = 1;
8364     /* Total Parameter Count */
8365     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8366     /* Total Data Count */
8367     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8368     /* Parameter Count */
8369     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8370     /* Parameter Offset */
8371     smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8372     /* Parameter Displacement */
8373     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8374     /* Data Count */
8375     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8376     /* Data Offset */
8377     smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8378     /* Data Displacement */
8379     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8380     smb_SetSMBParmByte(outp, parmSlot, 0);      /* Setup Count */
8381     smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8382
8383     outData = smb_GetSMBData(outp, NULL);
8384     outData++;                  /* round to get to parmOffset */
8385     *((ULONG *)outData) = 36; outData += 4;     /* length */
8386
8387     if (maxData >= 36) {
8388         memcpy(outData, nullSecurityDesc, 36);
8389         outData += 36;
8390         return 0;
8391     } else
8392         return CM_ERROR_BUFFERTOOSMALL;
8393 }
8394
8395 /* SMB_COM_NT_TRANSACT
8396
8397    SMB_COM_NT_TRANSACT_SECONDARY should also be handled here.
8398  */
8399 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8400 {
8401     unsigned short function;
8402
8403     function = smb_GetSMBParm(inp, 18);
8404
8405     osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8406
8407     /* We can handle long names */
8408     if (vcp->flags & SMB_VCFLAG_USENT)
8409         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8410         
8411     switch (function) {
8412     case 1:                     /* NT_TRANSACT_CREATE */
8413         return smb_ReceiveNTTranCreate(vcp, inp, outp);
8414     case 2:                     /* NT_TRANSACT_IOCTL */
8415         osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8416         break;
8417     case 3:                     /* NT_TRANSACT_SET_SECURITY_DESC */
8418         osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8419         break;
8420     case 4:                     /* NT_TRANSACT_NOTIFY_CHANGE */
8421         return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8422     case 5:                     /* NT_TRANSACT_RENAME */
8423         osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8424         break;
8425     case 6:                     /* NT_TRANSACT_QUERY_SECURITY_DESC */
8426         return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8427     case 7:
8428         osi_Log0(smb_logp, "SMB NT Transact Query Quota - not implemented");
8429         break;
8430     case 8:
8431         osi_Log0(smb_logp, "SMB NT Transact Set Quota - not implemented");
8432         break;
8433     }
8434     return CM_ERROR_INVAL;
8435 }
8436
8437 /*
8438  * smb_NotifyChange -- find relevant change notification messages and
8439  *                     reply to them
8440  *
8441  * If we don't know the file name (i.e. a callback break), filename is
8442  * NULL, and we return a zero-length list.
8443  *
8444  * At present there is not a single call to smb_NotifyChange that 
8445  * has the isDirectParent parameter set to FALSE.  
8446  */
8447 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8448         cm_scache_t *dscp, clientchar_t *filename, clientchar_t *otherFilename,
8449         BOOL isDirectParent)
8450 {
8451     smb_packet_t *watch, *lastWatch, *nextWatch;
8452     ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen = 0;
8453     char *outData, *oldOutData;
8454     ULONG filter;
8455     USHORT fid, wtree;
8456     ULONG maxLen;
8457     BOOL twoEntries = FALSE;
8458     ULONG otherNameLen, oldParmCount = 0;
8459     DWORD otherAction;
8460     smb_fid_t *fidp;
8461
8462     /* Get ready for rename within directory */
8463     if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8464         twoEntries = TRUE;
8465         otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8466     }
8467
8468     osi_Log4(smb_logp,"in smb_NotifyChange for file [%S] dscp [%p] notification 0x%x parent %d",
8469              osi_LogSaveClientString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8470     if (action == 0)
8471         osi_Log0(smb_logp,"      FILE_ACTION_NONE");
8472     if (action == FILE_ACTION_ADDED)
8473         osi_Log0(smb_logp,"      FILE_ACTION_ADDED");
8474     if (action == FILE_ACTION_REMOVED)
8475         osi_Log0(smb_logp,"      FILE_ACTION_REMOVED");
8476     if (action == FILE_ACTION_MODIFIED)
8477         osi_Log0(smb_logp,"      FILE_ACTION_MODIFIED");
8478     if (action == FILE_ACTION_RENAMED_OLD_NAME)
8479         osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_OLD_NAME");
8480     if (action == FILE_ACTION_RENAMED_NEW_NAME)
8481         osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_NEW_NAME");
8482
8483     lock_ObtainMutex(&smb_Dir_Watch_Lock);
8484     watch = smb_Directory_Watches;
8485     while (watch) {
8486         filter = smb_GetSMBParm(watch, 19)
8487             | (smb_GetSMBParm(watch, 20) << 16);
8488         fid = smb_GetSMBParm(watch, 21);
8489         wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8490
8491         maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8492             | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8493
8494         /*
8495          * Strange hack - bug in NT Client and NT Server that we must emulate?
8496          */
8497         if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8498             filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8499
8500         fidp = smb_FindFID(watch->vcp, fid, 0);
8501         if (!fidp) {
8502             osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8503             lastWatch = watch;
8504             watch = watch->nextp;
8505             continue;
8506         }      
8507
8508         if (fidp->scp != dscp ||
8509             fidp->scp->flags & CM_SCACHEFLAG_DELETED ||
8510             (filter & notifyFilter) == 0 ||
8511             (!isDirectParent && !wtree)) 
8512         {
8513             osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8514             smb_ReleaseFID(fidp);
8515             lastWatch = watch;
8516             watch = watch->nextp;
8517             continue;
8518         }
8519         smb_ReleaseFID(fidp);
8520
8521         osi_Log4(smb_logp,
8522                   "Sending Change Notification for fid %d filter 0x%x wtree %d file %S",
8523                   fid, filter, wtree, osi_LogSaveClientString(smb_logp, filename));
8524         if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8525             osi_Log0(smb_logp, "      Notify Change File Name");
8526         if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8527             osi_Log0(smb_logp, "      Notify Change Directory Name");
8528         if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8529             osi_Log0(smb_logp, "      Notify Change Attributes");
8530         if (filter & FILE_NOTIFY_CHANGE_SIZE)
8531             osi_Log0(smb_logp, "      Notify Change Size");
8532         if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8533             osi_Log0(smb_logp, "      Notify Change Last Write");
8534         if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8535             osi_Log0(smb_logp, "      Notify Change Last Access");
8536         if (filter & FILE_NOTIFY_CHANGE_CREATION)
8537             osi_Log0(smb_logp, "      Notify Change Creation");
8538         if (filter & FILE_NOTIFY_CHANGE_EA)
8539             osi_Log0(smb_logp, "      Notify Change Extended Attributes");
8540         if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8541             osi_Log0(smb_logp, "      Notify Change Security");
8542         if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8543             osi_Log0(smb_logp, "      Notify Change Stream Name");
8544         if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8545             osi_Log0(smb_logp, "      Notify Change Stream Size");
8546         if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8547             osi_Log0(smb_logp, "      Notify Change Stream Write");
8548                      
8549         /* A watch can only be notified once.  Remove it from the list */
8550         nextWatch = watch->nextp;
8551         if (watch == smb_Directory_Watches)
8552             smb_Directory_Watches = nextWatch;
8553         else
8554             lastWatch->nextp = nextWatch;
8555
8556         /* Turn off WATCHED flag in dscp */
8557         lock_ObtainWrite(&dscp->rw);
8558         if (wtree)
8559             dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8560         else
8561             dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8562         lock_ReleaseWrite(&dscp->rw);
8563
8564         /* Convert to response packet */
8565         ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT;
8566 #ifdef SEND_CANONICAL_PATHNAMES
8567         ((smb_t *) watch)->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
8568 #endif
8569         ((smb_t *) watch)->wct = 0;
8570
8571         /* out parms */
8572         if (filename == NULL) {
8573             parmCount = 0;
8574         } else {
8575             nameLen = (ULONG)cm_ClientStrLen(filename);
8576             parmCount = 3*4 + nameLen*2;
8577             parmCount = (parmCount + 3) & ~3;   /* pad to 4 */
8578             if (twoEntries) {
8579                 otherNameLen = (ULONG)cm_ClientStrLen(otherFilename);
8580                 oldParmCount = parmCount;
8581                 parmCount += 3*4 + otherNameLen*2;
8582                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8583             }
8584             if (maxLen < parmCount)
8585                 parmCount = 0;  /* not enough room */
8586         }
8587         parmOffset = 8*4 + 39;
8588         parmOffset += 1;                        /* pad to 4 */
8589         dataOffset = parmOffset + parmCount;
8590
8591         parmSlot = 1;
8592         watch->oddByte = 1;
8593         /* Total Parameter Count */
8594         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8595         /* Total Data Count */
8596         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8597         /* Parameter Count */
8598         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8599         /* Parameter Offset */
8600         smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8601         /* Parameter Displacement */
8602         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8603         /* Data Count */
8604         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8605         /* Data Offset */
8606         smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8607         /* Data Displacement */
8608         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8609         smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8610         smb_SetSMBDataLength(watch, parmCount + 1);
8611
8612         if (parmCount != 0) {
8613             outData = smb_GetSMBData(watch, NULL);
8614             outData++;  /* round to get to parmOffset */
8615             oldOutData = outData;
8616             *((DWORD *)outData) = oldParmCount; outData += 4;
8617             /* Next Entry Offset */
8618             *((DWORD *)outData) = action; outData += 4;
8619             /* Action */
8620             *((DWORD *)outData) = nameLen*2; outData += 4;
8621             /* File Name Length */
8622
8623             smb_UnparseString(watch, outData, filename, NULL, 0);
8624             /* File Name */
8625
8626             if (twoEntries) {
8627                 outData = oldOutData + oldParmCount;
8628                 *((DWORD *)outData) = 0; outData += 4;
8629                 /* Next Entry Offset */
8630                 *((DWORD *)outData) = otherAction; outData += 4;
8631                 /* Action */
8632                 *((DWORD *)outData) = otherNameLen*2;
8633                 outData += 4;   /* File Name Length */
8634                 smb_UnparseString(watch, outData, otherFilename, NULL, 0);
8635             }       
8636         }
8637
8638         /*
8639          * If filename is null, we don't know the cause of the
8640          * change notification.  We return zero data (see above),
8641          * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8642          * (= 0x010C).  We set the error code here by hand, without
8643          * modifying wct and bcc.
8644          */
8645         if (filename == NULL) {
8646             ((smb_t *) watch)->rcls = 0x0C;
8647             ((smb_t *) watch)->reh = 0x01;
8648             ((smb_t *) watch)->errLow = 0;
8649             ((smb_t *) watch)->errHigh = 0;
8650             /* Set NT Status codes flag */
8651             ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8652         }
8653
8654         smb_SendPacket(watch->vcp, watch);
8655         smb_FreePacket(watch);
8656         watch = nextWatch;
8657     }
8658     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8659 }       
8660
8661 /* SMB_COM_NT_CANCEL */
8662 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8663 {
8664     unsigned char *replyWctp;
8665     smb_packet_t *watch, *lastWatch;
8666     USHORT fid, watchtree;
8667     smb_fid_t *fidp;
8668     cm_scache_t *scp;
8669
8670     osi_Log0(smb_logp, "SMB3 receive NT cancel");
8671
8672     lock_ObtainMutex(&smb_Dir_Watch_Lock);
8673     watch = smb_Directory_Watches;
8674     while (watch) {
8675         if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8676              && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8677              && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8678              && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8679             if (watch == smb_Directory_Watches)
8680                 smb_Directory_Watches = watch->nextp;
8681             else
8682                 lastWatch->nextp = watch->nextp;
8683             lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8684
8685             /* Turn off WATCHED flag in scp */
8686             fid = smb_GetSMBParm(watch, 21);
8687             watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8688
8689             if (vcp != watch->vcp)
8690                 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x", 
8691                           vcp, watch->vcp);
8692
8693             fidp = smb_FindFID(vcp, fid, 0);
8694             if (fidp) {
8695                 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %S", 
8696                          fid, watchtree,
8697                          (fidp ? osi_LogSaveClientString(smb_logp, fidp->NTopen_wholepathp) :_C("")));
8698
8699                 scp = fidp->scp;
8700                 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8701                 lock_ObtainWrite(&scp->rw);
8702                 if (watchtree)
8703                     scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8704                 else
8705                     scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8706                 lock_ReleaseWrite(&scp->rw);
8707                 smb_ReleaseFID(fidp);
8708             } else {
8709                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8710             }
8711
8712             /* assume STATUS32; return 0xC0000120 (CANCELED) */
8713             replyWctp = watch->wctp;
8714             *replyWctp++ = 0;
8715             *replyWctp++ = 0;
8716             *replyWctp++ = 0;
8717             ((smb_t *)watch)->rcls = 0x20;
8718             ((smb_t *)watch)->reh = 0x1;
8719             ((smb_t *)watch)->errLow = 0;
8720             ((smb_t *)watch)->errHigh = 0xC0;
8721             ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8722             smb_SendPacket(vcp, watch);
8723             smb_FreePacket(watch);
8724             return 0;
8725         }
8726         lastWatch = watch;
8727         watch = watch->nextp;
8728     }
8729     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8730
8731     return 0;
8732 }
8733
8734 /*
8735  * NT rename also does hard links.
8736  */
8737
8738 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8739 #define RENAME_FLAG_HARD_LINK                0x103
8740 #define RENAME_FLAG_RENAME                   0x104
8741 #define RENAME_FLAG_COPY                     0x105
8742
8743 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8744 {
8745     clientchar_t *oldPathp, *newPathp;
8746     long code = 0;
8747     char * tp;
8748     int attrs;
8749     int rename_type;
8750
8751     attrs = smb_GetSMBParm(inp, 0);
8752     rename_type = smb_GetSMBParm(inp, 1);
8753
8754     if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8755         osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8756         return CM_ERROR_NOACCESS;
8757     }
8758
8759     tp = smb_GetSMBData(inp, NULL);
8760     oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8761     newPathp = smb_ParseASCIIBlock(inp, tp, &tp, 0);
8762
8763     osi_Log3(smb_logp, "NTRename for [%S]->[%S] type [%s]",
8764              osi_LogSaveClientString(smb_logp, oldPathp),
8765              osi_LogSaveClientString(smb_logp, newPathp),
8766              ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8767
8768     if (rename_type == RENAME_FLAG_RENAME) {
8769         code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8770     } else { /* RENAME_FLAG_HARD_LINK */
8771         code = smb_Link(vcp,inp,oldPathp,newPathp);
8772     }
8773     return code;
8774 }
8775
8776 void smb3_Init()
8777 {
8778     lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8779 }
8780
8781 cm_user_t *smb_FindCMUserByName(clientchar_t *usern, clientchar_t *machine, afs_uint32 flags)
8782 {
8783     smb_username_t *unp;
8784     cm_user_t *     userp;
8785
8786     unp = smb_FindUserByName(usern, machine, flags);
8787     if (!unp->userp) {
8788         lock_ObtainMutex(&unp->mx);
8789         unp->userp = cm_NewUser();
8790         lock_ReleaseMutex(&unp->mx);
8791         osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8792     }  else     {
8793         osi_Log2(smb_logp,"smb_FindCMUserByName Found name[%S] machine[%S]",osi_LogSaveClientString(smb_logp,usern),osi_LogSaveClientString(smb_logp,machine));
8794     }
8795     userp = unp->userp;
8796     cm_HoldUser(userp);
8797     smb_ReleaseUsername(unp);
8798     return userp;
8799 }
8800