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