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