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