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