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