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