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