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