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