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