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