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