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