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