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