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