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