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