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