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