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