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