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