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