ff8ff13f9d31c2e0c09557e05cfd3f2a063c6b7f
[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,"\r\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,"\r\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 && code != CM_ERROR_BPLUS_NOMATCH) {
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     afs_int32 mustFake = 0;
3653
3654     code = cm_FindACLCache(dscp, userp, &rights);
3655     if (code == 0 && !(rights & PRSFS_READ))
3656         mustFake = 1;
3657     else if (code == -1) {
3658         lock_ObtainMutex(&dscp->mx);
3659         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
3660                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3661         lock_ReleaseMutex(&dscp->mx);
3662         if (code == CM_ERROR_NOACCESS) {
3663             mustFake = 1;
3664             code = 0;
3665         }
3666     }
3667     if (code)
3668         return code;
3669
3670     for(patchp = *dirPatchespp; patchp; patchp =
3671          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3672         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3673         if (code) 
3674             continue;
3675
3676         lock_ObtainMutex(&scp->mx);
3677         if (mustFake == 0)
3678             code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3679                              CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3680         if (mustFake || code) { 
3681             lock_ReleaseMutex(&scp->mx);
3682
3683             dptr = patchp->dptr;
3684
3685             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3686                errors in the client. */
3687             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3688                 /* 1969-12-31 23:59:59 +00 */
3689                 ft.dwHighDateTime = 0x19DB200;
3690                 ft.dwLowDateTime = 0x5BB78980;
3691
3692                 /* copy to Creation Time */
3693                 *((FILETIME *)dptr) = ft;
3694                 dptr += 8;
3695
3696                 /* copy to Last Access Time */
3697                 *((FILETIME *)dptr) = ft;
3698                 dptr += 8;
3699
3700                 /* copy to Last Write Time */
3701                 *((FILETIME *)dptr) = ft;
3702                 dptr += 8;
3703
3704                 /* copy to Change Time */
3705                 *((FILETIME *)dptr) = ft;
3706                 dptr += 24;
3707
3708                 switch (scp->fileType) {
3709                 case CM_SCACHETYPE_DIRECTORY:
3710                 case CM_SCACHETYPE_MOUNTPOINT:
3711                 case CM_SCACHETYPE_SYMLINK:
3712                 case CM_SCACHETYPE_INVALID:
3713                     *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
3714                     break;
3715                 default:
3716                     /* if we get here we either have a normal file
3717                      * or we have a file for which we have never 
3718                      * received status info.  In this case, we can
3719                      * check the even/odd value of the entry's vnode.
3720                      * even means it is to be treated as a directory
3721                      * and odd means it is to be treated as a file.
3722                      */
3723                     if (mustFake && (scp->fid.vnode & 0x1))
3724                         *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
3725                     else
3726                         *((u_long *)dptr) = SMB_ATTR_NORMAL;
3727                         
3728                 }
3729                 /* merge in hidden attribute */
3730                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3731                     *((u_long *)dptr) |= SMB_ATTR_HIDDEN;
3732                 }
3733                 dptr += 4;
3734             } else {
3735                 /* 1969-12-31 23:59:58 +00*/
3736                 dosTime = 0xEBBFBF7D;
3737
3738                 /* and copy out date */
3739                 shortTemp = (dosTime>>16) & 0xffff;
3740                 *((u_short *)dptr) = shortTemp;
3741                 dptr += 2;
3742
3743                 /* copy out creation time */
3744                 shortTemp = dosTime & 0xffff;
3745                 *((u_short *)dptr) = shortTemp;
3746                 dptr += 2;
3747
3748                 /* and copy out date */
3749                 shortTemp = (dosTime>>16) & 0xffff;
3750                 *((u_short *)dptr) = shortTemp;
3751                 dptr += 2;
3752                         
3753                 /* copy out access time */
3754                 shortTemp = dosTime & 0xffff;
3755                 *((u_short *)dptr) = shortTemp;
3756                 dptr += 2;
3757
3758                 /* and copy out date */
3759                 shortTemp = (dosTime>>16) & 0xffff;
3760                 *((u_short *)dptr) = shortTemp;
3761                 dptr += 2;
3762                         
3763                 /* copy out mod time */
3764                 shortTemp = dosTime & 0xffff;
3765                 *((u_short *)dptr) = shortTemp;
3766                 dptr += 10;
3767
3768                 /* set the attribute */
3769                 switch (scp->fileType) {
3770                 case CM_SCACHETYPE_DIRECTORY:
3771                 case CM_SCACHETYPE_MOUNTPOINT:
3772                 case CM_SCACHETYPE_SYMLINK:
3773                 case CM_SCACHETYPE_INVALID:
3774                     attr = SMB_ATTR_DIRECTORY;
3775                 default:
3776                     attr = SMB_ATTR_NORMAL;
3777                 }
3778                 /* merge in hidden (dot file) attribute */
3779                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3780                     attr |= SMB_ATTR_HIDDEN;
3781                 }       
3782                 *dptr++ = attr & 0xff;
3783                 *dptr++ = (attr >> 8) & 0xff;
3784             }
3785             
3786             cm_ReleaseSCache(scp);
3787             continue;
3788         }
3789         
3790         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3791
3792         /* now watch for a symlink */
3793         code = 0;
3794         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3795             lock_ReleaseMutex(&scp->mx);
3796             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3797             if (code == 0) {
3798                 /* we have a more accurate file to use (the
3799                  * target of the symbolic link).  Otherwise,
3800                  * we'll just use the symlink anyway.
3801                  */
3802                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3803                           scp, targetScp);
3804                 cm_ReleaseSCache(scp);
3805                 scp = targetScp;
3806             }
3807             lock_ObtainMutex(&scp->mx);
3808         }
3809
3810         dptr = patchp->dptr;
3811
3812         if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3813             /* get filetime */
3814             smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3815
3816             /* copy to Creation Time */
3817             *((FILETIME *)dptr) = ft;
3818             dptr += 8;
3819
3820             /* copy to Last Access Time */
3821             *((FILETIME *)dptr) = ft;
3822             dptr += 8;
3823
3824             /* copy to Last Write Time */
3825             *((FILETIME *)dptr) = ft;
3826             dptr += 8;
3827
3828             /* copy to Change Time */
3829             *((FILETIME *)dptr) = ft;
3830             dptr += 8;
3831
3832             /* Use length for both file length and alloc length */
3833             *((LARGE_INTEGER *)dptr) = scp->length;
3834             dptr += 8;
3835             *((LARGE_INTEGER *)dptr) = scp->length;
3836             dptr += 8;
3837
3838             /* Copy attributes */
3839             lattr = smb_ExtAttributes(scp);
3840             if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3841                 if (lattr == SMB_ATTR_NORMAL)
3842                     lattr = SMB_ATTR_DIRECTORY;
3843                 else
3844                     lattr |= SMB_ATTR_DIRECTORY;
3845             }
3846             /* merge in hidden (dot file) attribute */
3847             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3848                 if (lattr == SMB_ATTR_NORMAL)
3849                     lattr = SMB_ATTR_HIDDEN;
3850                 else
3851                     lattr |= SMB_ATTR_HIDDEN;
3852             }
3853             *((u_long *)dptr) = lattr;
3854             dptr += 4;
3855         } else {
3856             /* get dos time */
3857             smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3858
3859             /* and copy out date */
3860             shortTemp = (dosTime>>16) & 0xffff;
3861             *((u_short *)dptr) = shortTemp;
3862             dptr += 2;
3863
3864             /* copy out creation time */
3865             shortTemp = dosTime & 0xffff;
3866             *((u_short *)dptr) = shortTemp;
3867             dptr += 2;
3868
3869             /* and copy out date */
3870             shortTemp = (dosTime>>16) & 0xffff;
3871             *((u_short *)dptr) = shortTemp;
3872             dptr += 2;
3873
3874             /* copy out access time */
3875             shortTemp = dosTime & 0xffff;
3876             *((u_short *)dptr) = shortTemp;
3877             dptr += 2;
3878
3879             /* and copy out date */
3880             shortTemp = (dosTime>>16) & 0xffff;
3881             *((u_short *)dptr) = shortTemp;
3882             dptr += 2;
3883
3884             /* copy out mod time */
3885             shortTemp = dosTime & 0xffff;
3886             *((u_short *)dptr) = shortTemp;
3887             dptr += 2;
3888
3889             /* copy out file length and alloc length,
3890              * using the same for both
3891              */
3892             *((u_long *)dptr) = scp->length.LowPart;
3893             dptr += 4;
3894             *((u_long *)dptr) = scp->length.LowPart;
3895             dptr += 4;
3896
3897             /* finally copy out attributes as short */
3898             attr = smb_Attributes(scp);
3899             /* merge in hidden (dot file) attribute */
3900             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3901                 if (lattr == SMB_ATTR_NORMAL)
3902                     lattr = SMB_ATTR_HIDDEN;
3903                 else
3904                     lattr |= SMB_ATTR_HIDDEN;
3905             }
3906             *dptr++ = attr & 0xff;
3907             *dptr++ = (attr >> 8) & 0xff;
3908         }
3909
3910         lock_ReleaseMutex(&scp->mx);
3911         cm_ReleaseSCache(scp);
3912     }
3913         
3914     /* now free the patches */
3915     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3916         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3917         free(patchp);
3918     }
3919         
3920     /* and mark the list as empty */
3921     *dirPatchespp = NULL;
3922
3923     return code;
3924 }
3925
3926 #ifndef USE_OLD_MATCHING
3927 // char table for case insensitive comparison
3928 char mapCaseTable[256];
3929
3930 VOID initUpperCaseTable(VOID) 
3931 {
3932     int i;
3933     for (i = 0; i < 256; ++i) 
3934        mapCaseTable[i] = toupper(i);
3935     // make '"' match '.' 
3936     mapCaseTable[(int)'"'] = toupper('.');
3937     // make '<' match '*' 
3938     mapCaseTable[(int)'<'] = toupper('*');
3939     // make '>' match '?' 
3940     mapCaseTable[(int)'>'] = toupper('?');    
3941 }
3942
3943 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3944 // name 'name'.
3945 // Note : this procedure works recursively calling itself.
3946 // Parameters
3947 // PSZ pattern    : string containing metacharacters.
3948 // PSZ name       : file name to be compared with 'pattern'.
3949 // Return value
3950 // BOOL : TRUE/FALSE (match/mistmatch)
3951
3952 BOOL 
3953 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold) 
3954 {
3955     PSZ pename;         // points to the last 'name' character
3956     PSZ p;
3957     pename = name + strlen(name) - 1;
3958     while (*name) {
3959         switch (*pattern) {
3960         case '?':
3961             ++pattern;
3962             if (*name == '.')
3963                 continue;
3964             ++name;
3965             break;
3966          case '*':
3967             ++pattern;
3968             if (*pattern == '\0')
3969                 return TRUE;
3970             for (p = pename; p >= name; --p) {
3971                 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3972                      !casefold && (*p == *pattern)) &&
3973                      szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3974                     return TRUE;
3975             } /* endfor */
3976             return FALSE;
3977         default:
3978             if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3979                 (!casefold && *name != *pattern))
3980                 return FALSE;
3981             ++pattern, ++name;
3982             break;
3983         } /* endswitch */
3984     } /* endwhile */ 
3985
3986     /* if all we have left are wildcards, then we match */
3987     for (;*pattern; pattern++) {
3988         if (*pattern != '*' && *pattern != '?')
3989             return FALSE;
3990     }
3991     return TRUE;
3992 }
3993
3994 /* do a case-folding search of the star name mask with the name in namep.
3995  * Return 1 if we match, otherwise 0.
3996  */
3997 int smb_V3MatchMask(char *namep, char *maskp, int flags) 
3998 {
3999     char * newmask;
4000     int    i, j, star, qmark, casefold, retval;
4001
4002     /* make sure we only match 8.3 names, if requested */
4003     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
4004         return 0;
4005     
4006     casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
4007
4008     /* optimize the pattern:
4009      * if there is a mixture of '?' and '*',
4010      * for example  the sequence "*?*?*?*"
4011      * must be turned into the form "*"
4012      */
4013     newmask = (char *)malloc(strlen(maskp)+1);
4014     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
4015         switch ( maskp[i] ) {
4016         case '?':
4017         case '>':
4018             qmark++;
4019             break;
4020         case '<':
4021         case '*':
4022             star++;
4023             break;
4024         default:
4025             if ( star ) {
4026                 newmask[j++] = '*';
4027             } else if ( qmark ) {
4028                 while ( qmark-- )
4029                     newmask[j++] = '?';
4030             }
4031             newmask[j++] = maskp[i];
4032             star = 0;
4033             qmark = 0;
4034         }
4035     }
4036     if ( star ) {
4037         newmask[j++] = '*';
4038     } else if ( qmark ) {
4039         while ( qmark-- )
4040             newmask[j++] = '?';
4041     }
4042     newmask[j++] = '\0';
4043
4044     retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
4045
4046     free(newmask);
4047     return retval;
4048 }
4049
4050 #else /* USE_OLD_MATCHING */
4051 /* do a case-folding search of the star name mask with the name in namep.
4052  * Return 1 if we match, otherwise 0.
4053  */
4054 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4055 {
4056     unsigned char tcp1, tcp2;   /* Pattern characters */
4057     unsigned char tcn1;         /* Name characters */
4058     int sawDot = 0, sawStar = 0, req8dot3 = 0;
4059     char *starNamep, *starMaskp;
4060     static char nullCharp[] = {0};
4061     int casefold = flags & CM_FLAG_CASEFOLD;
4062
4063     /* make sure we only match 8.3 names, if requested */
4064     req8dot3 = (flags & CM_FLAG_8DOT3);
4065     if (req8dot3 && !cm_Is8Dot3(namep)) 
4066         return 0;
4067
4068     /* loop */
4069     while (1) {
4070         /* Next pattern character */
4071         tcp1 = *maskp++;
4072
4073         /* Next name character */
4074         tcn1 = *namep;
4075
4076         if (tcp1 == 0) {
4077             /* 0 - end of pattern */
4078             if (tcn1 == 0)
4079                 return 1;
4080             else
4081                 return 0;
4082         }
4083         else if (tcp1 == '.' || tcp1 == '"') {
4084             if (sawDot) {
4085                 if (tcn1 == '.') {
4086                     namep++;
4087                     continue;
4088                 } else
4089                     return 0;
4090             }
4091             else {
4092                 /*
4093                  * first dot in pattern;
4094                  * must match dot or end of name
4095                  */
4096                 sawDot = 1;
4097                 if (tcn1 == 0)
4098                     continue;
4099                 else if (tcn1 == '.') {
4100                     sawStar = 0;
4101                     namep++;
4102                     continue;
4103                 }
4104                 else
4105                     return 0;
4106             }
4107         }
4108         else if (tcp1 == '?') {
4109             if (tcn1 == 0 || tcn1 == '.')
4110                 return 0;
4111             namep++;
4112             continue;
4113         }
4114         else if (tcp1 == '>') {
4115             if (tcn1 != 0 && tcn1 != '.')
4116                 namep++;
4117             continue;
4118         }
4119         else if (tcp1 == '*' || tcp1 == '<') {
4120             tcp2 = *maskp++;
4121             if (tcp2 == 0)
4122                 return 1;
4123             else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4124                 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4125                     tcn1 = *++namep;
4126                 if (tcn1 == 0) {
4127                     if (sawDot)
4128                         return 0;
4129                     else
4130                         continue;
4131                 }
4132                 else {
4133                     namep++;
4134                     continue;
4135                 }
4136             }
4137             else {
4138                 /*
4139                  * pattern character after '*' is not null or
4140                  * period.  If it is '?' or '>', we are not
4141                  * going to understand it.  If it is '*' or
4142                  * '<', we are going to skip over it.  None of
4143                  * these are likely, I hope.
4144                  */
4145                 /* skip over '*' and '<' */
4146                 while (tcp2 == '*' || tcp2 == '<')
4147                     tcp2 = *maskp++;
4148
4149                 /* skip over characters that don't match tcp2 */
4150                 while (req8dot3 && tcn1 != '.' && tcn1 != 0 && 
4151                         ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
4152                           (!casefold && tcn1 != tcp2)))
4153                     tcn1 = *++namep;
4154
4155                 /* No match */
4156                 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4157                     return 0;
4158
4159                 /* Remember where we are */
4160                 sawStar = 1;
4161                 starMaskp = maskp;
4162                 starNamep = namep;
4163
4164                 namep++;
4165                 continue;
4166             }
4167         }
4168         else {
4169             /* tcp1 is not a wildcard */
4170             if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
4171                  (!casefold && tcn1 == tcp1)) {
4172                 /* they match */
4173                 namep++;
4174                 continue;
4175             }
4176             /* if trying to match a star pattern, go back */
4177             if (sawStar) {
4178                 maskp = starMaskp - 2;
4179                 namep = starNamep + 1;
4180                 sawStar = 0;
4181                 continue;
4182             }
4183             /* that's all */
4184             return 0;
4185         }
4186     }
4187 }
4188 #endif /* USE_OLD_MATCHING */
4189
4190 /* smb_ReceiveTran2SearchDir implements both 
4191  * Tran2_Find_First and Tran2_Find_Next
4192  */
4193 #define TRAN2_FIND_FLAG_CLOSE_SEARCH            0x01
4194 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END     0x02
4195 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS      0x04
4196 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH         0x08
4197 #define TRAN2_FIND_FLAG_BACKUP_INTENT           0x10
4198
4199 /* this is an optimized handler for T2SearchDir that handles the case
4200    where there are no wildcards in the search path.  I.e. an
4201    application is using FindFirst(Ex) to get information about a
4202    single file or directory.  It will attempt to do a single lookup.
4203    If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4204    the usual mechanism. 
4205    
4206    This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4207    */
4208 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4209 {
4210     int attribute;
4211     long nextCookie;
4212     long code = 0, code2 = 0;
4213     char *pathp;
4214     int maxCount;
4215     smb_dirListPatch_t *dirListPatchesp;
4216     smb_dirListPatch_t *curPatchp;
4217     long orbytes;                       /* # of bytes in this output record */
4218     long ohbytes;                       /* # of bytes, except file name */
4219     long onbytes;                       /* # of bytes in name, incl. term. null */
4220     cm_scache_t *scp = NULL;
4221     cm_scache_t *targetscp = NULL;
4222     cm_user_t *userp = NULL;
4223     char *op;                           /* output data ptr */
4224     char *origOp;                       /* original value of op */
4225     cm_space_t *spacep;                 /* for pathname buffer */
4226     long maxReturnData;                 /* max # of return data */
4227     long maxReturnParms;                /* max # of return parms */
4228     long bytesInBuffer;                 /* # data bytes in the output buffer */
4229     char *maskp;                        /* mask part of path */
4230     int infoLevel;
4231     int searchFlags;
4232     int eos;
4233     smb_tran2Packet_t *outp;            /* response packet */
4234     char *tidPathp;
4235     int align;
4236     char shortName[13];                 /* 8.3 name if needed */
4237     int NeedShortName;
4238     char *shortNameEnd;
4239     cm_req_t req;
4240     char * s;
4241
4242     cm_InitReq(&req);
4243
4244     eos = 0;
4245     osi_assert(p->opcode == 1);
4246
4247     /* find first; obtain basic parameters from request */
4248
4249     /* note that since we are going to failover to regular
4250      * processing at smb_ReceiveTran2SearchDir(), we shouldn't
4251      * modify any of the input parameters here. */
4252     attribute = p->parmsp[0];
4253     maxCount = p->parmsp[1];
4254     infoLevel = p->parmsp[3];
4255     searchFlags = p->parmsp[2];
4256     pathp = ((char *) p->parmsp) + 12;  /* points to path */
4257     nextCookie = 0;
4258     maskp = strrchr(pathp, '\\');
4259     if (maskp == NULL) 
4260         maskp = pathp;
4261     else 
4262         maskp++;        /* skip over backslash */
4263     /* track if this is likely to match a lot of entries */
4264
4265     osi_Log2(smb_logp, "smb_T2SearchDirSingle : path[%s], mask[%s]",
4266             osi_LogSaveString(smb_logp, pathp),
4267             osi_LogSaveString(smb_logp, maskp));
4268
4269     switch ( infoLevel ) {
4270     case SMB_INFO_STANDARD:
4271         s = "InfoStandard";
4272         break;
4273     case SMB_INFO_QUERY_EA_SIZE:
4274         s = "InfoQueryEaSize";
4275         break;
4276     case SMB_INFO_QUERY_EAS_FROM_LIST:
4277         s = "InfoQueryEasFromList";
4278         break;
4279     case SMB_FIND_FILE_DIRECTORY_INFO:
4280         s = "FindFileDirectoryInfo";
4281         break;
4282     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4283         s = "FindFileFullDirectoryInfo";
4284         break;
4285     case SMB_FIND_FILE_NAMES_INFO:
4286         s = "FindFileNamesInfo";
4287         break;
4288     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4289         s = "FindFileBothDirectoryInfo";
4290         break;
4291     default:
4292         s = "unknownInfoLevel";
4293     }
4294
4295     osi_Log1(smb_logp, "smb_T2SearchDirSingle info level: %s", s);
4296
4297     osi_Log4(smb_logp,
4298              "smb_T2SearchDirSingle attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4299              attribute, infoLevel, maxCount, searchFlags);
4300     
4301     if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4302         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4303         return CM_ERROR_INVAL;
4304     }
4305
4306     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4307         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;     /* no resume keys */
4308
4309     dirListPatchesp = NULL;
4310
4311     maxReturnData = p->maxReturnData;
4312     maxReturnParms = 10;        /* return params for findfirst, which
4313                                    is the only one we handle.*/
4314
4315 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4316     if (maxReturnData > 6000) 
4317         maxReturnData = 6000;
4318 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4319
4320     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4321                                       maxReturnData);
4322
4323     osi_Log2(smb_logp, "T2SDSingle search dir count %d [%s]",
4324              maxCount, osi_LogSaveString(smb_logp, pathp));
4325         
4326     /* bail out if request looks bad */
4327     if (!pathp) {
4328         smb_FreeTran2Packet(outp);
4329         return CM_ERROR_BADSMB;
4330     }
4331         
4332     userp = smb_GetTran2User(vcp, p);
4333     if (!userp) {
4334         osi_Log1(smb_logp, "T2SDSingle search dir unable to resolve user [%d]", p->uid);
4335         smb_FreeTran2Packet(outp);
4336         return CM_ERROR_BADSMB;
4337     }
4338
4339     /* try to get the vnode for the path name next */
4340     spacep = cm_GetSpace();
4341     smb_StripLastComponent(spacep->data, NULL, pathp);
4342     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4343     if (code) {
4344         cm_ReleaseUser(userp);
4345         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4346         smb_FreeTran2Packet(outp);
4347         return 0;
4348     }
4349
4350     code = cm_NameI(cm_data.rootSCachep, spacep->data,
4351                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4352                     userp, tidPathp, &req, &scp);
4353     cm_FreeSpace(spacep);
4354
4355     if (code) {
4356         cm_ReleaseUser(userp);
4357         smb_SendTran2Error(vcp, p, opx, code);
4358         smb_FreeTran2Packet(outp);
4359         return 0;
4360     }
4361
4362 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4363     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4364         cm_ReleaseSCache(scp);
4365         cm_ReleaseUser(userp);
4366         if ( WANTS_DFS_PATHNAMES(p) )
4367             code = CM_ERROR_PATH_NOT_COVERED;
4368         else
4369             code = CM_ERROR_BADSHARENAME;
4370         smb_SendTran2Error(vcp, p, opx, code);
4371         smb_FreeTran2Packet(outp);
4372         return 0;
4373     }
4374 #endif /* DFS_SUPPORT */
4375     osi_Log1(smb_logp,"T2SDSingle scp 0x%p", scp);
4376
4377     /* now do a single case sensitive lookup for the file in question */
4378     code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE, userp, &req, &targetscp);
4379
4380     /* if a case sensitive match failed, we try a case insensitive one
4381        next. */
4382     if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
4383         code = cm_Lookup(scp, maskp, CM_FLAG_NOMOUNTCHASE | CM_FLAG_CASEFOLD, userp, &req, &targetscp);
4384     }
4385
4386     if (code == 0 && targetscp->fid.vnode == 0) {
4387         cm_ReleaseSCache(targetscp);
4388         code = CM_ERROR_NOSUCHFILE;
4389     }
4390
4391     if (code) {
4392         /* if we can't find the directory entry, this block will
4393            return CM_ERROR_NOSUCHFILE, which we will pass on to
4394            smb_ReceiveTran2SearchDir(). */
4395         cm_ReleaseSCache(scp);
4396         cm_ReleaseUser(userp);
4397         if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4398             smb_SendTran2Error(vcp, p, opx, code);
4399             code = 0;
4400         }
4401         smb_FreeTran2Packet(outp);
4402         return code;
4403     }
4404
4405     /* now that we have the target in sight, we proceed with filling
4406        up the return data. */
4407
4408     op = origOp = outp->datap;
4409     bytesInBuffer = 0;
4410
4411     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4412         /* skip over resume key */
4413         op += 4;
4414     }
4415
4416     if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4417         && targetscp->fid.vnode != 0
4418         && !cm_Is8Dot3(maskp)) {
4419
4420         cm_dirFid_t dfid;
4421         dfid.vnode = htonl(targetscp->fid.vnode);
4422         dfid.unique = htonl(targetscp->fid.unique);
4423
4424         cm_Gen8Dot3NameInt(maskp, &dfid, shortName, &shortNameEnd);
4425         NeedShortName = 1;
4426     } else {
4427         NeedShortName = 0;
4428     }
4429
4430     osi_Log4(smb_logp, "T2SDSingle dir vn %u uniq %u name %s (%s)",
4431               htonl(targetscp->fid.vnode),
4432               htonl(targetscp->fid.unique),
4433               osi_LogSaveString(smb_logp, pathp),
4434               NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4435
4436     /* Eliminate entries that don't match requested attributes */
4437     if (smb_hideDotFiles && !(attribute & SMB_ATTR_HIDDEN) &&
4438         smb_IsDotFile(maskp)) {
4439
4440         code = CM_ERROR_NOSUCHFILE;
4441         osi_Log0(smb_logp, "T2SDSingle skipping hidden file");
4442         goto skip_file;
4443
4444     }
4445
4446     if (!(attribute & SMB_ATTR_DIRECTORY) &&
4447         (targetscp->fileType == CM_SCACHETYPE_DIRECTORY ||
4448          targetscp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4449          targetscp->fileType == CM_SCACHETYPE_DFSLINK ||
4450          targetscp->fileType == CM_SCACHETYPE_INVALID)) {
4451
4452         code = CM_ERROR_NOSUCHFILE;
4453         osi_Log0(smb_logp, "T2SDSingle skipping directory or bad link");
4454         goto skip_file;
4455
4456     }
4457
4458     /* Check if the name will fit */
4459     if (infoLevel < 0x101)
4460         ohbytes = 23;           /* pre-NT */
4461     else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4462         ohbytes = 12;           /* NT names only */
4463     else
4464         ohbytes = 64;           /* NT */
4465
4466     if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4467         ohbytes += 26;          /* Short name & length */
4468
4469     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4470         ohbytes += 4;           /* if resume key required */
4471     }
4472
4473     if (infoLevel != SMB_INFO_STANDARD
4474         && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4475         && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4476         ohbytes += 4;           /* EASIZE */
4477
4478     /* add header to name & term. null */
4479     onbytes = strlen(maskp);
4480     orbytes = ohbytes + onbytes + 1;
4481
4482     /* now, we round up the record to a 4 byte alignment, and we make
4483      * sure that we have enough room here for even the aligned version
4484      * (so we don't have to worry about an * overflow when we pad
4485      * things out below).  That's the reason for the alignment
4486      * arithmetic below.
4487      */
4488     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4489         align = (4 - (orbytes & 3)) & 3;
4490     else
4491         align = 0;
4492
4493     if (orbytes + align > maxReturnData) {
4494
4495         /* even though this request is unlikely to succeed with a
4496            failover, we do it anyway. */
4497         code = CM_ERROR_NOSUCHFILE;
4498         osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4499                  maxReturnData);
4500         goto skip_file;
4501     }
4502
4503     /* this is one of the entries to use: it is not deleted and it
4504      * matches the star pattern we're looking for.  Put out the name,
4505      * preceded by its length.
4506      */
4507     /* First zero everything else */
4508     memset(origOp, 0, ohbytes);
4509
4510     if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4511         *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4512     else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4513         *((u_long *)(op + 8)) = onbytes;
4514     else
4515         *((u_long *)(op + 60)) = onbytes;
4516     strcpy(origOp+ohbytes, maskp);
4517     if (smb_StoreAnsiFilenames)
4518         CharToOem(origOp+ohbytes, origOp+ohbytes);
4519
4520     /* Short name if requested and needed */
4521     if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4522         if (NeedShortName) {
4523             strcpy(op + 70, shortName);
4524             if (smb_StoreAnsiFilenames)
4525                 CharToOem(op + 70, op + 70);
4526             *(op + 68) = (char)(shortNameEnd - shortName);
4527         }
4528     }
4529
4530     /* NextEntryOffset and FileIndex */
4531     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4532         int entryOffset = orbytes + align;
4533         *((u_long *)op) = 0;
4534         *((u_long *)(op+4)) = 0;
4535     }
4536
4537     if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4538         curPatchp = malloc(sizeof(*curPatchp));
4539         osi_QAdd((osi_queue_t **) &dirListPatchesp,
4540                  &curPatchp->q);
4541         curPatchp->dptr = op;
4542         if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4543             curPatchp->dptr += 8;
4544
4545         if (smb_hideDotFiles && smb_IsDotFile(maskp)) {
4546             curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4547         } else {
4548             curPatchp->flags = 0;
4549         }
4550
4551         curPatchp->fid.cell = targetscp->fid.cell;
4552         curPatchp->fid.volume = targetscp->fid.volume;
4553         curPatchp->fid.vnode = targetscp->fid.vnode;
4554         curPatchp->fid.unique = targetscp->fid.unique;
4555
4556         /* temp */
4557         curPatchp->dep = NULL;
4558     }   
4559
4560     if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
4561         /* put out resume key */
4562         *((u_long *)origOp) = 0;
4563     }
4564
4565     /* Adjust byte ptr and count */
4566     origOp += orbytes;  /* skip entire record */
4567     bytesInBuffer += orbytes;
4568
4569     /* and pad the record out */
4570     while (--align >= 0) {
4571         *origOp++ = 0;
4572         bytesInBuffer++;
4573     }
4574
4575     /* apply the patches */
4576     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp, &req);
4577
4578     outp->parmsp[0] = 0;
4579     outp->parmsp[1] = 1;        /* number of names returned */
4580     outp->parmsp[2] = 1;        /* end of search */
4581     outp->parmsp[3] = 0;        /* nothing wrong with EAS */
4582     outp->parmsp[4] = 0;
4583
4584     outp->totalParms = 10;      /* in bytes */
4585
4586     outp->totalData = bytesInBuffer;
4587
4588     osi_Log0(smb_logp, "T2SDSingle done.");
4589
4590     if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
4591         if (code)
4592             smb_SendTran2Error(vcp, p, opx, code);
4593         else
4594             smb_SendTran2Packet(vcp, outp, opx);
4595         code = 0;
4596     }
4597
4598  skip_file:
4599     smb_FreeTran2Packet(outp);
4600     cm_ReleaseSCache(scp);
4601     cm_ReleaseSCache(targetscp);
4602     cm_ReleaseUser(userp);
4603
4604     return code;
4605 }
4606
4607
4608 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4609 {
4610     int attribute;
4611     long nextCookie;
4612     char *tp;
4613     long code = 0, code2 = 0;
4614     char *pathp;
4615     cm_dirEntry_t *dep;
4616     int maxCount;
4617     smb_dirListPatch_t *dirListPatchesp;
4618     smb_dirListPatch_t *curPatchp;
4619     cm_buf_t *bufferp;
4620     long temp;
4621     long orbytes;                       /* # of bytes in this output record */
4622     long ohbytes;                       /* # of bytes, except file name */
4623     long onbytes;                       /* # of bytes in name, incl. term. null */
4624     osi_hyper_t dirLength;
4625     osi_hyper_t bufferOffset;
4626     osi_hyper_t curOffset;
4627     osi_hyper_t thyper;
4628     smb_dirSearch_t *dsp;
4629     cm_scache_t *scp;
4630     long entryInDir;
4631     long entryInBuffer;
4632     cm_pageHeader_t *pageHeaderp;
4633     cm_user_t *userp = NULL;
4634     int slotInPage;
4635     int returnedNames;
4636     long nextEntryCookie;
4637     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
4638     char *op;                   /* output data ptr */
4639     char *origOp;                       /* original value of op */
4640     cm_space_t *spacep;         /* for pathname buffer */
4641     long maxReturnData;         /* max # of return data */
4642     long maxReturnParms;                /* max # of return parms */
4643     long bytesInBuffer;         /* # data bytes in the output buffer */
4644     int starPattern;
4645     char *maskp;                        /* mask part of path */
4646     int infoLevel;
4647     int searchFlags;
4648     int eos;
4649     smb_tran2Packet_t *outp;    /* response packet */
4650     char *tidPathp;
4651     int align;
4652     char shortName[13];         /* 8.3 name if needed */
4653     int NeedShortName;
4654     int foundInexact;
4655     char *shortNameEnd;
4656     int fileType;
4657     cm_fid_t fid;
4658     cm_req_t req;
4659     char * s;
4660
4661     cm_InitReq(&req);
4662
4663     eos = 0;
4664     if (p->opcode == 1) {
4665         /* find first; obtain basic parameters from request */
4666         attribute = p->parmsp[0];
4667         maxCount = p->parmsp[1];
4668         infoLevel = p->parmsp[3];
4669         searchFlags = p->parmsp[2];
4670         pathp = ((char *) p->parmsp) + 12;      /* points to path */
4671         if (smb_StoreAnsiFilenames)
4672             OemToChar(pathp,pathp);
4673         nextCookie = 0;
4674         maskp = strrchr(pathp, '\\');
4675         if (maskp == NULL) 
4676             maskp = pathp;
4677         else 
4678             maskp++;    /* skip over backslash */
4679
4680         /* track if this is likely to match a lot of entries */
4681         starPattern = smb_V3IsStarMask(maskp);
4682
4683 #ifndef NOFINDFIRSTOPTIMIZE
4684         if (!starPattern) {
4685             /* if this is for a single directory or file, we let the
4686                optimized routine handle it.  The only error it 
4687                returns is CM_ERROR_NOSUCHFILE.  The  */
4688             code = smb_T2SearchDirSingle(vcp, p, opx);
4689
4690             /* we only failover if we see a CM_ERROR_NOSUCHFILE */
4691             if (code != CM_ERROR_NOSUCHFILE) {
4692 #ifdef USE_BPLUS
4693                 if (code == CM_ERROR_BPLUS_NOMATCH)
4694                     code = CM_ERROR_NOSUCHFILE;
4695 #endif
4696                 return code;
4697             }
4698         }
4699 #endif
4700         dir_enums++;
4701
4702         dsp = smb_NewDirSearch(1);
4703         dsp->attribute = attribute;
4704         strcpy(dsp->mask, maskp);       /* and save mask */
4705     }
4706     else {
4707         osi_assert(p->opcode == 2);
4708         /* find next; obtain basic parameters from request or open dir file */
4709         dsp = smb_FindDirSearch(p->parmsp[0]);
4710         maxCount = p->parmsp[1];
4711         infoLevel = p->parmsp[2];
4712         nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4713         searchFlags = p->parmsp[5];
4714         if (!dsp) {
4715             osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4716                      p->parmsp[0], nextCookie);
4717             return CM_ERROR_BADFD;
4718         }
4719         attribute = dsp->attribute;
4720         pathp = NULL;
4721         maskp = dsp->mask;
4722         starPattern = 1;        /* assume, since required a Find Next */
4723     }
4724
4725     switch ( infoLevel ) {
4726     case SMB_INFO_STANDARD:
4727         s = "InfoStandard";
4728         break;
4729     case SMB_INFO_QUERY_EA_SIZE:
4730         s = "InfoQueryEaSize";
4731         break;
4732     case SMB_INFO_QUERY_EAS_FROM_LIST:
4733         s = "InfoQueryEasFromList";
4734         break;
4735     case SMB_FIND_FILE_DIRECTORY_INFO:
4736         s = "FindFileDirectoryInfo";
4737         break;
4738     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4739         s = "FindFileFullDirectoryInfo";
4740         break;
4741     case SMB_FIND_FILE_NAMES_INFO:
4742         s = "FindFileNamesInfo";
4743         break;
4744     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4745         s = "FindFileBothDirectoryInfo";
4746         break;
4747     default:
4748         s = "unknownInfoLevel";
4749     }
4750
4751     osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4752
4753     osi_Log4(smb_logp,
4754               "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4755               attribute, infoLevel, maxCount, searchFlags);
4756
4757     osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4758               p->opcode, dsp->cookie, nextCookie);
4759
4760     if (infoLevel > SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4761         osi_Log1(smb_logp, "Unsupported InfoLevel 0x%x", infoLevel);
4762         smb_ReleaseDirSearch(dsp);
4763         return CM_ERROR_INVAL;
4764     }
4765
4766     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4767         searchFlags &= ~TRAN2_FIND_FLAG_RETURN_RESUME_KEYS;     /* no resume keys */
4768
4769     dirListPatchesp = NULL;
4770
4771     maxReturnData = p->maxReturnData;
4772     if (p->opcode == 1) /* find first */
4773         maxReturnParms = 10;    /* bytes */
4774     else    
4775         maxReturnParms = 8;     /* bytes */
4776
4777 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4778     if (maxReturnData > 6000) 
4779         maxReturnData = 6000;
4780 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4781
4782     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4783                                       maxReturnData);
4784
4785     osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4786              maxCount, osi_LogSaveString(smb_logp, pathp));
4787         
4788     /* bail out if request looks bad */
4789     if (p->opcode == 1 && !pathp) {
4790         smb_ReleaseDirSearch(dsp);
4791         smb_FreeTran2Packet(outp);
4792         return CM_ERROR_BADSMB;
4793     }
4794         
4795     osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4796              dsp->cookie, nextCookie, attribute);
4797
4798     userp = smb_GetTran2User(vcp, p);
4799     if (!userp) {
4800         osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4801         smb_ReleaseDirSearch(dsp);
4802         smb_FreeTran2Packet(outp);
4803         return CM_ERROR_BADSMB;
4804     }
4805
4806     /* try to get the vnode for the path name next */
4807     lock_ObtainMutex(&dsp->mx);
4808     if (dsp->scp) {
4809         scp = dsp->scp;
4810         osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4811         cm_HoldSCache(scp);
4812         code = 0;
4813     } else {
4814         spacep = cm_GetSpace();
4815         smb_StripLastComponent(spacep->data, NULL, pathp);
4816         code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4817         if (code) {
4818             cm_ReleaseUser(userp);
4819             smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4820             smb_FreeTran2Packet(outp);
4821             lock_ReleaseMutex(&dsp->mx);
4822             smb_DeleteDirSearch(dsp);
4823             smb_ReleaseDirSearch(dsp);
4824             return 0;
4825         }
4826         code = cm_NameI(cm_data.rootSCachep, spacep->data,
4827                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4828                         userp, tidPathp, &req, &scp);
4829         cm_FreeSpace(spacep);
4830
4831         if (code == 0) {
4832 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4833             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4834                 cm_ReleaseSCache(scp);
4835                 cm_ReleaseUser(userp);
4836                 if ( WANTS_DFS_PATHNAMES(p) )
4837                     code = CM_ERROR_PATH_NOT_COVERED;
4838                 else
4839                     code = CM_ERROR_BADSHARENAME;
4840                 smb_SendTran2Error(vcp, p, opx, code);
4841                 smb_FreeTran2Packet(outp);
4842                 lock_ReleaseMutex(&dsp->mx);
4843                 smb_DeleteDirSearch(dsp);
4844                 smb_ReleaseDirSearch(dsp);
4845                 return 0;
4846             }
4847 #endif /* DFS_SUPPORT */
4848             dsp->scp = scp;
4849             osi_Log2(smb_logp,"smb_ReceiveTran2SearchDir dsp 0x%p scp 0x%p", dsp, scp);
4850             /* we need one hold for the entry we just stored into,
4851              * and one for our own processing.  When we're done
4852              * with this function, we'll drop the one for our own
4853              * processing.  We held it once from the namei call,
4854              * and so we do another hold now.
4855              */
4856             cm_HoldSCache(scp);
4857             lock_ObtainMutex(&scp->mx);
4858             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4859                  LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4860                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4861                 dsp->flags |= SMB_DIRSEARCH_BULKST;
4862             }
4863             lock_ReleaseMutex(&scp->mx);
4864         } 
4865     }
4866     lock_ReleaseMutex(&dsp->mx);
4867     if (code) {
4868         cm_ReleaseUser(userp);
4869         smb_FreeTran2Packet(outp);
4870         smb_DeleteDirSearch(dsp);
4871         smb_ReleaseDirSearch(dsp);
4872         return code;
4873     }
4874
4875     /* get the directory size */
4876     lock_ObtainMutex(&scp->mx);
4877     code = cm_SyncOp(scp, NULL, userp, &req, 0,
4878                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4879     if (code) {
4880         lock_ReleaseMutex(&scp->mx);
4881         cm_ReleaseSCache(scp);
4882         cm_ReleaseUser(userp);
4883         smb_FreeTran2Packet(outp);
4884         smb_DeleteDirSearch(dsp);
4885         smb_ReleaseDirSearch(dsp);
4886         return code;
4887     }
4888
4889     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4890
4891   startsearch:
4892     dirLength = scp->length;
4893     bufferp = NULL;
4894     bufferOffset.LowPart = bufferOffset.HighPart = 0;
4895     curOffset.HighPart = 0;
4896     curOffset.LowPart = nextCookie;
4897     origOp = outp->datap;
4898
4899     foundInexact = 0;
4900     code = 0;
4901     returnedNames = 0;
4902     bytesInBuffer = 0;
4903     while (1) {
4904         op = origOp;
4905         if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
4906             /* skip over resume key */
4907             op += 4;
4908
4909         /* make sure that curOffset.LowPart doesn't point to the first
4910          * 32 bytes in the 2nd through last dir page, and that it doesn't
4911          * point at the first 13 32-byte chunks in the first dir page,
4912          * since those are dir and page headers, and don't contain useful
4913          * information.
4914          */
4915         temp = curOffset.LowPart & (2048-1);
4916         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4917             /* we're in the first page */
4918             if (temp < 13*32) temp = 13*32;
4919         }
4920         else {
4921             /* we're in a later dir page */
4922             if (temp < 32) temp = 32;
4923         }
4924                 
4925         /* make sure the low order 5 bits are zero */
4926         temp &= ~(32-1);
4927                 
4928         /* now put temp bits back ito curOffset.LowPart */
4929         curOffset.LowPart &= ~(2048-1);
4930         curOffset.LowPart |= temp;
4931
4932         /* check if we've passed the dir's EOF */
4933         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4934             osi_Log0(smb_logp, "T2 search dir passed eof");
4935             eos = 1;
4936             break;
4937         }
4938
4939         /* check if we've returned all the names that will fit in the
4940          * response packet; we check return count as well as the number
4941          * of bytes requested.  We check the # of bytes after we find
4942          * the dir entry, since we'll need to check its size.
4943          */
4944         if (returnedNames >= maxCount) {
4945             osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4946                       returnedNames, maxCount);
4947             break;
4948         }
4949
4950         /* see if we can use the bufferp we have now; compute in which
4951          * page the current offset would be, and check whether that's
4952          * the offset of the buffer we have.  If not, get the buffer.
4953          */
4954         thyper.HighPart = curOffset.HighPart;
4955         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4956         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4957             /* wrong buffer */
4958             if (bufferp) {
4959                 buf_Release(bufferp);
4960                 bufferp = NULL;
4961             }       
4962             lock_ReleaseMutex(&scp->mx);
4963             lock_ObtainRead(&scp->bufCreateLock);
4964             code = buf_Get(scp, &thyper, &bufferp);
4965             lock_ReleaseRead(&scp->bufCreateLock);
4966             lock_ObtainMutex(&dsp->mx);
4967
4968             /* now, if we're doing a star match, do bulk fetching
4969              * of all of the status info for files in the dir.
4970              */
4971             if (starPattern) {
4972                 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4973                                            infoLevel, userp,
4974                                            &req);
4975                 lock_ObtainMutex(&scp->mx);
4976                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4977                     LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4978                     /* Don't bulk stat if risking timeout */
4979                     DWORD now = GetTickCount();
4980                     if (now - req.startTime > RDRtimeout * 1000) {
4981                         scp->bulkStatProgress = thyper;
4982                         scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4983                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4984                     } else
4985                         code = cm_TryBulkStat(scp, &thyper, userp, &req);
4986                 }
4987             } else {
4988                 lock_ObtainMutex(&scp->mx);
4989             }
4990             lock_ReleaseMutex(&dsp->mx);
4991             if (code) {
4992                 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4993                 break;
4994             }
4995
4996             bufferOffset = thyper;
4997
4998             /* now get the data in the cache */
4999             while (1) {
5000                 code = cm_SyncOp(scp, bufferp, userp, &req,
5001                                  PRSFS_LOOKUP,
5002                                  CM_SCACHESYNC_NEEDCALLBACK
5003                                  | CM_SCACHESYNC_READ);
5004                 if (code) {
5005                     osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
5006                     break;
5007                 }
5008                        
5009                 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5010
5011                 if (cm_HaveBuffer(scp, bufferp, 0)) {
5012                     osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5013                     break;
5014                 }
5015
5016                 /* otherwise, load the buffer and try again */
5017                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
5018                                     &req);
5019                 if (code) {
5020                     osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d", 
5021                               scp, bufferp, code);
5022                     break;
5023                 }
5024             }
5025             if (code) {
5026                 buf_Release(bufferp);
5027                 bufferp = NULL;
5028                 break;
5029             }
5030         }       /* if (wrong buffer) ... */
5031                 
5032         /* now we have the buffer containing the entry we're interested
5033          * in; copy it out if it represents a non-deleted entry.
5034          */
5035         entryInDir = curOffset.LowPart & (2048-1);
5036         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5037
5038         /* page header will help tell us which entries are free.  Page
5039          * header can change more often than once per buffer, since
5040          * AFS 3 dir page size may be less than (but not more than)
5041          * a buffer package buffer.
5042          */
5043         /* only look intra-buffer */
5044         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5045         temp &= ~(2048 - 1);    /* turn off intra-page bits */
5046         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5047
5048         /* now determine which entry we're looking at in the page.
5049          * If it is free (there's a free bitmap at the start of the
5050          * dir), we should skip these 32 bytes.
5051          */
5052         slotInPage = (entryInDir & 0x7e0) >> 5;
5053         if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
5054             (1 << (slotInPage & 0x7)))) {
5055             /* this entry is free */
5056             numDirChunks = 1;   /* only skip this guy */
5057             goto nextEntry;
5058         }
5059
5060         tp = bufferp->datap + entryInBuffer;
5061         dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
5062
5063         /* while we're here, compute the next entry's location, too,
5064          * since we'll need it when writing out the cookie into the dir
5065          * listing stream.
5066          *
5067          * XXXX Probably should do more sanity checking.
5068          */
5069         numDirChunks = cm_NameEntries(dep->name, &onbytes);
5070                 
5071         /* compute offset of cookie representing next entry */
5072         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5073
5074         /* Need 8.3 name? */
5075         NeedShortName = 0;
5076         if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
5077              && dep->fid.vnode != 0
5078              && !cm_Is8Dot3(dep->name)) {
5079             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
5080             NeedShortName = 1;
5081         }
5082
5083         osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
5084                   dep->fid.vnode, dep->fid.unique, 
5085                   osi_LogSaveString(smb_logp, dep->name),
5086                   NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
5087
5088         /* When matching, we are using doing a case fold if we have a wildcard mask.
5089          * If we get a non-wildcard match, it's a lookup for a specific file. 
5090          */
5091         if (dep->fid.vnode != 0 && 
5092             (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
5093              (NeedShortName &&
5094               smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
5095
5096             /* Eliminate entries that don't match requested attributes */
5097             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
5098                  smb_IsDotFile(dep->name)) {
5099                 osi_Log0(smb_logp, "T2 search dir skipping hidden");
5100                 goto nextEntry; /* no hidden files */
5101             }
5102             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
5103             {
5104                 /* We have already done the cm_TryBulkStat above */
5105                 fid.cell = scp->fid.cell;
5106                 fid.volume = scp->fid.volume;
5107                 fid.vnode = ntohl(dep->fid.vnode);
5108                 fid.unique = ntohl(dep->fid.unique);
5109                 fileType = cm_FindFileType(&fid);
5110                 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
5111                  "has filetype %d", dep->name,
5112                  fileType);*/
5113                 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5114                     fileType == CM_SCACHETYPE_MOUNTPOINT ||
5115                     fileType == CM_SCACHETYPE_DFSLINK ||
5116                     fileType == CM_SCACHETYPE_INVALID)
5117                     osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
5118                     goto nextEntry;
5119             }
5120
5121             /* finally check if this name will fit */
5122
5123             /* standard dir entry stuff */
5124             if (infoLevel < 0x101)
5125                 ohbytes = 23;   /* pre-NT */
5126             else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5127                 ohbytes = 12;   /* NT names only */
5128             else
5129                 ohbytes = 64;   /* NT */
5130
5131             if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
5132                 ohbytes += 26;  /* Short name & length */
5133
5134             if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS) {
5135                 ohbytes += 4;   /* if resume key required */
5136             }   
5137
5138             if (infoLevel != SMB_INFO_STANDARD
5139                  && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
5140                  && infoLevel != SMB_FIND_FILE_NAMES_INFO)
5141                 ohbytes += 4;   /* EASIZE */
5142
5143             /* add header to name & term. null */
5144             orbytes = onbytes + ohbytes + 1;
5145
5146             /* now, we round up the record to a 4 byte alignment,
5147              * and we make sure that we have enough room here for
5148              * even the aligned version (so we don't have to worry
5149              * about an * overflow when we pad things out below).
5150              * That's the reason for the alignment arithmetic below.
5151              */
5152             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5153                 align = (4 - (orbytes & 3)) & 3;
5154             else
5155                 align = 0;
5156             if (orbytes + bytesInBuffer + align > maxReturnData) {
5157                 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
5158                           maxReturnData);
5159                 break;
5160             }
5161
5162             /* this is one of the entries to use: it is not deleted
5163              * and it matches the star pattern we're looking for.
5164              * Put out the name, preceded by its length.
5165              */
5166             /* First zero everything else */
5167             memset(origOp, 0, ohbytes);
5168
5169             if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
5170                 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
5171             else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
5172                 *((u_long *)(op + 8)) = onbytes;
5173             else
5174                 *((u_long *)(op + 60)) = onbytes;
5175             strcpy(origOp+ohbytes, dep->name);
5176             if (smb_StoreAnsiFilenames)
5177                 CharToOem(origOp+ohbytes, origOp+ohbytes);
5178
5179             /* Short name if requested and needed */
5180             if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
5181                 if (NeedShortName) {
5182                     strcpy(op + 70, shortName);
5183                     if (smb_StoreAnsiFilenames)
5184                         CharToOem(op + 70, op + 70);
5185                     *(op + 68) = (char)(shortNameEnd - shortName);
5186                 }
5187             }
5188
5189             /* now, adjust the # of entries copied */
5190             returnedNames++;
5191
5192             /* NextEntryOffset and FileIndex */
5193             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
5194                 int entryOffset = orbytes + align;
5195                 *((u_long *)op) = entryOffset;
5196                 *((u_long *)(op+4)) = nextEntryCookie;
5197             }
5198
5199             /* now we emit the attribute.  This is tricky, since
5200              * we need to really stat the file to find out what
5201              * type of entry we've got.  Right now, we're copying
5202              * out data from a buffer, while holding the scp
5203              * locked, so it isn't really convenient to stat
5204              * something now.  We'll put in a place holder
5205              * now, and make a second pass before returning this
5206              * to get the real attributes.  So, we just skip the
5207              * data for now, and adjust it later.  We allocate a
5208              * patch record to make it easy to find this point
5209              * later.  The replay will happen at a time when it is
5210              * safe to unlock the directory.
5211              */
5212             if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
5213                 curPatchp = malloc(sizeof(*curPatchp));
5214                 osi_QAdd((osi_queue_t **) &dirListPatchesp,
5215                           &curPatchp->q);
5216                 curPatchp->dptr = op;
5217                 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
5218                     curPatchp->dptr += 8;
5219
5220                 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
5221                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5222                 }       
5223                 else    
5224                     curPatchp->flags = 0;
5225
5226                 curPatchp->fid.cell = scp->fid.cell;
5227                 curPatchp->fid.volume = scp->fid.volume;
5228                 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
5229                 curPatchp->fid.unique = ntohl(dep->fid.unique);
5230
5231                 /* temp */
5232                 curPatchp->dep = dep;
5233             }   
5234
5235             if (searchFlags & TRAN2_FIND_FLAG_RETURN_RESUME_KEYS)
5236                 /* put out resume key */
5237                 *((u_long *)origOp) = nextEntryCookie;
5238
5239             /* Adjust byte ptr and count */
5240             origOp += orbytes;  /* skip entire record */
5241             bytesInBuffer += orbytes;
5242
5243             /* and pad the record out */
5244             while (--align >= 0) {
5245                 *origOp++ = 0;
5246                 bytesInBuffer++;
5247             }
5248         }       /* if we're including this name */
5249         else if (!starPattern &&
5250                  !foundInexact &&
5251                  dep->fid.vnode != 0 &&
5252                  smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
5253             /* We were looking for exact matches, but here's an inexact one*/
5254             foundInexact = 1;
5255         }
5256                 
5257       nextEntry:
5258         /* and adjust curOffset to be where the new cookie is */
5259         thyper.HighPart = 0;
5260         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5261         curOffset = LargeIntegerAdd(thyper, curOffset);
5262     } /* while copying data for dir listing */
5263
5264     /* If we didn't get a star pattern, we did an exact match during the first pass. 
5265      * If there were no exact matches found, we fail over to inexact matches by
5266      * marking the query as a star pattern (matches all case permutations), and
5267      * re-running the query. 
5268      */
5269     if (returnedNames == 0 && !starPattern && foundInexact) {
5270         osi_Log0(smb_logp,"T2 Search: No exact matches. Re-running for inexact matches");
5271         starPattern = 1;
5272         goto startsearch;
5273     }
5274
5275     /* release the mutex */
5276     lock_ReleaseMutex(&scp->mx);
5277     if (bufferp) {
5278         buf_Release(bufferp);
5279         bufferp = NULL;
5280     }
5281
5282     /* apply and free last set of patches; if not doing a star match, this
5283      * will be empty, but better safe (and freeing everything) than sorry.
5284      */
5285     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
5286                               &req);
5287         
5288     /* now put out the final parameters */
5289     if (returnedNames == 0) 
5290         eos = 1;
5291     if (p->opcode == 1) {
5292         /* find first */
5293         outp->parmsp[0] = (unsigned short) dsp->cookie;
5294         outp->parmsp[1] = returnedNames;
5295         outp->parmsp[2] = eos;
5296         outp->parmsp[3] = 0;            /* nothing wrong with EAS */
5297         outp->parmsp[4] = 0;    
5298         /* don't need last name to continue
5299          * search, cookie is enough.  Normally,
5300          * this is the offset of the file name
5301          * of the last entry returned.
5302          */
5303         outp->totalParms = 10;  /* in bytes */
5304     }
5305     else {
5306         /* find next */
5307         outp->parmsp[0] = returnedNames;
5308         outp->parmsp[1] = eos;
5309         outp->parmsp[2] = 0;    /* EAS error */
5310         outp->parmsp[3] = 0;    /* last name, as above */
5311         outp->totalParms = 8;   /* in bytes */
5312     }   
5313
5314     /* return # of bytes in the buffer */
5315     outp->totalData = bytesInBuffer;
5316
5317     /* Return error code if unsuccessful on first request */
5318     if (code == 0 && p->opcode == 1 && returnedNames == 0)
5319         code = CM_ERROR_NOSUCHFILE;
5320
5321     osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
5322              p->opcode, dsp->cookie, returnedNames, code);
5323
5324     /* if we're supposed to close the search after this request, or if
5325      * we're supposed to close the search if we're done, and we're done,
5326      * or if something went wrong, close the search.
5327      */
5328     if ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH) || 
5329         (returnedNames == 0) ||
5330         ((searchFlags & TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END) && eos) || 
5331         code != 0)
5332         smb_DeleteDirSearch(dsp);
5333
5334     if (code)
5335         smb_SendTran2Error(vcp, p, opx, code);
5336     else
5337         smb_SendTran2Packet(vcp, outp, opx);
5338
5339     smb_FreeTran2Packet(outp);
5340     smb_ReleaseDirSearch(dsp);
5341     cm_ReleaseSCache(scp);
5342     cm_ReleaseUser(userp);
5343     return 0;
5344 }
5345
5346 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5347 {
5348     int dirHandle;
5349     smb_dirSearch_t *dsp;
5350
5351     dirHandle = smb_GetSMBParm(inp, 0);
5352         
5353     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
5354
5355     dsp = smb_FindDirSearch(dirHandle);
5356         
5357     if (!dsp)
5358         return CM_ERROR_BADFD;
5359         
5360     /* otherwise, we have an FD to destroy */
5361     smb_DeleteDirSearch(dsp);
5362     smb_ReleaseDirSearch(dsp);
5363         
5364     /* and return results */
5365     smb_SetSMBDataLength(outp, 0);
5366
5367     return 0;
5368 }
5369
5370 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5371 {
5372     smb_SetSMBDataLength(outp, 0);
5373     return 0;
5374 }
5375
5376 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5377 {
5378     char *pathp;
5379     long code = 0;
5380     cm_space_t *spacep;
5381     int excl;
5382     cm_user_t *userp;
5383     cm_scache_t *dscp;          /* dir we're dealing with */
5384     cm_scache_t *scp;           /* file we're creating */
5385     cm_attr_t setAttr;
5386     int initialModeBits;
5387     smb_fid_t *fidp;
5388     int attributes;
5389     char *lastNamep;
5390     afs_uint32 dosTime;
5391     int openFun;
5392     int trunc;
5393     int openMode;
5394     int extraInfo;
5395     int openAction;
5396     int parmSlot;                       /* which parm we're dealing with */
5397     char *tidPathp;
5398     cm_req_t req;
5399     int created = 0;
5400
5401     cm_InitReq(&req);
5402
5403     scp = NULL;
5404         
5405     extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
5406     openFun = smb_GetSMBParm(inp, 8); /* open function */
5407     excl = ((openFun & 3) == 0);
5408     trunc = ((openFun & 3) == 2); /* truncate it */
5409     openMode = (smb_GetSMBParm(inp, 3) & 0x7);
5410     openAction = 0;             /* tracks what we did */
5411
5412     attributes = smb_GetSMBParm(inp, 5);
5413     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
5414
5415                                 /* compute initial mode bits based on read-only flag in attributes */
5416     initialModeBits = 0666;
5417     if (attributes & SMB_ATTR_READONLY) 
5418         initialModeBits &= ~0222;
5419         
5420     pathp = smb_GetSMBData(inp, NULL);
5421     if (smb_StoreAnsiFilenames)
5422         OemToChar(pathp,pathp);
5423
5424     spacep = inp->spacep;
5425     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5426
5427     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5428         /* special case magic file name for receiving IOCTL requests
5429          * (since IOCTL calls themselves aren't getting through).
5430          */
5431 #ifdef NOTSERVICE
5432         osi_Log0(smb_logp, "IOCTL Open");
5433 #endif
5434
5435         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5436         smb_SetupIoctlFid(fidp, spacep);
5437
5438         /* set inp->fid so that later read calls in same msg can find fid */
5439         inp->fid = fidp->fid;
5440         
5441         /* copy out remainder of the parms */
5442         parmSlot = 2;
5443         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5444         if (extraInfo) {
5445             smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
5446             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* mod time */
5447             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5448             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* len */
5449             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
5450             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5451             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5452             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5453         }   
5454         /* and the final "always present" stuff */
5455         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
5456         /* next write out the "unique" ID */
5457         smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
5458         smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
5459         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5460         smb_SetSMBDataLength(outp, 0);
5461
5462         /* and clean up fid reference */
5463         smb_ReleaseFID(fidp);
5464         return 0;
5465     }
5466
5467 #ifdef DEBUG_VERBOSE
5468     {
5469         char *hexp, *asciip;
5470         asciip = (lastNamep ? lastNamep : pathp );
5471         hexp = osi_HexifyString(asciip);
5472         DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
5473         free(hexp);
5474     }
5475 #endif
5476     userp = smb_GetUserFromVCP(vcp, inp);
5477
5478     dscp = NULL;
5479     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5480     if (code) {
5481         cm_ReleaseUser(userp);
5482         return CM_ERROR_NOSUCHPATH;
5483     }
5484     code = cm_NameI(cm_data.rootSCachep, pathp,
5485                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5486                     userp, tidPathp, &req, &scp);
5487
5488 #ifdef DFS_SUPPORT
5489     if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5490         cm_ReleaseSCache(scp);
5491         cm_ReleaseUser(userp);
5492         if ( WANTS_DFS_PATHNAMES(inp) )
5493             return CM_ERROR_PATH_NOT_COVERED;
5494         else
5495             return CM_ERROR_BADSHARENAME;
5496     }
5497 #endif /* DFS_SUPPORT */
5498
5499     if (code != 0) {
5500         code = cm_NameI(cm_data.rootSCachep, spacep->data,
5501                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5502                         userp, tidPathp, &req, &dscp);
5503         if (code) {
5504             cm_ReleaseUser(userp);
5505             return code;
5506         }
5507
5508 #ifdef DFS_SUPPORT
5509         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5510             cm_ReleaseSCache(dscp);
5511             cm_ReleaseUser(userp);
5512             if ( WANTS_DFS_PATHNAMES(inp) )
5513                 return CM_ERROR_PATH_NOT_COVERED;
5514             else
5515                 return CM_ERROR_BADSHARENAME;
5516         }
5517 #endif /* DFS_SUPPORT */
5518         /* otherwise, scp points to the parent directory.  Do a lookup,
5519          * and truncate the file if we find it, otherwise we create the
5520          * file.
5521          */
5522         if (!lastNamep) 
5523             lastNamep = pathp;
5524         else 
5525             lastNamep++;
5526         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
5527                           &req, &scp);
5528         if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
5529             cm_ReleaseSCache(dscp);
5530             cm_ReleaseUser(userp);
5531             return code;
5532         }
5533     }
5534         
5535     /* if we get here, if code is 0, the file exists and is represented by
5536      * scp.  Otherwise, we have to create it.  The dir may be represented
5537      * by dscp, or we may have found the file directly.  If code is non-zero,
5538      * scp is NULL.
5539      */
5540     if (code == 0) {
5541         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5542         if (code) {
5543             if (dscp) cm_ReleaseSCache(dscp);
5544             cm_ReleaseSCache(scp);
5545             cm_ReleaseUser(userp);
5546             return code;
5547         }
5548
5549         if (excl) {
5550             /* oops, file shouldn't be there */
5551             if (dscp) 
5552                 cm_ReleaseSCache(dscp);
5553             cm_ReleaseSCache(scp);
5554             cm_ReleaseUser(userp);
5555             return CM_ERROR_EXISTS;
5556         }
5557
5558         if (trunc) {
5559             setAttr.mask = CM_ATTRMASK_LENGTH;
5560             setAttr.length.LowPart = 0;
5561             setAttr.length.HighPart = 0;
5562             code = cm_SetAttr(scp, &setAttr, userp, &req);
5563             openAction = 3;     /* truncated existing file */
5564         }
5565         else openAction = 1;    /* found existing file */
5566     }
5567     else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5568         /* don't create if not found */
5569         if (dscp) cm_ReleaseSCache(dscp);
5570         cm_ReleaseUser(userp);
5571         return CM_ERROR_NOSUCHFILE;
5572     }
5573     else {
5574         osi_assert(dscp != NULL);
5575         osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5576                  osi_LogSaveString(smb_logp, lastNamep));
5577         openAction = 2; /* created file */
5578         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5579         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5580         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5581                          &req);
5582         if (code == 0) {
5583             created = 1;
5584             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5585                 smb_NotifyChange(FILE_ACTION_ADDED,
5586                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5587                                  dscp, lastNamep, NULL, TRUE);
5588         } else if (!excl && code == CM_ERROR_EXISTS) {
5589             /* not an exclusive create, and someone else tried
5590              * creating it already, then we open it anyway.  We
5591              * don't bother retrying after this, since if this next
5592              * fails, that means that the file was deleted after we
5593              * started this call.
5594              */
5595             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5596                              userp, &req, &scp);
5597             if (code == 0) {
5598                 if (trunc) {
5599                     setAttr.mask = CM_ATTRMASK_LENGTH;
5600                     setAttr.length.LowPart = 0;
5601                     setAttr.length.HighPart = 0;
5602                     code = cm_SetAttr(scp, &setAttr, userp, &req);
5603                 }   
5604             }   /* lookup succeeded */
5605         }
5606     }
5607         
5608     /* we don't need this any longer */
5609     if (dscp) 
5610         cm_ReleaseSCache(dscp);
5611
5612     if (code) {
5613         /* something went wrong creating or truncating the file */
5614         if (scp) 
5615             cm_ReleaseSCache(scp);
5616         cm_ReleaseUser(userp);
5617         return code;
5618     }
5619         
5620     /* make sure we're about to open a file */
5621     if (scp->fileType != CM_SCACHETYPE_FILE) {
5622         cm_ReleaseSCache(scp);
5623         cm_ReleaseUser(userp);
5624         return CM_ERROR_ISDIR;
5625     }
5626
5627     /* now all we have to do is open the file itself */
5628     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5629     osi_assert(fidp);
5630         
5631     cm_HoldUser(userp);
5632     lock_ObtainMutex(&fidp->mx);
5633     /* save a pointer to the vnode */
5634     fidp->scp = scp;
5635     lock_ObtainMutex(&scp->mx);
5636     scp->flags |= CM_SCACHEFLAG_SMB_FID;
5637     lock_ReleaseMutex(&scp->mx);
5638     osi_Log2(smb_logp,"smb_ReceiveV3OpenX fidp 0x%p scp 0x%p", fidp, scp);
5639     /* also the user */
5640     fidp->userp = userp;
5641         
5642     /* compute open mode */
5643     if (openMode != 1) 
5644         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5645     if (openMode == 1 || openMode == 2)
5646         fidp->flags |= SMB_FID_OPENWRITE;
5647
5648     /* remember if the file was newly created */
5649     if (created)
5650         fidp->flags |= SMB_FID_CREATED;
5651
5652     lock_ReleaseMutex(&fidp->mx);
5653     smb_ReleaseFID(fidp);
5654         
5655     cm_Open(scp, 0, userp);
5656
5657     /* set inp->fid so that later read calls in same msg can find fid */
5658     inp->fid = fidp->fid;
5659         
5660     /* copy out remainder of the parms */
5661     parmSlot = 2;
5662     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5663     lock_ObtainMutex(&scp->mx);
5664     if (extraInfo) {
5665         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5666         smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5667         smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5668         smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5669         smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5670         smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5671         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5672         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5673         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5674     }
5675     /* and the final "always present" stuff */
5676     smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5677     /* next write out the "unique" ID */
5678     smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5679     smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5680     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5681     lock_ReleaseMutex(&scp->mx);
5682     smb_SetSMBDataLength(outp, 0);
5683
5684     osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5685
5686     cm_ReleaseUser(userp);
5687     /* leave scp held since we put it in fidp->scp */
5688     return 0;
5689 }       
5690
5691 static void smb_GetLockParams(unsigned char LockType, 
5692                               char ** buf, 
5693                               unsigned int * ppid, 
5694                               LARGE_INTEGER * pOffset, 
5695                               LARGE_INTEGER * pLength)
5696 {
5697     if (LockType & LOCKING_ANDX_LARGE_FILES) {
5698         /* Large Files */
5699         *ppid = *((USHORT *) *buf);
5700         pOffset->HighPart = *((LONG *)(*buf + 4));
5701         pOffset->LowPart = *((DWORD *)(*buf + 8));
5702         pLength->HighPart = *((LONG *)(*buf + 12));
5703         pLength->LowPart = *((DWORD *)(*buf + 16));
5704         *buf += 20;
5705     }
5706     else {
5707         /* Not Large Files */
5708         *ppid = *((USHORT *) *buf);
5709         pOffset->HighPart = 0;
5710         pOffset->LowPart = *((DWORD *)(*buf + 2));
5711         pLength->HighPart = 0;
5712         pLength->LowPart = *((DWORD *)(*buf + 6));
5713         *buf += 10;
5714     }
5715 }
5716
5717 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5718 {
5719     cm_req_t req;
5720     cm_user_t *userp;
5721     unsigned short fid;
5722     smb_fid_t *fidp;
5723     cm_scache_t *scp;
5724     unsigned char LockType;
5725     unsigned short NumberOfUnlocks, NumberOfLocks;
5726     long Timeout;
5727     char *op;
5728     char *op_locks;
5729     LARGE_INTEGER LOffset, LLength;
5730     smb_waitingLockRequest_t *wlRequest = NULL;
5731     cm_file_lock_t *lockp;
5732     long code = 0;
5733     int i;
5734     cm_key_t key;
5735     unsigned int pid;
5736
5737     cm_InitReq(&req);
5738
5739     fid = smb_GetSMBParm(inp, 2);
5740     fid = smb_ChainFID(fid, inp);
5741
5742     fidp = smb_FindFID(vcp, fid, 0);
5743     if (!fidp)
5744         return CM_ERROR_BADFD;
5745     
5746     lock_ObtainMutex(&fidp->mx);
5747     if (fidp->flags & SMB_FID_IOCTL) {
5748         osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5749         lock_ReleaseMutex(&fidp->mx);
5750         smb_ReleaseFID(fidp);
5751         return CM_ERROR_BADFD;
5752     }
5753     scp = fidp->scp;
5754     osi_Log2(smb_logp,"smb_ReceiveV3LockingX fidp 0x%p scp 0x%p", fidp, scp);
5755     cm_HoldSCache(scp);
5756     lock_ReleaseMutex(&fidp->mx);
5757
5758     /* set inp->fid so that later read calls in same msg can find fid */
5759     inp->fid = fid;
5760
5761     userp = smb_GetUserFromVCP(vcp, inp);
5762
5763
5764     lock_ObtainMutex(&scp->mx);
5765     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5766                       CM_SCACHESYNC_NEEDCALLBACK
5767                          | CM_SCACHESYNC_GETSTATUS
5768                          | CM_SCACHESYNC_LOCK);
5769     if (code) {
5770         osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5771         goto doneSync;
5772     }
5773
5774     LockType = smb_GetSMBParm(inp, 3) & 0xff;
5775     Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5776     NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5777     NumberOfLocks = smb_GetSMBParm(inp, 7);
5778
5779     if (!(fidp->flags & SMB_FID_OPENWRITE) &&
5780         !(LockType & LOCKING_ANDX_SHARED_LOCK)) {
5781         /* somebody wants exclusive locks on a file that they only
5782            opened for reading.  We downgrade this to a shared lock. */
5783         osi_Log0(smb_logp, "smb_ReceiveV3Locking reinterpreting exclusive lock as shared for read-only fid");
5784         LockType |= LOCKING_ANDX_SHARED_LOCK;
5785     }
5786
5787     if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5788         (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5789
5790         /* We don't support these requests.  Apparently, we can safely
5791            not deal with them too. */
5792         osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5793                  ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5794                   "LOCKING_ANDX_CANCEL_LOCK":
5795                   "LOCKING_ANDX_CHANGE_LOCKTYPE")); 
5796         /* No need to call osi_LogSaveString since these are string
5797            constants.*/
5798
5799         code = CM_ERROR_BADOP;
5800         goto done;
5801
5802     }
5803
5804     op = smb_GetSMBData(inp, NULL);
5805
5806     for (i=0; i<NumberOfUnlocks; i++) {
5807         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5808
5809         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5810
5811         code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5812
5813         if (code) 
5814             goto done;
5815     }
5816
5817     op_locks = op;
5818
5819     for (i=0; i<NumberOfLocks; i++) {
5820         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5821
5822         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5823
5824         code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5825                         userp, &req, &lockp);
5826
5827         if (code == CM_ERROR_NOACCESS && LockType == LockWrite && 
5828             (fidp->flags & (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE)) == SMB_FID_OPENREAD_LISTDIR)
5829         {
5830             code = cm_Lock(scp, LockRead, LOffset, LLength, key, (Timeout != 0),
5831                             userp, &req, &lockp);
5832         }
5833
5834         if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5835             smb_waitingLock_t * wLock;
5836
5837             /* Put on waiting list */
5838             if(wlRequest == NULL) {
5839                 int j;
5840                 char * opt;
5841                 cm_key_t tkey;
5842                 LARGE_INTEGER tOffset, tLength;
5843
5844                 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5845
5846                 osi_assert(wlRequest != NULL);
5847
5848                 wlRequest->vcp = vcp;
5849                 smb_HoldVC(vcp);
5850                 wlRequest->scp = scp;
5851                 osi_Log2(smb_logp,"smb_ReceiveV3LockingX wlRequest 0x%p scp 0x%p", wlRequest, scp);
5852                 cm_HoldSCache(scp);
5853                 wlRequest->inp = smb_CopyPacket(inp);
5854                 wlRequest->outp = smb_CopyPacket(outp);
5855                 wlRequest->lockType = LockType;
5856                 wlRequest->timeRemaining = Timeout;
5857                 wlRequest->locks = NULL;
5858
5859                 /* The waiting lock request needs to have enough
5860                    information to undo all the locks in the request.
5861                    We do the following to store info about locks that
5862                    have already been granted.  Sure, we can get most
5863                    of the info from the packet, but the packet doesn't
5864                    hold the result of cm_Lock call.  In practice we
5865                    only receive packets with one or two locks, so we
5866                    are only wasting a few bytes here and there and
5867                    only for a limited period of time until the waiting
5868                    lock times out or is freed. */
5869
5870                 for(opt = op_locks, j=i; j > 0; j--) {
5871                     smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5872
5873                     tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5874
5875                     wLock = malloc(sizeof(smb_waitingLock_t));
5876
5877                     osi_assert(wLock != NULL);
5878
5879                     wLock->key = tkey;
5880                     wLock->LOffset = tOffset;
5881                     wLock->LLength = tLength;
5882                     wLock->lockp = NULL;
5883                     wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5884                     osi_QAdd((osi_queue_t **) &wlRequest->locks,
5885                              &wLock->q);
5886                 }
5887             }
5888
5889             wLock = malloc(sizeof(smb_waitingLock_t));
5890
5891             osi_assert(wLock != NULL);
5892
5893             wLock->key = key;
5894             wLock->LOffset = LOffset;
5895             wLock->LLength = LLength;
5896             wLock->lockp = lockp;
5897             wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5898             osi_QAdd((osi_queue_t **) &wlRequest->locks,
5899                      &wLock->q);
5900
5901             osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5902                      wLock);
5903
5904             code = 0;
5905             continue;
5906         }
5907
5908         if (code) {
5909             osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5910             break;
5911         }
5912     }
5913
5914     if (code) {
5915
5916         /* Since something went wrong with the lock number i, we now
5917            have to go ahead and release any locks acquired before the
5918            failure.  All locks before lock number i (of which there
5919            are i of them) have either been successful or are waiting.
5920            Either case requires calling cm_Unlock(). */
5921
5922         /* And purge the waiting lock */
5923         if(wlRequest != NULL) {
5924             smb_waitingLock_t * wl;
5925             smb_waitingLock_t * wlNext;
5926             long ul_code;
5927
5928             for(wl = wlRequest->locks; wl; wl = wlNext) {
5929
5930                 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5931
5932                 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5933                 
5934                 if(ul_code != 0) {
5935                     osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5936                 } else {
5937                     osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5938                 }
5939
5940                 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5941                 free(wl);
5942
5943             }
5944
5945             smb_ReleaseVC(wlRequest->vcp);
5946             cm_ReleaseSCache(wlRequest->scp);
5947             smb_FreePacket(wlRequest->inp);
5948             smb_FreePacket(wlRequest->outp);
5949
5950             free(wlRequest);
5951
5952             wlRequest = NULL;
5953         }
5954
5955     } else {
5956
5957         if (wlRequest != NULL) {
5958
5959             lock_ObtainWrite(&smb_globalLock);
5960             osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5961                      &wlRequest->q);
5962             osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5963             lock_ReleaseWrite(&smb_globalLock);
5964
5965             /* don't send reply immediately */
5966             outp->flags |= SMB_PACKETFLAG_NOSEND;
5967         }
5968
5969         smb_SetSMBDataLength(outp, 0);
5970     }
5971
5972   done:   
5973     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5974
5975   doneSync:
5976     lock_ReleaseMutex(&scp->mx);
5977     cm_ReleaseSCache(scp);
5978     cm_ReleaseUser(userp);
5979     smb_ReleaseFID(fidp);
5980
5981     return code;
5982 }
5983
5984 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5985 {
5986     unsigned short fid;
5987     smb_fid_t *fidp;
5988     cm_scache_t *scp;
5989     long code = 0;
5990     afs_uint32 searchTime;
5991     cm_user_t *userp;
5992     cm_req_t req;
5993
5994     cm_InitReq(&req);
5995
5996     fid = smb_GetSMBParm(inp, 0);
5997     fid = smb_ChainFID(fid, inp);
5998         
5999     fidp = smb_FindFID(vcp, fid, 0);
6000     if (!fidp)
6001         return CM_ERROR_BADFD;
6002     
6003     lock_ObtainMutex(&fidp->mx);
6004     if (fidp->flags & SMB_FID_IOCTL) {
6005         lock_ReleaseMutex(&fidp->mx);
6006         smb_ReleaseFID(fidp);
6007         return CM_ERROR_BADFD;
6008     }
6009     scp = fidp->scp;
6010     osi_Log2(smb_logp,"smb_ReceiveV3GetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6011     cm_HoldSCache(scp);
6012     lock_ReleaseMutex(&fidp->mx);
6013         
6014     userp = smb_GetUserFromVCP(vcp, inp);
6015         
6016         
6017     /* otherwise, stat the file */
6018     lock_ObtainMutex(&scp->mx);
6019     code = cm_SyncOp(scp, NULL, userp, &req, 0,
6020                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6021     if (code) 
6022         goto done;
6023
6024     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6025
6026     /* decode times.  We need a search time, but the response to this
6027      * call provides the date first, not the time, as returned in the
6028      * searchTime variable.  So we take the high-order bits first.
6029      */
6030     smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
6031     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);       /* ctime */
6032     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
6033     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);       /* atime */
6034     smb_SetSMBParm(outp, 3, searchTime & 0xffff);
6035     smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);       /* mtime */
6036     smb_SetSMBParm(outp, 5, searchTime & 0xffff);
6037
6038     /* now handle file size and allocation size */
6039     smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);              /* file size */
6040     smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
6041     smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);              /* alloc size */
6042     smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
6043
6044     /* file attribute */
6045     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
6046         
6047     /* and finalize stuff */
6048     smb_SetSMBDataLength(outp, 0);
6049     code = 0;
6050
6051   done:
6052     lock_ReleaseMutex(&scp->mx);
6053     cm_ReleaseSCache(scp);
6054     cm_ReleaseUser(userp);
6055     smb_ReleaseFID(fidp);
6056     return code;
6057 }       
6058
6059 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6060 {
6061     unsigned short fid;
6062     smb_fid_t *fidp;
6063     cm_scache_t *scp;
6064     long code = 0;
6065     afs_uint32 searchTime;
6066     time_t unixTime;
6067     cm_user_t *userp;
6068     cm_attr_t attrs;
6069     cm_req_t req;
6070
6071     cm_InitReq(&req);
6072
6073     fid = smb_GetSMBParm(inp, 0);
6074     fid = smb_ChainFID(fid, inp);
6075         
6076     fidp = smb_FindFID(vcp, fid, 0);
6077     if (!fidp)
6078         return CM_ERROR_BADFD;
6079     
6080     lock_ObtainMutex(&fidp->mx);
6081     if (fidp->flags & SMB_FID_IOCTL) {
6082         lock_ReleaseMutex(&fidp->mx);
6083         smb_ReleaseFID(fidp);
6084         return CM_ERROR_BADFD;
6085     }
6086     scp = fidp->scp;
6087     osi_Log2(smb_logp,"smb_ReceiveV3SetAttributes fidp 0x%p scp 0x%p", fidp, scp);
6088     cm_HoldSCache(scp);
6089     lock_ReleaseMutex(&fidp->mx);
6090         
6091     userp = smb_GetUserFromVCP(vcp, inp);
6092         
6093         
6094     /* now prepare to call cm_setattr.  This message only sets various times,
6095      * and AFS only implements mtime, and we'll set the mtime if that's
6096      * requested.  The others we'll ignore.
6097      */
6098     searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
6099         
6100     if (searchTime != 0) {
6101         smb_UnixTimeFromSearchTime(&unixTime, searchTime);
6102
6103         if ( unixTime != -1 ) {
6104             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
6105             attrs.clientModTime = unixTime;
6106             code = cm_SetAttr(scp, &attrs, userp, &req);
6107
6108             osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
6109         } else {
6110             osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
6111         }
6112     }
6113     else 
6114         code = 0;
6115
6116     cm_ReleaseSCache(scp);
6117     cm_ReleaseUser(userp);
6118     smb_ReleaseFID(fidp);
6119     return code;
6120 }
6121
6122 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6123 {
6124     osi_hyper_t offset;
6125     long count, written = 0, total_written = 0;
6126     unsigned short fd;
6127     unsigned pid;
6128     smb_fid_t *fidp;
6129     long code = 0;
6130     cm_user_t *userp;
6131     char *op;
6132     int inDataBlockCount;
6133
6134     fd = smb_GetSMBParm(inp, 2);
6135     count = smb_GetSMBParm(inp, 10);
6136
6137     offset.HighPart = 0;
6138     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6139
6140     if (*inp->wctp == 14) {
6141         /* we have a request with 64-bit file offsets */
6142 #ifdef AFS_LARGEFILES
6143         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6144 #else
6145         if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6146             /* uh oh */
6147             osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
6148             /* we shouldn't have received this op if we didn't specify
6149                largefile support */
6150             return CM_ERROR_BADOP;
6151         }
6152 #endif
6153     }
6154
6155     op = inp->data + smb_GetSMBParm(inp, 11);
6156     inDataBlockCount = count;
6157
6158     osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
6159              fd, offset.HighPart, offset.LowPart, count);
6160         
6161     fd = smb_ChainFID(fd, inp);
6162     fidp = smb_FindFID(vcp, fd, 0);
6163     if (!fidp)
6164         return CM_ERROR_BADFD;
6165         
6166     lock_ObtainMutex(&fidp->mx);
6167     if (fidp->flags & SMB_FID_IOCTL) {
6168         lock_ReleaseMutex(&fidp->mx);
6169         code = smb_IoctlV3Write(fidp, vcp, inp, outp);
6170         smb_ReleaseFID(fidp);
6171         return code;
6172     }
6173     lock_ReleaseMutex(&fidp->mx);
6174     userp = smb_GetUserFromVCP(vcp, inp);
6175
6176     /* special case: 0 bytes transferred means there is no data
6177        transferred.  A slight departure from SMB_COM_WRITE where this
6178        means that we are supposed to truncate the file at this
6179        position. */
6180
6181     {
6182         cm_key_t key;
6183         LARGE_INTEGER LOffset;
6184         LARGE_INTEGER LLength;
6185         cm_scache_t * scp;
6186
6187         pid = ((smb_t *) inp)->pid;
6188         key = cm_GenerateKey(vcp->vcID, pid, fd);
6189
6190         LOffset.HighPart = offset.HighPart;
6191         LOffset.LowPart = offset.LowPart;
6192         LLength.HighPart = 0;
6193         LLength.LowPart = count;
6194
6195         scp = fidp->scp;
6196         lock_ObtainMutex(&scp->mx);
6197         code = cm_LockCheckWrite(scp, LOffset, LLength, key);
6198         lock_ReleaseMutex(&scp->mx);
6199
6200         if (code)
6201             goto done;
6202     }
6203
6204     /*
6205      * Work around bug in NT client
6206      *
6207      * When copying a file, the NT client should first copy the data,
6208      * then copy the last write time.  But sometimes the NT client does
6209      * these in the wrong order, so the data copies would inadvertently
6210      * cause the last write time to be overwritten.  We try to detect this,
6211      * and don't set client mod time if we think that would go against the
6212      * intention.
6213      */
6214     lock_ObtainMutex(&fidp->mx);
6215     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6216         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6217         fidp->scp->clientModTime = time(NULL);
6218     }
6219     lock_ReleaseMutex(&fidp->mx);
6220
6221     code = 0;
6222     while ( code == 0 && count > 0 ) {
6223         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6224         if (code == 0 && written == 0)
6225             code = CM_ERROR_PARTIALWRITE;
6226
6227         offset = LargeIntegerAdd(offset,
6228                                  ConvertLongToLargeInteger(written));
6229         count -= written;
6230         total_written += written;
6231         written = 0;
6232     }
6233
6234  done_writing:
6235     
6236     /* slots 0 and 1 are reserved for request chaining and will be
6237        filled in when we return. */
6238     smb_SetSMBParm(outp, 2, total_written);
6239     smb_SetSMBParm(outp, 3, 0); /* reserved */
6240     smb_SetSMBParm(outp, 4, 0); /* reserved */
6241     smb_SetSMBParm(outp, 5, 0); /* reserved */
6242     smb_SetSMBDataLength(outp, 0);
6243
6244  done:
6245     cm_ReleaseUser(userp);
6246     smb_ReleaseFID(fidp);
6247
6248     return code;
6249 }
6250
6251 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6252 {
6253     osi_hyper_t offset;
6254     long count;
6255     long finalCount = 0;
6256     unsigned short fd;
6257     unsigned pid;
6258     smb_fid_t *fidp;
6259     long code = 0;
6260     cm_user_t *userp;
6261     cm_key_t key;
6262     char *op;
6263         
6264     fd = smb_GetSMBParm(inp, 2);
6265     count = smb_GetSMBParm(inp, 5);
6266     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6267
6268     if (*inp->wctp == 12) {
6269         /* a request with 64-bit offsets */
6270 #ifdef AFS_LARGEFILES
6271         offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
6272
6273         if (LargeIntegerLessThanZero(offset)) {
6274             osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
6275                      offset.HighPart, offset.LowPart);
6276             return CM_ERROR_BADSMB;
6277         }
6278 #else
6279         if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
6280             osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit.  Dropping");
6281             return CM_ERROR_BADSMB;
6282         } else {
6283             offset.HighPart = 0;
6284         }
6285 #endif
6286     } else {
6287         offset.HighPart = 0;
6288     }
6289
6290     osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
6291              fd, offset.HighPart, offset.LowPart, count);
6292
6293     fd = smb_ChainFID(fd, inp);
6294     fidp = smb_FindFID(vcp, fd, 0);
6295     if (!fidp) {
6296         return CM_ERROR_BADFD;
6297     }
6298
6299     pid = ((smb_t *) inp)->pid;
6300     key = cm_GenerateKey(vcp->vcID, pid, fd);
6301     {
6302         LARGE_INTEGER LOffset, LLength;
6303         cm_scache_t *scp;
6304
6305         LOffset.HighPart = offset.HighPart;
6306         LOffset.LowPart = offset.LowPart;
6307         LLength.HighPart = 0;
6308         LLength.LowPart = count;
6309
6310         scp = fidp->scp;
6311         lock_ObtainMutex(&scp->mx);
6312         code = cm_LockCheckRead(scp, LOffset, LLength, key);
6313         lock_ReleaseMutex(&scp->mx);
6314     }
6315
6316     if (code) {
6317         smb_ReleaseFID(fidp);
6318         return code;
6319     }
6320
6321     /* set inp->fid so that later read calls in same msg can find fid */
6322     inp->fid = fd;
6323
6324     lock_ObtainMutex(&fidp->mx);
6325     if (fidp->flags & SMB_FID_IOCTL) {
6326         lock_ReleaseMutex(&fidp->mx);
6327         code = smb_IoctlV3Read(fidp, vcp, inp, outp);
6328         smb_ReleaseFID(fidp);
6329         return code;
6330     }
6331     lock_ReleaseMutex(&fidp->mx);
6332
6333     userp = smb_GetUserFromVCP(vcp, inp);
6334
6335     /* 0 and 1 are reserved for request chaining, were setup by our caller,
6336      * and will be further filled in after we return.
6337      */
6338     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
6339     smb_SetSMBParm(outp, 3, 0); /* resvd */
6340     smb_SetSMBParm(outp, 4, 0); /* resvd */
6341     smb_SetSMBParm(outp, 5, count);     /* # of bytes we're going to read */
6342     /* fill in #6 when we have all the parameters' space reserved */
6343     smb_SetSMBParm(outp, 7, 0); /* resv'd */
6344     smb_SetSMBParm(outp, 8, 0); /* resv'd */
6345     smb_SetSMBParm(outp, 9, 0); /* resv'd */
6346     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
6347     smb_SetSMBParm(outp, 11, 0);        /* reserved */
6348
6349     /* get op ptr after putting in the parms, since otherwise we don't
6350      * know where the data really is.
6351      */
6352     op = smb_GetSMBData(outp, NULL);
6353         
6354     /* now fill in offset from start of SMB header to first data byte (to op) */
6355     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
6356
6357     /* set the packet data length the count of the # of bytes */
6358     smb_SetSMBDataLength(outp, count);
6359
6360     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6361
6362     /* fix some things up */
6363     smb_SetSMBParm(outp, 5, finalCount);
6364     smb_SetSMBDataLength(outp, finalCount);
6365
6366     cm_ReleaseUser(userp);
6367     smb_ReleaseFID(fidp);
6368     return code;
6369 }   
6370         
6371 /*
6372  * Values for createDisp, copied from NTDDK.H
6373  */
6374 #define  FILE_SUPERSEDE 0       // (???)
6375 #define  FILE_OPEN      1       // (open)
6376 #define  FILE_CREATE    2       // (exclusive)
6377 #define  FILE_OPEN_IF   3       // (non-exclusive)
6378 #define  FILE_OVERWRITE 4       // (open & truncate, but do not create)
6379 #define  FILE_OVERWRITE_IF 5    // (open & truncate, or create)
6380
6381 /* Flags field */
6382 #define REQUEST_OPLOCK 2
6383 #define REQUEST_BATCH_OPLOCK 4
6384 #define OPEN_DIRECTORY 8
6385 #define EXTENDED_RESPONSE_REQUIRED 0x10
6386
6387 /* CreateOptions field. */
6388 #define FILE_DIRECTORY_FILE       0x0001
6389 #define FILE_WRITE_THROUGH        0x0002
6390 #define FILE_SEQUENTIAL_ONLY      0x0004
6391 #define FILE_NON_DIRECTORY_FILE   0x0040
6392 #define FILE_NO_EA_KNOWLEDGE      0x0200
6393 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
6394 #define FILE_RANDOM_ACCESS        0x0800
6395 #define FILE_DELETE_ON_CLOSE      0x1000
6396 #define FILE_OPEN_BY_FILE_ID      0x2000
6397
6398 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6399 {
6400     char *pathp, *realPathp;
6401     long code = 0;
6402     cm_space_t *spacep;
6403     cm_user_t *userp;
6404     cm_scache_t *dscp;          /* parent dir */
6405     cm_scache_t *scp;           /* file to create or open */
6406     cm_scache_t *targetScp;     /* if scp is a symlink */
6407     cm_attr_t setAttr;
6408     char *lastNamep;
6409     char *treeStartp;
6410     unsigned short nameLength;
6411     unsigned int flags;
6412     unsigned int requestOpLock;
6413     unsigned int requestBatchOpLock;
6414     unsigned int mustBeDir;
6415     unsigned int extendedRespRequired;
6416     unsigned int treeCreate;
6417     int realDirFlag;
6418     unsigned int desiredAccess;
6419     unsigned int extAttributes;
6420     unsigned int createDisp;
6421     unsigned int createOptions;
6422     unsigned int shareAccess;
6423     int initialModeBits;
6424     unsigned short baseFid;
6425     smb_fid_t *baseFidp;
6426     smb_fid_t *fidp;
6427     cm_scache_t *baseDirp;
6428     unsigned short openAction;
6429     int parmSlot;
6430     long fidflags;
6431     FILETIME ft;
6432     LARGE_INTEGER sz;
6433     char *tidPathp;
6434     BOOL foundscp;
6435     cm_req_t req;
6436     int created = 0;
6437     cm_lock_data_t *ldp = NULL;
6438
6439     cm_InitReq(&req);
6440
6441     /* This code is very long and has a lot of if-then-else clauses
6442      * scp and dscp get reused frequently and we need to ensure that 
6443      * we don't lose a reference.  Start by ensuring that they are NULL.
6444      */
6445     scp = NULL;
6446     dscp = NULL;
6447     treeCreate = FALSE;
6448     foundscp = FALSE;
6449
6450     nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
6451     flags = smb_GetSMBOffsetParm(inp, 3, 1)
6452         | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
6453     requestOpLock = flags & REQUEST_OPLOCK;
6454     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6455     mustBeDir = flags & OPEN_DIRECTORY;
6456     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6457
6458     /*
6459      * Why all of a sudden 32-bit FID?
6460      * We will reject all bits higher than 16.
6461      */
6462     if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
6463         return CM_ERROR_INVAL;
6464     baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
6465     desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
6466         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6467     extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
6468         | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
6469     shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
6470         | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
6471     createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
6472         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
6473     createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
6474         | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
6475
6476     /* mustBeDir is never set; createOptions directory bit seems to be
6477      * more important
6478      */
6479     if (createOptions & FILE_DIRECTORY_FILE)
6480         realDirFlag = 1;
6481     else if (createOptions & FILE_NON_DIRECTORY_FILE)
6482         realDirFlag = 0;
6483     else
6484         realDirFlag = -1;
6485
6486     /*
6487      * compute initial mode bits based on read-only flag in
6488      * extended attributes
6489      */
6490     initialModeBits = 0666;
6491     if (extAttributes & SMB_ATTR_READONLY) 
6492         initialModeBits &= ~0222;
6493
6494     pathp = smb_GetSMBData(inp, NULL);
6495     /* Sometimes path is not null-terminated, so we make a copy. */
6496     realPathp = malloc(nameLength+1);
6497     memcpy(realPathp, pathp, nameLength);
6498     realPathp[nameLength] = 0;
6499     if (smb_StoreAnsiFilenames)
6500         OemToChar(realPathp,realPathp);
6501
6502     spacep = inp->spacep;
6503     smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6504
6505     osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
6506     osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
6507     osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
6508
6509     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
6510         /* special case magic file name for receiving IOCTL requests
6511          * (since IOCTL calls themselves aren't getting through).
6512          */
6513         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6514         smb_SetupIoctlFid(fidp, spacep);
6515         osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
6516
6517         /* set inp->fid so that later read calls in same msg can find fid */
6518         inp->fid = fidp->fid;
6519
6520         /* out parms */
6521         parmSlot = 2;
6522         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
6523         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6524         smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
6525         /* times */
6526         memset(&ft, 0, sizeof(ft));
6527         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6528         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6529         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6530         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6531         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
6532         sz.HighPart = 0x7fff; sz.LowPart = 0;
6533         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
6534         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
6535         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
6536         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
6537         smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
6538         smb_SetSMBDataLength(outp, 0);
6539
6540         /* clean up fid reference */
6541         smb_ReleaseFID(fidp);
6542         free(realPathp);
6543         return 0;
6544     }
6545
6546 #ifdef DEBUG_VERBOSE
6547     {
6548         char *hexp, *asciip;
6549         asciip = (lastNamep? lastNamep : realPathp);
6550         hexp = osi_HexifyString( asciip );
6551         DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6552         free(hexp);
6553     }
6554 #endif
6555
6556     userp = smb_GetUserFromVCP(vcp, inp);
6557     if (!userp) {
6558         osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6559         free(realPathp);
6560         return CM_ERROR_INVAL;
6561     }
6562
6563     if (baseFid == 0) {
6564         baseFidp = NULL;
6565         baseDirp = cm_data.rootSCachep;
6566         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6567         if (code == CM_ERROR_TIDIPC) {
6568             /* Attempt to use a TID allocated for IPC.  The client
6569              * is probably looking for DCE RPC end points which we
6570              * don't support OR it could be looking to make a DFS
6571              * referral request. 
6572              */
6573             osi_Log0(smb_logp, "NTCreateX received IPC TID");
6574 #ifndef DFS_SUPPORT
6575             free(realPathp);
6576             cm_ReleaseUser(userp);
6577             return CM_ERROR_NOSUCHFILE;
6578 #endif /* DFS_SUPPORT */
6579         }
6580     } else {
6581         baseFidp = smb_FindFID(vcp, baseFid, 0);
6582         if (!baseFidp) {
6583             osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6584             free(realPathp);
6585             cm_ReleaseUser(userp);
6586             return CM_ERROR_INVAL;
6587         }       
6588         baseDirp = baseFidp->scp;
6589         tidPathp = NULL;
6590     }
6591
6592     osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6593
6594     /* compute open mode */
6595     fidflags = 0;
6596     if (desiredAccess & DELETE)
6597         fidflags |= SMB_FID_OPENDELETE;
6598     if (desiredAccess & AFS_ACCESS_READ)
6599         fidflags |= SMB_FID_OPENREAD_LISTDIR;
6600     if (desiredAccess & AFS_ACCESS_WRITE)
6601         fidflags |= SMB_FID_OPENWRITE;
6602     if (createOptions & FILE_DELETE_ON_CLOSE)
6603         fidflags |= SMB_FID_DELONCLOSE;
6604     if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
6605         fidflags |= SMB_FID_SEQUENTIAL;
6606     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
6607         fidflags |= SMB_FID_RANDOM;
6608
6609     /* and the share mode */
6610     if (shareAccess & FILE_SHARE_READ)
6611         fidflags |= SMB_FID_SHARE_READ;
6612     if (shareAccess & FILE_SHARE_WRITE)
6613         fidflags |= SMB_FID_SHARE_WRITE;
6614
6615     osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6616     code = 0;
6617
6618     /* For an exclusive create, we want to do a case sensitive match for the last component. */
6619     if ( createDisp == FILE_CREATE || 
6620          createDisp == FILE_OVERWRITE ||
6621          createDisp == FILE_OVERWRITE_IF) {
6622         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6623                         userp, tidPathp, &req, &dscp);
6624         if (code == 0) {
6625 #ifdef DFS_SUPPORT
6626             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6627                 cm_ReleaseSCache(dscp);
6628                 cm_ReleaseUser(userp);
6629                 free(realPathp);
6630                 if (baseFidp) 
6631                     smb_ReleaseFID(baseFidp);
6632                 if ( WANTS_DFS_PATHNAMES(inp) )
6633                     return CM_ERROR_PATH_NOT_COVERED;
6634                 else
6635                     return CM_ERROR_BADSHARENAME;
6636             }
6637 #endif /* DFS_SUPPORT */
6638             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6639                              userp, &req, &scp);
6640             if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
6641                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
6642                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6643                 if (code == 0 && realDirFlag == 1) {
6644                     cm_ReleaseSCache(scp);
6645                     cm_ReleaseSCache(dscp);
6646                     cm_ReleaseUser(userp);
6647                     free(realPathp);
6648                     if (baseFidp) 
6649                         smb_ReleaseFID(baseFidp);
6650                     return CM_ERROR_EXISTS;
6651                 }
6652             }
6653         }
6654         /* we have both scp and dscp */
6655     } else {
6656         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6657                         userp, tidPathp, &req, &scp);
6658 #ifdef DFS_SUPPORT
6659         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6660             cm_ReleaseSCache(scp);
6661             cm_ReleaseUser(userp);
6662             free(realPathp);
6663             if (baseFidp) 
6664                 smb_ReleaseFID(baseFidp);
6665             if ( WANTS_DFS_PATHNAMES(inp) )
6666                 return CM_ERROR_PATH_NOT_COVERED;
6667             else
6668                 return CM_ERROR_BADSHARENAME;
6669         }
6670 #endif /* DFS_SUPPORT */
6671         /* we might have scp but not dscp */
6672     }
6673
6674     if (scp)
6675         foundscp = TRUE;
6676     
6677     if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6678         /* look up parent directory */
6679         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6680          * the immediate parent.  We have to work our way up realPathp until we hit something that we
6681          * recognize.
6682          */
6683
6684         /* we might or might not have scp */
6685
6686         if (dscp == NULL) {
6687             do {
6688                 char *tp;
6689
6690                 code = cm_NameI(baseDirp, spacep->data,
6691                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6692                              userp, tidPathp, &req, &dscp);
6693
6694 #ifdef DFS_SUPPORT
6695                 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6696                     if (scp)
6697                         cm_ReleaseSCache(scp);
6698                     cm_ReleaseSCache(dscp);
6699                     cm_ReleaseUser(userp);
6700                     free(realPathp);
6701                     if (baseFidp) 
6702                         smb_ReleaseFID(baseFidp);
6703                     if ( WANTS_DFS_PATHNAMES(inp) )
6704                         return CM_ERROR_PATH_NOT_COVERED;
6705                     else
6706                         return CM_ERROR_BADSHARENAME;
6707                 }
6708 #endif /* DFS_SUPPORT */
6709
6710                 if (code && 
6711                      (tp = strrchr(spacep->data,'\\')) &&
6712                      (createDisp == FILE_CREATE) &&
6713                      (realDirFlag == 1)) {
6714                     *tp++ = 0;
6715                     treeCreate = TRUE;
6716                     treeStartp = realPathp + (tp - spacep->data);
6717
6718                     if (*tp && !smb_IsLegalFilename(tp)) {
6719                         cm_ReleaseUser(userp);
6720                         if (baseFidp) 
6721                             smb_ReleaseFID(baseFidp);
6722                         free(realPathp);
6723                         if (scp)
6724                             cm_ReleaseSCache(scp);
6725                         return CM_ERROR_BADNTFILENAME;
6726                     }
6727                     code = 0;
6728                 }
6729             } while (dscp == NULL && code == 0);
6730         } else
6731             code = 0;
6732
6733         /* we might have scp and we might have dscp */
6734
6735         if (baseFidp)
6736             smb_ReleaseFID(baseFidp);
6737
6738         if (code) {
6739             osi_Log0(smb_logp,"NTCreateX parent not found");
6740             if (scp)
6741                 cm_ReleaseSCache(scp);
6742             if (dscp)
6743                 cm_ReleaseSCache(dscp);
6744             cm_ReleaseUser(userp);
6745             free(realPathp);
6746             return code;
6747         }
6748
6749         if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6750             /* A file exists where we want a directory. */
6751             if (scp)
6752                 cm_ReleaseSCache(scp);
6753             cm_ReleaseSCache(dscp);
6754             cm_ReleaseUser(userp);
6755             free(realPathp);
6756             return CM_ERROR_EXISTS;
6757         }
6758
6759         if (!lastNamep) 
6760             lastNamep = realPathp;
6761         else 
6762             lastNamep++;
6763
6764         if (!smb_IsLegalFilename(lastNamep)) {
6765             if (scp)
6766                 cm_ReleaseSCache(scp);
6767             if (dscp)
6768                 cm_ReleaseSCache(dscp);
6769             cm_ReleaseUser(userp);
6770             free(realPathp);
6771             return CM_ERROR_BADNTFILENAME;
6772         }
6773
6774         if (!foundscp && !treeCreate) {
6775             if ( createDisp == FILE_CREATE || 
6776                  createDisp == FILE_OVERWRITE ||
6777                  createDisp == FILE_OVERWRITE_IF) 
6778             {
6779                 code = cm_Lookup(dscp, lastNamep,
6780                                   CM_FLAG_FOLLOW, userp, &req, &scp);
6781             } else {
6782                 code = cm_Lookup(dscp, lastNamep,
6783                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6784                                  userp, &req, &scp);
6785             }
6786             if (code && (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH)) {
6787                 if (dscp)
6788                     cm_ReleaseSCache(dscp);
6789                 cm_ReleaseUser(userp);
6790                 free(realPathp);
6791                 return code;
6792             }
6793         }
6794         /* we have scp and dscp */
6795     } else {
6796         /* we have scp but not dscp */
6797         if (baseFidp)
6798             smb_ReleaseFID(baseFidp);
6799     }
6800
6801     /* if we get here, if code is 0, the file exists and is represented by
6802      * scp.  Otherwise, we have to create it.  The dir may be represented
6803      * by dscp, or we may have found the file directly.  If code is non-zero,
6804      * scp is NULL.
6805      */
6806     if (code == 0 && !treeCreate) {
6807         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6808         if (code) {
6809             if (dscp)
6810                 cm_ReleaseSCache(dscp);
6811             if (scp)
6812                 cm_ReleaseSCache(scp);
6813             cm_ReleaseUser(userp);
6814             free(realPathp);
6815             return code;
6816         }
6817
6818         if (createDisp == FILE_CREATE) {
6819             /* oops, file shouldn't be there */
6820             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6821             if (dscp)
6822                 cm_ReleaseSCache(dscp);
6823             if (scp)
6824                 cm_ReleaseSCache(scp);
6825             cm_ReleaseUser(userp);
6826             free(realPathp);
6827             return CM_ERROR_EXISTS;
6828         }
6829
6830         if ( createDisp == FILE_OVERWRITE || 
6831              createDisp == FILE_OVERWRITE_IF) {
6832
6833             setAttr.mask = CM_ATTRMASK_LENGTH;
6834             setAttr.length.LowPart = 0;
6835             setAttr.length.HighPart = 0;
6836             /* now watch for a symlink */
6837             code = 0;
6838             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6839                 targetScp = 0;
6840                 osi_assert(dscp != NULL);
6841                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6842                 if (code == 0) {
6843                     /* we have a more accurate file to use (the
6844                      * target of the symbolic link).  Otherwise,
6845                      * we'll just use the symlink anyway.
6846                      */
6847                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
6848                               scp, targetScp);
6849                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
6850                     cm_ReleaseSCache(scp);
6851                     scp = targetScp;
6852                     code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
6853                     if (code) {
6854                         if (dscp)
6855                             cm_ReleaseSCache(dscp);
6856                         if (scp)
6857                             cm_ReleaseSCache(scp);
6858                         cm_ReleaseUser(userp);
6859                         free(realPathp);
6860                         return code;
6861                     }
6862                 }
6863             }
6864             code = cm_SetAttr(scp, &setAttr, userp, &req);
6865             openAction = 3;     /* truncated existing file */
6866         }
6867         else 
6868             openAction = 1;     /* found existing file */
6869
6870     } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6871         /* don't create if not found */
6872         if (dscp)
6873             cm_ReleaseSCache(dscp);
6874         if (scp)
6875             cm_ReleaseSCache(scp);
6876         cm_ReleaseUser(userp);
6877         free(realPathp);
6878         return CM_ERROR_NOSUCHFILE;
6879     } else if (realDirFlag == 0 || realDirFlag == -1) {
6880         osi_assert(dscp != NULL);
6881         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6882                   osi_LogSaveString(smb_logp, lastNamep));
6883         openAction = 2;         /* created file */
6884         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6885         setAttr.clientModTime = time(NULL);
6886         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6887         if (code == 0) {
6888             created = 1;
6889             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6890                 smb_NotifyChange(FILE_ACTION_ADDED,
6891                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6892                                  dscp, lastNamep, NULL, TRUE);
6893         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6894             /* Not an exclusive create, and someone else tried
6895              * creating it already, then we open it anyway.  We
6896              * don't bother retrying after this, since if this next
6897              * fails, that means that the file was deleted after we
6898              * started this call.
6899              */
6900             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6901                               userp, &req, &scp);
6902             if (code == 0) {
6903                 if (createDisp == FILE_OVERWRITE_IF) {
6904                     setAttr.mask = CM_ATTRMASK_LENGTH;
6905                     setAttr.length.LowPart = 0;
6906                     setAttr.length.HighPart = 0;
6907
6908                     /* now watch for a symlink */
6909                     code = 0;
6910                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6911                         targetScp = 0;
6912                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6913                         if (code == 0) {
6914                             /* we have a more accurate file to use (the
6915                              * target of the symbolic link).  Otherwise,
6916                              * we'll just use the symlink anyway.
6917                              */
6918                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
6919                                       scp, targetScp);
6920                             cm_ReleaseSCache(scp);
6921                             scp = targetScp;
6922                         }
6923                     }
6924                     code = cm_SetAttr(scp, &setAttr, userp, &req);
6925                 }
6926             }   /* lookup succeeded */
6927         }
6928     } else {
6929         char *tp, *pp;
6930         char *cp; /* This component */
6931         int clen = 0; /* length of component */
6932         cm_scache_t *tscp1, *tscp2;
6933         int isLast = 0;
6934
6935         /* create directory */
6936         if ( !treeCreate ) 
6937             treeStartp = lastNamep;
6938         osi_assert(dscp != NULL);
6939         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6940                   osi_LogSaveString(smb_logp, treeStartp));
6941         openAction = 2;         /* created directory */
6942
6943         /* if the request is to create the root directory 
6944          * it will appear as a directory name of the nul-string
6945          * and a code of CM_ERROR_NOSUCHFILE
6946          */
6947         if ( !*treeStartp && (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH))
6948             code = CM_ERROR_EXISTS;
6949
6950         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6951         setAttr.clientModTime = time(NULL);
6952
6953         pp = treeStartp;
6954         cp = spacep->data;
6955         tscp1 = dscp;
6956         cm_HoldSCache(tscp1);
6957         tscp2 = NULL;
6958
6959         while (pp && *pp) {
6960             tp = strchr(pp, '\\');
6961             if (!tp) {
6962                 strcpy(cp,pp);
6963                 clen = (int)strlen(cp);
6964                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
6965             } else {
6966                 clen = (int)(tp - pp);
6967                 strncpy(cp,pp,clen);
6968                 *(cp + clen) = 0;
6969                 tp++;
6970             }
6971             pp = tp;
6972
6973             if (clen == 0) 
6974                 continue; /* the supplied path can't have consecutive slashes either , but */
6975
6976             /* cp is the next component to be created. */
6977             code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6978             if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6979                 smb_NotifyChange(FILE_ACTION_ADDED,
6980                                   FILE_NOTIFY_CHANGE_DIR_NAME,
6981                                   tscp1, cp, NULL, TRUE);
6982             if (code == 0 || 
6983                  (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6984                 /* Not an exclusive create, and someone else tried
6985                  * creating it already, then we open it anyway.  We
6986                  * don't bother retrying after this, since if this next
6987                  * fails, that means that the file was deleted after we
6988                  * started this call.
6989                  */
6990                 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6991                                   userp, &req, &tscp2);
6992             }       
6993             if (code) 
6994                 break;
6995
6996             if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6997                 cm_ReleaseSCache(tscp1);
6998                 tscp1 = tscp2; /* Newly created directory will be next parent */
6999                 /* the hold is transfered to tscp1 from tscp2 */
7000             }
7001         }
7002
7003         if (dscp)
7004             cm_ReleaseSCache(dscp);
7005         dscp = tscp1;
7006         if (scp)
7007             cm_ReleaseSCache(scp);
7008         scp = tscp2;
7009         /* 
7010          * if we get here and code == 0, then scp is the last directory created, and dscp is the
7011          * parent of scp.
7012          */
7013     }
7014
7015     if (code) {
7016         /* something went wrong creating or truncating the file */
7017         if (ldp)
7018             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7019         if (scp) 
7020             cm_ReleaseSCache(scp);
7021         if (dscp) 
7022             cm_ReleaseSCache(dscp);
7023         cm_ReleaseUser(userp);
7024         free(realPathp);
7025         return code;
7026     }
7027
7028     /* make sure we have file vs. dir right (only applies for single component case) */
7029     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7030         /* now watch for a symlink */
7031         code = 0;
7032         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7033             cm_scache_t * targetScp = 0;
7034             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7035             if (code == 0) {
7036                 /* we have a more accurate file to use (the
7037                 * target of the symbolic link).  Otherwise,
7038                 * we'll just use the symlink anyway.
7039                 */
7040                 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
7041                 if (ldp)
7042                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7043                 cm_ReleaseSCache(scp);
7044                 scp = targetScp;
7045             }
7046         }
7047
7048         if (scp->fileType != CM_SCACHETYPE_FILE) {
7049             if (ldp)
7050                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7051             if (dscp)
7052                 cm_ReleaseSCache(dscp);
7053             cm_ReleaseSCache(scp);
7054             cm_ReleaseUser(userp);
7055             free(realPathp);
7056             return CM_ERROR_ISDIR;
7057         }
7058     }
7059
7060     /* (only applies to single component case) */
7061     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7062         if (ldp)
7063             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7064         cm_ReleaseSCache(scp);
7065         if (dscp)
7066             cm_ReleaseSCache(dscp);
7067         cm_ReleaseUser(userp);
7068         free(realPathp);
7069         return CM_ERROR_NOTDIR;
7070     }
7071
7072     /* open the file itself */
7073     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7074     osi_assert(fidp);
7075
7076     /* save a reference to the user */
7077     cm_HoldUser(userp);
7078     fidp->userp = userp;
7079
7080     /* If we are restricting sharing, we should do so with a suitable
7081        share lock. */
7082     if (scp->fileType == CM_SCACHETYPE_FILE &&
7083         !(fidflags & SMB_FID_SHARE_WRITE)) {
7084         cm_key_t key;
7085         LARGE_INTEGER LOffset, LLength;
7086         int sLockType;
7087
7088         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7089         LOffset.LowPart = SMB_FID_QLOCK_LOW;
7090         LLength.HighPart = 0;
7091         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7092
7093         /* If we are not opening the file for writing, then we don't
7094            try to get an exclusive lock.  Noone else should be able to
7095            get an exclusive lock on the file anyway, although someone
7096            else can get a shared lock. */
7097         if ((fidflags & SMB_FID_SHARE_READ) ||
7098             !(fidflags & SMB_FID_OPENWRITE)) {
7099             sLockType = LOCKING_ANDX_SHARED_LOCK;
7100         } else {
7101             sLockType = 0;
7102         }
7103
7104         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7105         
7106         lock_ObtainMutex(&scp->mx);
7107         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7108         lock_ReleaseMutex(&scp->mx);
7109
7110         if (code) {
7111             if (ldp)
7112                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7113             cm_ReleaseSCache(scp);
7114             if (dscp)
7115                 cm_ReleaseSCache(dscp);
7116             cm_ReleaseUser(userp);
7117             /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
7118             smb_CloseFID(vcp, fidp, NULL, 0);
7119             smb_ReleaseFID(fidp);
7120             free(realPathp);
7121             return code;
7122         }
7123     }
7124
7125     /* Now its safe to release the file server lock obtained by cm_CheckNTOpen() */
7126     if (ldp)
7127         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7128
7129     lock_ObtainMutex(&fidp->mx);
7130     /* save a pointer to the vnode */
7131     fidp->scp = scp;    /* Hold transfered to fidp->scp and no longer needed */
7132     lock_ObtainMutex(&scp->mx);
7133     scp->flags |= CM_SCACHEFLAG_SMB_FID;
7134     lock_ReleaseMutex(&scp->mx);
7135     osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p scp 0x%p", fidp, scp);
7136
7137     fidp->flags = fidflags;
7138
7139     /* remember if the file was newly created */
7140     if (created)
7141         fidp->flags |= SMB_FID_CREATED;
7142
7143     /* save parent dir and pathname for delete or change notification */
7144     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7145         osi_Log2(smb_logp,"smb_ReceiveNTCreateX fidp 0x%p dscp 0x%p", fidp, dscp);
7146         fidp->flags |= SMB_FID_NTOPEN;
7147         fidp->NTopen_dscp = dscp;
7148         dscp = NULL;
7149         fidp->NTopen_pathp = strdup(lastNamep);
7150     }
7151     fidp->NTopen_wholepathp = realPathp;
7152     lock_ReleaseMutex(&fidp->mx);
7153
7154     /* we don't need this any longer */
7155     if (dscp) {
7156         cm_ReleaseSCache(dscp);
7157         dscp = NULL;
7158     }
7159
7160     cm_Open(scp, 0, userp);
7161
7162     /* set inp->fid so that later read calls in same msg can find fid */
7163     inp->fid = fidp->fid;
7164
7165     /* out parms */
7166     parmSlot = 2;
7167     lock_ObtainMutex(&scp->mx);
7168     smb_SetSMBParmByte(outp, parmSlot, 0);      /* oplock */
7169     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
7170     smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
7171     smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7172     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7173     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7174     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7175     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
7176     smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
7177     parmSlot += 2;
7178     smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7179     smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
7180     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* filetype */
7181     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* dev state */
7182     smb_SetSMBParmByte(outp, parmSlot,
7183                         (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7184                          scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7185                          scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
7186     lock_ReleaseMutex(&scp->mx);
7187     smb_SetSMBDataLength(outp, 0);
7188
7189     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
7190               osi_LogSaveString(smb_logp, realPathp));
7191
7192     cm_ReleaseUser(userp);
7193     smb_ReleaseFID(fidp);
7194
7195     /* Can't free realPathp if we get here since
7196        fidp->NTopen_wholepathp is pointing there */
7197
7198     /* leave scp held since we put it in fidp->scp */
7199     return 0;
7200 }       
7201
7202 /*
7203  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
7204  * Instead, ultimately, would like to use a subroutine for common code.
7205  */
7206 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7207 {
7208     char *pathp, *realPathp;
7209     long code = 0;
7210     cm_space_t *spacep;
7211     cm_user_t *userp;
7212     cm_scache_t *dscp;          /* parent dir */
7213     cm_scache_t *scp;           /* file to create or open */
7214     cm_scache_t *targetScp;     /* if scp is a symlink */
7215     cm_attr_t setAttr;
7216     char *lastNamep;
7217     unsigned long nameLength;
7218     unsigned int flags;
7219     unsigned int requestOpLock;
7220     unsigned int requestBatchOpLock;
7221     unsigned int mustBeDir;
7222     unsigned int extendedRespRequired;
7223     int realDirFlag;
7224     unsigned int desiredAccess;
7225 #ifdef DEBUG_VERBOSE    
7226     unsigned int allocSize;
7227 #endif
7228     unsigned int shareAccess;
7229     unsigned int extAttributes;
7230     unsigned int createDisp;
7231 #ifdef DEBUG_VERBOSE
7232     unsigned int sdLen;
7233 #endif
7234     unsigned int createOptions;
7235     int initialModeBits;
7236     unsigned short baseFid;
7237     smb_fid_t *baseFidp;
7238     smb_fid_t *fidp;
7239     cm_scache_t *baseDirp;
7240     unsigned short openAction;
7241     int parmSlot;
7242     long fidflags;
7243     FILETIME ft;
7244     char *tidPathp;
7245     BOOL foundscp;
7246     int parmOffset, dataOffset;
7247     char *parmp;
7248     ULONG *lparmp;
7249     char *outData;
7250     cm_req_t req;
7251     int created = 0;
7252     cm_lock_data_t *ldp = NULL;
7253
7254     cm_InitReq(&req);
7255
7256     foundscp = FALSE;
7257     scp = NULL;
7258
7259     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7260         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7261     parmp = inp->data + parmOffset;
7262     lparmp = (ULONG *) parmp;
7263
7264     flags = lparmp[0];
7265     requestOpLock = flags & REQUEST_OPLOCK;
7266     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
7267     mustBeDir = flags & OPEN_DIRECTORY;
7268     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
7269
7270     /*
7271      * Why all of a sudden 32-bit FID?
7272      * We will reject all bits higher than 16.
7273      */
7274     if (lparmp[1] & 0xFFFF0000)
7275         return CM_ERROR_INVAL;
7276     baseFid = (unsigned short)lparmp[1];
7277     desiredAccess = lparmp[2];
7278 #ifdef DEBUG_VERBOSE
7279     allocSize = lparmp[3];
7280 #endif /* DEBUG_VERSOSE */
7281     extAttributes = lparmp[5];
7282     shareAccess = lparmp[6];
7283     createDisp = lparmp[7];
7284     createOptions = lparmp[8];
7285 #ifdef DEBUG_VERBOSE
7286     sdLen = lparmp[9];
7287 #endif
7288     nameLength = lparmp[11];
7289
7290 #ifdef DEBUG_VERBOSE
7291     osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
7292     osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
7293     osi_Log1(smb_logp,"... flags[%x]",flags);
7294 #endif
7295
7296     /* mustBeDir is never set; createOptions directory bit seems to be
7297      * more important
7298      */
7299     if (createOptions & FILE_DIRECTORY_FILE)
7300         realDirFlag = 1;
7301     else if (createOptions & FILE_NON_DIRECTORY_FILE)
7302         realDirFlag = 0;
7303     else
7304         realDirFlag = -1;
7305
7306     /*
7307      * compute initial mode bits based on read-only flag in
7308      * extended attributes
7309      */
7310     initialModeBits = 0666;
7311     if (extAttributes & SMB_ATTR_READONLY) 
7312         initialModeBits &= ~0222;
7313
7314     pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
7315     /* Sometimes path is not null-terminated, so we make a copy. */
7316     realPathp = malloc(nameLength+1);
7317     memcpy(realPathp, pathp, nameLength);
7318     realPathp[nameLength] = 0;
7319     if (smb_StoreAnsiFilenames)
7320         OemToChar(realPathp,realPathp);
7321
7322     spacep = cm_GetSpace();
7323     smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
7324
7325     /*
7326      * Nothing here to handle SMB_IOCTL_FILENAME.
7327      * Will add it if necessary.
7328      */
7329
7330 #ifdef DEBUG_VERBOSE
7331     {
7332         char *hexp, *asciip;
7333         asciip = (lastNamep? lastNamep : realPathp);
7334         hexp = osi_HexifyString( asciip );
7335         DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
7336         free(hexp);
7337     }
7338 #endif
7339
7340     userp = smb_GetUserFromVCP(vcp, inp);
7341     if (!userp) {
7342         osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
7343         free(realPathp);
7344         return CM_ERROR_INVAL;
7345     }
7346
7347     if (baseFid == 0) {
7348         baseFidp = NULL;
7349         baseDirp = cm_data.rootSCachep;
7350         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7351         if (code == CM_ERROR_TIDIPC) {
7352             /* Attempt to use a TID allocated for IPC.  The client
7353              * is probably looking for DCE RPC end points which we
7354              * don't support OR it could be looking to make a DFS
7355              * referral request. 
7356              */
7357             osi_Log0(smb_logp, "NTTranCreate received IPC TID");
7358 #ifndef DFS_SUPPORT
7359             free(realPathp);
7360             cm_ReleaseUser(userp);
7361             return CM_ERROR_NOSUCHPATH;
7362 #endif 
7363         }
7364     } else {
7365         baseFidp = smb_FindFID(vcp, baseFid, 0);
7366         if (!baseFidp) {
7367             osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
7368             free(realPathp);
7369             cm_ReleaseUser(userp);
7370             return CM_ERROR_INVAL;
7371         }       
7372         baseDirp = baseFidp->scp;
7373         tidPathp = NULL;
7374     }
7375
7376     /* compute open mode */
7377     fidflags = 0;
7378     if (desiredAccess & DELETE)
7379         fidflags |= SMB_FID_OPENDELETE;
7380     if (desiredAccess & AFS_ACCESS_READ)
7381         fidflags |= SMB_FID_OPENREAD_LISTDIR;
7382     if (desiredAccess & AFS_ACCESS_WRITE)
7383         fidflags |= SMB_FID_OPENWRITE;
7384     if (createOptions & FILE_DELETE_ON_CLOSE)
7385         fidflags |= SMB_FID_DELONCLOSE;
7386     if (createOptions & FILE_SEQUENTIAL_ONLY && !(createOptions & FILE_RANDOM_ACCESS))
7387         fidflags |= SMB_FID_SEQUENTIAL;
7388     if (createOptions & FILE_RANDOM_ACCESS && !(createOptions & FILE_SEQUENTIAL_ONLY))
7389         fidflags |= SMB_FID_RANDOM;
7390
7391     /* And the share mode */
7392     if (shareAccess & FILE_SHARE_READ)
7393         fidflags |= SMB_FID_SHARE_READ;
7394     if (shareAccess & FILE_SHARE_WRITE)
7395         fidflags |= SMB_FID_SHARE_WRITE;
7396
7397     dscp = NULL;
7398     code = 0;
7399     if ( createDisp == FILE_OPEN || 
7400          createDisp == FILE_OVERWRITE ||
7401          createDisp == FILE_OVERWRITE_IF) {
7402         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7403                         userp, tidPathp, &req, &dscp);
7404         if (code == 0) {
7405 #ifdef DFS_SUPPORT
7406             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7407                 cm_ReleaseSCache(dscp);
7408                 cm_ReleaseUser(userp);
7409                 free(realPathp);
7410                 if (baseFidp)
7411                     smb_ReleaseFID(baseFidp);
7412                 if ( WANTS_DFS_PATHNAMES(inp) )
7413                     return CM_ERROR_PATH_NOT_COVERED;
7414                 else
7415                     return CM_ERROR_BADSHARENAME;
7416             }
7417 #endif /* DFS_SUPPORT */
7418             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
7419                              userp, &req, &scp);
7420             if (code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) {
7421                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
7422                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
7423                 if (code == 0 && realDirFlag == 1) {
7424                     cm_ReleaseSCache(scp);
7425                     cm_ReleaseSCache(dscp);
7426                     cm_ReleaseUser(userp);
7427                     free(realPathp);
7428                     if (baseFidp)
7429                         smb_ReleaseFID(baseFidp);
7430                     return CM_ERROR_EXISTS;
7431                 }
7432             }
7433         } else 
7434             dscp = NULL;
7435     } else {
7436         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7437                         userp, tidPathp, &req, &scp);
7438 #ifdef DFS_SUPPORT
7439         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
7440             cm_ReleaseSCache(scp);
7441             cm_ReleaseUser(userp);
7442             free(realPathp);
7443             if (baseFidp)
7444                 smb_ReleaseFID(baseFidp);
7445             if ( WANTS_DFS_PATHNAMES(inp) )
7446                 return CM_ERROR_PATH_NOT_COVERED;
7447             else
7448                 return CM_ERROR_BADSHARENAME;
7449         }
7450 #endif /* DFS_SUPPORT */
7451     }
7452
7453     if (code == 0) 
7454         foundscp = TRUE;
7455
7456     if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
7457         /* look up parent directory */
7458         if ( !dscp ) {
7459             code = cm_NameI(baseDirp, spacep->data,
7460                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7461                              userp, tidPathp, &req, &dscp);
7462 #ifdef DFS_SUPPORT
7463             if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7464                 cm_ReleaseSCache(dscp);
7465                 cm_ReleaseUser(userp);
7466                 free(realPathp);
7467                 if (baseFidp)
7468                     smb_ReleaseFID(baseFidp);
7469                 if ( WANTS_DFS_PATHNAMES(inp) )
7470                     return CM_ERROR_PATH_NOT_COVERED;
7471                 else
7472                     return CM_ERROR_BADSHARENAME;
7473             }
7474 #endif /* DFS_SUPPORT */
7475         } else
7476             code = 0;
7477         
7478         cm_FreeSpace(spacep);
7479
7480         if (baseFidp)
7481             smb_ReleaseFID(baseFidp);
7482
7483         if (code) {
7484             cm_ReleaseUser(userp);
7485             free(realPathp);
7486             return code;
7487         }
7488
7489         if (!lastNamep)
7490             lastNamep = realPathp;
7491         else 
7492             lastNamep++;
7493
7494         if (!smb_IsLegalFilename(lastNamep))
7495             return CM_ERROR_BADNTFILENAME;
7496
7497         if (!foundscp) {
7498             if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
7499                 code = cm_Lookup(dscp, lastNamep,
7500                                   CM_FLAG_FOLLOW, userp, &req, &scp);
7501             } else {
7502                 code = cm_Lookup(dscp, lastNamep,
7503                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
7504                                  userp, &req, &scp);
7505             }
7506             if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7507                 cm_ReleaseSCache(dscp);
7508                 cm_ReleaseUser(userp);
7509                 free(realPathp);
7510                 return code;
7511             }
7512         }
7513     } else {
7514         if (baseFidp)
7515             smb_ReleaseFID(baseFidp);
7516         cm_FreeSpace(spacep);
7517     }
7518
7519     /* if we get here, if code is 0, the file exists and is represented by
7520      * scp.  Otherwise, we have to create it.  The dir may be represented
7521      * by dscp, or we may have found the file directly.  If code is non-zero,
7522      * scp is NULL.
7523      */
7524     if (code == 0) {
7525         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7526         if (code) {     
7527             if (dscp) 
7528                 cm_ReleaseSCache(dscp);
7529             cm_ReleaseSCache(scp);
7530             cm_ReleaseUser(userp);
7531             free(realPathp);
7532             return code;
7533         }
7534
7535         if (createDisp == FILE_CREATE) {
7536             /* oops, file shouldn't be there */
7537             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7538             if (dscp) 
7539                 cm_ReleaseSCache(dscp);
7540             cm_ReleaseSCache(scp);
7541             cm_ReleaseUser(userp);
7542             free(realPathp);
7543             return CM_ERROR_EXISTS;
7544         }
7545
7546         if (createDisp == FILE_OVERWRITE ||
7547             createDisp == FILE_OVERWRITE_IF) {
7548             setAttr.mask = CM_ATTRMASK_LENGTH;
7549             setAttr.length.LowPart = 0;
7550             setAttr.length.HighPart = 0;
7551
7552             /* now watch for a symlink */
7553             code = 0;
7554             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7555                 targetScp = 0;
7556                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7557                 if (code == 0) {
7558                     /* we have a more accurate file to use (the
7559                     * target of the symbolic link).  Otherwise,
7560                     * we'll just use the symlink anyway.
7561                     */
7562                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
7563                               scp, targetScp);
7564                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7565                     cm_ReleaseSCache(scp);
7566                     scp = targetScp;
7567                     code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req, &ldp);
7568                     if (code) {
7569                         if (dscp)
7570                             cm_ReleaseSCache(dscp);
7571                         if (scp)
7572                             cm_ReleaseSCache(scp);
7573                         cm_ReleaseUser(userp);
7574                         free(realPathp);
7575                         return code;
7576                     }
7577                 }
7578             }
7579             code = cm_SetAttr(scp, &setAttr, userp, &req);
7580             openAction = 3;     /* truncated existing file */
7581         }
7582         else openAction = 1;    /* found existing file */
7583     }
7584     else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
7585         /* don't create if not found */
7586         if (dscp) 
7587             cm_ReleaseSCache(dscp);
7588         cm_ReleaseUser(userp);
7589         free(realPathp);
7590         return CM_ERROR_NOSUCHFILE;
7591     }
7592     else if (realDirFlag == 0 || realDirFlag == -1) {
7593         osi_assert(dscp != NULL);
7594         osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
7595                   osi_LogSaveString(smb_logp, lastNamep));
7596         openAction = 2;         /* created file */
7597         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7598         setAttr.clientModTime = time(NULL);
7599         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7600                           &req);
7601         if (code == 0) {
7602             created = 1;
7603             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7604                 smb_NotifyChange(FILE_ACTION_ADDED,
7605                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7606                                  dscp, lastNamep, NULL, TRUE);
7607         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7608             /* Not an exclusive create, and someone else tried
7609              * creating it already, then we open it anyway.  We
7610              * don't bother retrying after this, since if this next
7611              * fails, that means that the file was deleted after we
7612              * started this call.
7613              */
7614             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7615                               userp, &req, &scp);
7616             if (code == 0) {
7617                 if (createDisp == FILE_OVERWRITE_IF) {
7618                     setAttr.mask = CM_ATTRMASK_LENGTH;
7619                     setAttr.length.LowPart = 0;
7620                     setAttr.length.HighPart = 0;
7621
7622                     /* now watch for a symlink */
7623                     code = 0;
7624                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7625                         targetScp = 0;
7626                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7627                         if (code == 0) {
7628                             /* we have a more accurate file to use (the
7629                             * target of the symbolic link).  Otherwise,
7630                             * we'll just use the symlink anyway.
7631                             */
7632                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
7633                                       scp, targetScp);
7634                             cm_ReleaseSCache(scp);
7635                             scp = targetScp;
7636                         }
7637                     }
7638                     code = cm_SetAttr(scp, &setAttr, userp, &req);
7639                 }       
7640             }   /* lookup succeeded */
7641         }
7642     } else {
7643         /* create directory */
7644         osi_assert(dscp != NULL);
7645         osi_Log1(smb_logp,
7646                   "smb_ReceiveNTTranCreate creating directory %s",
7647                   osi_LogSaveString(smb_logp, lastNamep));
7648         openAction = 2;         /* created directory */
7649         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7650         setAttr.clientModTime = time(NULL);
7651         code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7652         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7653             smb_NotifyChange(FILE_ACTION_ADDED,
7654                               FILE_NOTIFY_CHANGE_DIR_NAME,
7655                               dscp, lastNamep, NULL, TRUE);
7656         if (code == 0 ||
7657             (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7658             /* Not an exclusive create, and someone else tried
7659              * creating it already, then we open it anyway.  We
7660              * don't bother retrying after this, since if this next
7661              * fails, that means that the file was deleted after we
7662              * started this call.
7663              */
7664             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7665                               userp, &req, &scp);
7666         }       
7667     }
7668
7669     if (code) {
7670         /* something went wrong creating or truncating the file */
7671         if (ldp)
7672             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7673         if (scp) 
7674             cm_ReleaseSCache(scp);
7675         cm_ReleaseUser(userp);
7676         free(realPathp);
7677         return code;
7678     }
7679
7680     /* make sure we have file vs. dir right */
7681     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7682         /* now watch for a symlink */
7683         code = 0;
7684         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7685             targetScp = 0;
7686             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7687             if (code == 0) {
7688                 /* we have a more accurate file to use (the
7689                 * target of the symbolic link).  Otherwise,
7690                 * we'll just use the symlink anyway.
7691                 */
7692                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7693                           scp, targetScp);
7694                 if (ldp)
7695                     cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7696                 cm_ReleaseSCache(scp);
7697                 scp = targetScp;
7698             }
7699         }
7700
7701         if (scp->fileType != CM_SCACHETYPE_FILE) {
7702             if (ldp)
7703                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7704             cm_ReleaseSCache(scp);
7705             cm_ReleaseUser(userp);
7706             free(realPathp);
7707             return CM_ERROR_ISDIR;
7708         }
7709     }
7710
7711     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7712         if (ldp)
7713             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7714         cm_ReleaseSCache(scp);
7715         cm_ReleaseUser(userp);
7716         free(realPathp);
7717         return CM_ERROR_NOTDIR;
7718     }
7719
7720     /* open the file itself */
7721     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7722     osi_assert(fidp);
7723
7724     /* save a reference to the user */
7725     cm_HoldUser(userp);
7726     fidp->userp = userp;
7727
7728     /* If we are restricting sharing, we should do so with a suitable
7729        share lock. */
7730     if (scp->fileType == CM_SCACHETYPE_FILE &&
7731         !(fidflags & SMB_FID_SHARE_WRITE)) {
7732         cm_key_t key;
7733         LARGE_INTEGER LOffset, LLength;
7734         int sLockType;
7735
7736         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7737         LOffset.LowPart = SMB_FID_QLOCK_LOW;
7738         LLength.HighPart = 0;
7739         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7740
7741         /* Similar to what we do in handling NTCreateX.  We get a
7742            shared lock if we are only opening the file for reading. */
7743         if ((fidflags & SMB_FID_SHARE_READ) ||
7744             !(fidflags & SMB_FID_OPENWRITE)) {
7745             sLockType = LOCKING_ANDX_SHARED_LOCK;
7746         } else {
7747             sLockType = 0;
7748         }
7749
7750         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7751         
7752         lock_ObtainMutex(&scp->mx);
7753         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7754         lock_ReleaseMutex(&scp->mx);
7755
7756         if (code) {
7757             if (ldp)
7758                 cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7759             cm_ReleaseSCache(scp);
7760             cm_ReleaseUser(userp);
7761             /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
7762             smb_CloseFID(vcp, fidp, NULL, 0);
7763             smb_ReleaseFID(fidp);
7764             free(realPathp);
7765             return CM_ERROR_SHARING_VIOLATION;
7766         }
7767     }
7768
7769     /* Now its safe to drop the file server lock obtained by cm_CheckNTOpen() */
7770     if (ldp)
7771         cm_CheckNTOpenDone(scp, userp, &req, &ldp);
7772
7773     lock_ObtainMutex(&fidp->mx);
7774     /* save a pointer to the vnode */
7775     fidp->scp = scp;
7776     lock_ObtainMutex(&scp->mx);
7777     scp->flags |= CM_SCACHEFLAG_SMB_FID;
7778     lock_ReleaseMutex(&scp->mx);
7779     osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p scp 0x%p", fidp, scp);
7780
7781     fidp->flags = fidflags;
7782
7783     /* remember if the file was newly created */
7784     if (created)
7785         fidp->flags |= SMB_FID_CREATED;
7786
7787     /* save parent dir and pathname for deletion or change notification */
7788     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7789         fidp->flags |= SMB_FID_NTOPEN;
7790         fidp->NTopen_dscp = dscp;
7791         osi_Log2(smb_logp,"smb_ReceiveNTTranCreate fidp 0x%p dscp 0x%p", fidp, dscp);
7792         dscp = NULL;
7793         fidp->NTopen_pathp = strdup(lastNamep);
7794     }
7795     fidp->NTopen_wholepathp = realPathp;
7796     lock_ReleaseMutex(&fidp->mx);
7797
7798     /* we don't need this any longer */
7799     if (dscp) 
7800         cm_ReleaseSCache(dscp);
7801
7802     cm_Open(scp, 0, userp);
7803
7804     /* set inp->fid so that later read calls in same msg can find fid */
7805     inp->fid = fidp->fid;
7806
7807     /* check whether we are required to send an extended response */
7808     if (!extendedRespRequired) {
7809         /* out parms */
7810         parmOffset = 8*4 + 39;
7811         parmOffset += 1;        /* pad to 4 */
7812         dataOffset = parmOffset + 70;
7813
7814         parmSlot = 1;
7815         outp->oddByte = 1;
7816         /* Total Parameter Count */
7817         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7818         /* Total Data Count */
7819         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7820         /* Parameter Count */
7821         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7822         /* Parameter Offset */
7823         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7824         /* Parameter Displacement */
7825         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7826         /* Data Count */
7827         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7828         /* Data Offset */
7829         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7830         /* Data Displacement */
7831         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7832         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
7833         smb_SetSMBDataLength(outp, 70);
7834
7835         lock_ObtainMutex(&scp->mx);
7836         outData = smb_GetSMBData(outp, NULL);
7837         outData++;                      /* round to get to parmOffset */
7838         *outData = 0; outData++;        /* oplock */
7839         *outData = 0; outData++;        /* reserved */
7840         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7841         *((ULONG *)outData) = openAction; outData += 4;
7842         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
7843         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7844         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
7845         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
7846         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
7847         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
7848         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7849         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7850         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7851         *((USHORT *)outData) = 0; outData += 2; /* filetype */
7852         *((USHORT *)outData) = 0; outData += 2; /* dev state */
7853         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7854                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7855                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7856         outData += 2;   /* is a dir? */
7857         lock_ReleaseMutex(&scp->mx);
7858     } else {
7859         /* out parms */
7860         parmOffset = 8*4 + 39;
7861         parmOffset += 1;        /* pad to 4 */
7862         dataOffset = parmOffset + 104;
7863         
7864         parmSlot = 1;
7865         outp->oddByte = 1;
7866         /* Total Parameter Count */
7867         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7868         /* Total Data Count */
7869         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7870         /* Parameter Count */
7871         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7872         /* Parameter Offset */
7873         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7874         /* Parameter Displacement */
7875         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7876         /* Data Count */
7877         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7878         /* Data Offset */
7879         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7880         /* Data Displacement */
7881         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7882         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
7883         smb_SetSMBDataLength(outp, 105);
7884         
7885         lock_ObtainMutex(&scp->mx);
7886         outData = smb_GetSMBData(outp, NULL);
7887         outData++;                      /* round to get to parmOffset */
7888         *outData = 0; outData++;        /* oplock */
7889         *outData = 1; outData++;        /* response type */
7890         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7891         *((ULONG *)outData) = openAction; outData += 4;
7892         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
7893         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7894         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
7895         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
7896         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
7897         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
7898         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7899         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7900         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7901         *((USHORT *)outData) = 0; outData += 2; /* filetype */
7902         *((USHORT *)outData) = 0; outData += 2; /* dev state */
7903         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7904                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7905                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7906         outData += 1;   /* is a dir? */
7907         memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7908         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7909         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7910         lock_ReleaseMutex(&scp->mx);
7911     }
7912
7913     osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7914
7915     cm_ReleaseUser(userp);
7916     smb_ReleaseFID(fidp);
7917
7918     /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7919     /* leave scp held since we put it in fidp->scp */
7920     return 0;
7921 }
7922
7923 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7924         smb_packet_t *outp)
7925 {
7926     smb_packet_t *savedPacketp;
7927     ULONG filter; 
7928     USHORT fid, watchtree;
7929     smb_fid_t *fidp;
7930     cm_scache_t *scp;
7931         
7932     filter = smb_GetSMBParm(inp, 19) |
7933              (smb_GetSMBParm(inp, 20) << 16);
7934     fid = smb_GetSMBParm(inp, 21);
7935     watchtree = (smb_GetSMBParm(inp, 22) & 0xff) ? 1 : 0;
7936
7937     fidp = smb_FindFID(vcp, fid, 0);
7938     if (!fidp) {
7939         osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7940         return CM_ERROR_BADFD;
7941     }
7942
7943     /* Create a copy of the Directory Watch Packet to use when sending the
7944      * notification if in the future a matching change is detected.
7945      */
7946     savedPacketp = smb_CopyPacket(inp);
7947     smb_HoldVC(vcp);
7948     if (savedPacketp->vcp)
7949         smb_ReleaseVC(savedPacketp->vcp);
7950     savedPacketp->vcp = vcp;
7951
7952     /* Add the watch to the list of events to send notifications for */
7953     lock_ObtainMutex(&smb_Dir_Watch_Lock);
7954     savedPacketp->nextp = smb_Directory_Watches;
7955     smb_Directory_Watches = savedPacketp;
7956     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7957
7958     scp = fidp->scp;
7959     osi_Log3(smb_logp,"smb_ReceiveNTTranNotifyChange fidp 0x%p scp 0x%p file \"%s\"", 
7960               fidp, scp, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7961     osi_Log3(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d",
7962              filter, fid, watchtree);
7963     if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
7964         osi_Log0(smb_logp, "      Notify Change File Name");
7965     if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
7966         osi_Log0(smb_logp, "      Notify Change Directory Name");
7967     if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
7968         osi_Log0(smb_logp, "      Notify Change Attributes");
7969     if (filter & FILE_NOTIFY_CHANGE_SIZE)
7970         osi_Log0(smb_logp, "      Notify Change Size");
7971     if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
7972         osi_Log0(smb_logp, "      Notify Change Last Write");
7973     if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
7974         osi_Log0(smb_logp, "      Notify Change Last Access");
7975     if (filter & FILE_NOTIFY_CHANGE_CREATION)
7976         osi_Log0(smb_logp, "      Notify Change Creation");
7977     if (filter & FILE_NOTIFY_CHANGE_EA)
7978         osi_Log0(smb_logp, "      Notify Change Extended Attributes");
7979     if (filter & FILE_NOTIFY_CHANGE_SECURITY)
7980         osi_Log0(smb_logp, "      Notify Change Security");
7981     if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
7982         osi_Log0(smb_logp, "      Notify Change Stream Name");
7983     if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
7984         osi_Log0(smb_logp, "      Notify Change Stream Size");
7985     if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
7986         osi_Log0(smb_logp, "      Notify Change Stream Write");
7987
7988     lock_ObtainMutex(&scp->mx);
7989     if (watchtree)
7990         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7991     else
7992         scp->flags |= CM_SCACHEFLAG_WATCHED;
7993     lock_ReleaseMutex(&scp->mx);
7994     smb_ReleaseFID(fidp);
7995
7996     outp->flags |= SMB_PACKETFLAG_NOSEND;
7997     return 0;
7998 }
7999
8000 unsigned char nullSecurityDesc[36] = {
8001     0x01,                               /* security descriptor revision */
8002     0x00,                               /* reserved, should be zero */
8003     0x00, 0x80,                         /* security descriptor control;
8004                                          * 0x8000 : self-relative format */
8005     0x14, 0x00, 0x00, 0x00,             /* offset of owner SID */
8006     0x1c, 0x00, 0x00, 0x00,             /* offset of group SID */
8007     0x00, 0x00, 0x00, 0x00,             /* offset of DACL would go here */
8008     0x00, 0x00, 0x00, 0x00,             /* offset of SACL would go here */
8009     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8010                                         /* "null SID" owner SID */
8011     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
8012                                         /* "null SID" group SID */
8013 };      
8014
8015 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8016 {
8017     int parmOffset, parmCount, dataOffset, dataCount;
8018     int parmSlot;
8019     int maxData;
8020     char *outData;
8021     char *parmp;
8022     USHORT *sparmp;
8023     ULONG *lparmp;
8024     USHORT fid;
8025     ULONG securityInformation;
8026
8027     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
8028         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
8029     parmp = inp->data + parmOffset;
8030     sparmp = (USHORT *) parmp;
8031     lparmp = (ULONG *) parmp;
8032
8033     fid = sparmp[0];
8034     securityInformation = lparmp[1];
8035
8036     maxData = smb_GetSMBOffsetParm(inp, 7, 1)
8037         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
8038
8039     if (maxData < 36)
8040         dataCount = 0;
8041     else
8042         dataCount = 36;
8043
8044     /* out parms */
8045     parmOffset = 8*4 + 39;
8046     parmOffset += 1;    /* pad to 4 */
8047     parmCount = 4;
8048     dataOffset = parmOffset + parmCount;
8049
8050     parmSlot = 1;
8051     outp->oddByte = 1;
8052     /* Total Parameter Count */
8053     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8054     /* Total Data Count */
8055     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8056     /* Parameter Count */
8057     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
8058     /* Parameter Offset */
8059     smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
8060     /* Parameter Displacement */
8061     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8062     /* Data Count */
8063     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
8064     /* Data Offset */
8065     smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
8066     /* Data Displacement */
8067     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
8068     smb_SetSMBParmByte(outp, parmSlot, 0);      /* Setup Count */
8069     smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
8070
8071     outData = smb_GetSMBData(outp, NULL);
8072     outData++;                  /* round to get to parmOffset */
8073     *((ULONG *)outData) = 36; outData += 4;     /* length */
8074
8075     if (maxData >= 36) {
8076         memcpy(outData, nullSecurityDesc, 36);
8077         outData += 36;
8078         return 0;
8079     } else
8080         return CM_ERROR_BUFFERTOOSMALL;
8081 }
8082
8083 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8084 {
8085     unsigned short function;
8086
8087     function = smb_GetSMBParm(inp, 18);
8088
8089     osi_Log1(smb_logp, "SMB NT Transact function %d", function);
8090
8091     /* We can handle long names */
8092     if (vcp->flags & SMB_VCFLAG_USENT)
8093         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
8094         
8095     switch (function) {
8096     case 1: 
8097         return smb_ReceiveNTTranCreate(vcp, inp, outp);
8098     case 2:
8099         osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
8100         break;
8101     case 3:
8102         osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
8103         break;
8104     case 4:
8105         return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
8106     case 5:
8107         osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
8108         break;
8109     case 6:
8110         return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
8111     }
8112     return CM_ERROR_INVAL;
8113 }
8114
8115 /*
8116  * smb_NotifyChange -- find relevant change notification messages and
8117  *                     reply to them
8118  *
8119  * If we don't know the file name (i.e. a callback break), filename is
8120  * NULL, and we return a zero-length list.
8121  *
8122  * At present there is not a single call to smb_NotifyChange that 
8123  * has the isDirectParent parameter set to FALSE.  
8124  */
8125 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
8126         cm_scache_t *dscp, char *filename, char *otherFilename,
8127         BOOL isDirectParent)
8128 {
8129     smb_packet_t *watch, *lastWatch, *nextWatch;
8130     ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
8131     char *outData, *oldOutData;
8132     ULONG filter;
8133     USHORT fid, wtree;
8134     ULONG maxLen;
8135     BOOL twoEntries = FALSE;
8136     ULONG otherNameLen, oldParmCount = 0;
8137     DWORD otherAction;
8138     smb_fid_t *fidp;
8139
8140     /* Get ready for rename within directory */
8141     if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
8142         twoEntries = TRUE;
8143         otherAction = FILE_ACTION_RENAMED_NEW_NAME;
8144     }
8145
8146     osi_Log4(smb_logp,"in smb_NotifyChange for file [%s] dscp [%p] notification 0x%x parent %d",
8147              osi_LogSaveString(smb_logp,filename),dscp, notifyFilter, isDirectParent);
8148     if (action == 0)
8149         osi_Log0(smb_logp,"      FILE_ACTION_NONE");
8150     if (action == FILE_ACTION_ADDED)
8151         osi_Log0(smb_logp,"      FILE_ACTION_ADDED");
8152     if (action == FILE_ACTION_REMOVED)
8153         osi_Log0(smb_logp,"      FILE_ACTION_REMOVED");
8154     if (action == FILE_ACTION_MODIFIED)
8155         osi_Log0(smb_logp,"      FILE_ACTION_MODIFIED");
8156     if (action == FILE_ACTION_RENAMED_OLD_NAME)
8157         osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_OLD_NAME");
8158     if (action == FILE_ACTION_RENAMED_NEW_NAME)
8159         osi_Log0(smb_logp,"      FILE_ACTION_RENAMED_NEW_NAME");
8160
8161     lock_ObtainMutex(&smb_Dir_Watch_Lock);
8162     watch = smb_Directory_Watches;
8163     while (watch) {
8164         filter = smb_GetSMBParm(watch, 19)
8165             | (smb_GetSMBParm(watch, 20) << 16);
8166         fid = smb_GetSMBParm(watch, 21);
8167         wtree = (smb_GetSMBParm(watch, 22) & 0xff) ? 1 : 0;
8168
8169         maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
8170             | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
8171
8172         /*
8173          * Strange hack - bug in NT Client and NT Server that we must emulate?
8174          */
8175         if ((filter == (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) && wtree)
8176             filter |= FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES;
8177
8178         fidp = smb_FindFID(watch->vcp, fid, 0);
8179         if (!fidp) {
8180             osi_Log2(smb_logp," no fidp for fid[%d] in vcp 0x%p",fid, watch->vcp);
8181             lastWatch = watch;
8182             watch = watch->nextp;
8183             continue;
8184         }       
8185         if (fidp->scp != dscp
8186              || (filter & notifyFilter) == 0
8187              || (!isDirectParent && !wtree)) {
8188             osi_Log1(smb_logp," skipping fidp->scp[%x]", fidp->scp);
8189             smb_ReleaseFID(fidp);
8190             lastWatch = watch;
8191             watch = watch->nextp;
8192             continue;
8193         }
8194         smb_ReleaseFID(fidp);
8195
8196         osi_Log4(smb_logp,
8197                   "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
8198                   fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
8199         if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
8200             osi_Log0(smb_logp, "      Notify Change File Name");
8201         if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
8202             osi_Log0(smb_logp, "      Notify Change Directory Name");
8203         if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
8204             osi_Log0(smb_logp, "      Notify Change Attributes");
8205         if (filter & FILE_NOTIFY_CHANGE_SIZE)
8206             osi_Log0(smb_logp, "      Notify Change Size");
8207         if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
8208             osi_Log0(smb_logp, "      Notify Change Last Write");
8209         if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
8210             osi_Log0(smb_logp, "      Notify Change Last Access");
8211         if (filter & FILE_NOTIFY_CHANGE_CREATION)
8212             osi_Log0(smb_logp, "      Notify Change Creation");
8213         if (filter & FILE_NOTIFY_CHANGE_EA)
8214             osi_Log0(smb_logp, "      Notify Change Extended Attributes");
8215         if (filter & FILE_NOTIFY_CHANGE_SECURITY)
8216             osi_Log0(smb_logp, "      Notify Change Security");
8217         if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
8218             osi_Log0(smb_logp, "      Notify Change Stream Name");
8219         if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
8220             osi_Log0(smb_logp, "      Notify Change Stream Size");
8221         if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
8222             osi_Log0(smb_logp, "      Notify Change Stream Write");
8223                      
8224         /* A watch can only be notified once.  Remove it from the list */
8225         nextWatch = watch->nextp;
8226         if (watch == smb_Directory_Watches)
8227             smb_Directory_Watches = nextWatch;
8228         else
8229             lastWatch->nextp = nextWatch;
8230
8231         /* Turn off WATCHED flag in dscp */
8232         lock_ObtainMutex(&dscp->mx);
8233         if (wtree)
8234             dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8235         else
8236             dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
8237         lock_ReleaseMutex(&dscp->mx);
8238
8239         /* Convert to response packet */
8240         ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
8241         ((smb_t *) watch)->wct = 0;
8242
8243         /* out parms */
8244         if (filename == NULL)
8245             parmCount = 0;
8246         else {
8247             nameLen = (ULONG)strlen(filename);
8248             parmCount = 3*4 + nameLen*2;
8249             parmCount = (parmCount + 3) & ~3;   /* pad to 4 */
8250             if (twoEntries) {
8251                 otherNameLen = (ULONG)strlen(otherFilename);
8252                 oldParmCount = parmCount;
8253                 parmCount += 3*4 + otherNameLen*2;
8254                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
8255             }
8256             if (maxLen < parmCount)
8257                 parmCount = 0;  /* not enough room */
8258         }
8259         parmOffset = 8*4 + 39;
8260         parmOffset += 1;                        /* pad to 4 */
8261         dataOffset = parmOffset + parmCount;
8262
8263         parmSlot = 1;
8264         watch->oddByte = 1;
8265         /* Total Parameter Count */
8266         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8267         /* Total Data Count */
8268         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8269         /* Parameter Count */
8270         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
8271         /* Parameter Offset */
8272         smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
8273         /* Parameter Displacement */
8274         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8275         /* Data Count */
8276         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8277         /* Data Offset */
8278         smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
8279         /* Data Displacement */
8280         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
8281         smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
8282         smb_SetSMBDataLength(watch, parmCount + 1);
8283
8284         if (parmCount != 0) {
8285             char * p;
8286             outData = smb_GetSMBData(watch, NULL);
8287             outData++;  /* round to get to parmOffset */
8288             oldOutData = outData;
8289             *((DWORD *)outData) = oldParmCount; outData += 4;
8290             /* Next Entry Offset */
8291             *((DWORD *)outData) = action; outData += 4;
8292             /* Action */
8293             *((DWORD *)outData) = nameLen*2; outData += 4;
8294             /* File Name Length */
8295             p = strdup(filename);
8296             if (smb_StoreAnsiFilenames)
8297                 CharToOem(p,p);
8298             mbstowcs((WCHAR *)outData, p, nameLen);
8299             free(p);
8300             /* File Name */
8301             if (twoEntries) {
8302                 outData = oldOutData + oldParmCount;
8303                 *((DWORD *)outData) = 0; outData += 4;
8304                 /* Next Entry Offset */
8305                 *((DWORD *)outData) = otherAction; outData += 4;
8306                 /* Action */
8307                 *((DWORD *)outData) = otherNameLen*2;
8308                 outData += 4;   /* File Name Length */
8309                 p = strdup(otherFilename);
8310                 if (smb_StoreAnsiFilenames)
8311                     CharToOem(p,p);
8312                 mbstowcs((WCHAR *)outData, p, otherNameLen);    /* File Name */
8313                 free(p);
8314             }       
8315         }       
8316
8317         /*
8318          * If filename is null, we don't know the cause of the
8319          * change notification.  We return zero data (see above),
8320          * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
8321          * (= 0x010C).  We set the error code here by hand, without
8322          * modifying wct and bcc.
8323          */
8324         if (filename == NULL) {
8325             ((smb_t *) watch)->rcls = 0x0C;
8326             ((smb_t *) watch)->reh = 0x01;
8327             ((smb_t *) watch)->errLow = 0;
8328             ((smb_t *) watch)->errHigh = 0;
8329             /* Set NT Status codes flag */
8330             ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8331         }
8332
8333         smb_SendPacket(watch->vcp, watch);
8334         smb_FreePacket(watch);
8335         watch = nextWatch;
8336     }
8337     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8338 }       
8339
8340 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8341 {
8342     unsigned char *replyWctp;
8343     smb_packet_t *watch, *lastWatch;
8344     USHORT fid, watchtree;
8345     smb_fid_t *fidp;
8346     cm_scache_t *scp;
8347
8348     osi_Log0(smb_logp, "SMB3 receive NT cancel");
8349
8350     lock_ObtainMutex(&smb_Dir_Watch_Lock);
8351     watch = smb_Directory_Watches;
8352     while (watch) {
8353         if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
8354              && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
8355              && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
8356              && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
8357             if (watch == smb_Directory_Watches)
8358                 smb_Directory_Watches = watch->nextp;
8359             else
8360                 lastWatch->nextp = watch->nextp;
8361             lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8362
8363             /* Turn off WATCHED flag in scp */
8364             fid = smb_GetSMBParm(watch, 21);
8365             watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
8366
8367             if (vcp != watch->vcp)
8368                 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x", 
8369                           vcp, watch->vcp);
8370
8371             fidp = smb_FindFID(vcp, fid, 0);
8372             if (fidp) {
8373                 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s", 
8374                           fid, watchtree,
8375                           osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
8376
8377                 scp = fidp->scp;
8378                 osi_Log2(smb_logp,"smb_ReceiveNTCancel fidp 0x%p scp 0x%p", fidp, scp);
8379                 lock_ObtainMutex(&scp->mx);
8380                 if (watchtree)
8381                     scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
8382                 else
8383                     scp->flags &= ~CM_SCACHEFLAG_WATCHED;
8384                 lock_ReleaseMutex(&scp->mx);
8385                 smb_ReleaseFID(fidp);
8386             } else {
8387                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
8388             }
8389
8390             /* assume STATUS32; return 0xC0000120 (CANCELED) */
8391             replyWctp = watch->wctp;
8392             *replyWctp++ = 0;
8393             *replyWctp++ = 0;
8394             *replyWctp++ = 0;
8395             ((smb_t *)watch)->rcls = 0x20;
8396             ((smb_t *)watch)->reh = 0x1;
8397             ((smb_t *)watch)->errLow = 0;
8398             ((smb_t *)watch)->errHigh = 0xC0;
8399             ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8400             smb_SendPacket(vcp, watch);
8401             smb_FreePacket(watch);
8402             return 0;
8403         }
8404         lastWatch = watch;
8405         watch = watch->nextp;
8406     }
8407     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
8408
8409     return 0;
8410 }
8411
8412 /*
8413  * NT rename also does hard links.
8414  */
8415
8416 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
8417 #define RENAME_FLAG_HARD_LINK                0x103
8418 #define RENAME_FLAG_RENAME                   0x104
8419 #define RENAME_FLAG_COPY                     0x105
8420
8421 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8422 {
8423     char *oldPathp, *newPathp;
8424     long code = 0;
8425     char * tp;
8426     int attrs;
8427     int rename_type;
8428
8429     attrs = smb_GetSMBParm(inp, 0);
8430     rename_type = smb_GetSMBParm(inp, 1);
8431
8432     if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
8433         osi_Log1(smb_logp, "NTRename invalid rename_type [%x]", rename_type);
8434         return CM_ERROR_NOACCESS;
8435     }
8436
8437     tp = smb_GetSMBData(inp, NULL);
8438     oldPathp = smb_ParseASCIIBlock(tp, &tp);
8439     if (smb_StoreAnsiFilenames)
8440         OemToChar(oldPathp,oldPathp);
8441     newPathp = smb_ParseASCIIBlock(tp, &tp);
8442     if (smb_StoreAnsiFilenames)
8443         OemToChar(newPathp,newPathp);
8444
8445     osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
8446              osi_LogSaveString(smb_logp, oldPathp),
8447              osi_LogSaveString(smb_logp, newPathp),
8448              ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
8449
8450     if (rename_type == RENAME_FLAG_RENAME) {
8451         code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
8452     } else { /* RENAME_FLAG_HARD_LINK */
8453         code = smb_Link(vcp,inp,oldPathp,newPathp);
8454     }
8455     return code;
8456 }
8457
8458 void smb3_Init()
8459 {
8460     lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
8461 }
8462
8463 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
8464 {
8465     smb_username_t *unp;
8466     cm_user_t *     userp;
8467
8468     unp = smb_FindUserByName(usern, machine, flags);
8469     if (!unp->userp) {
8470         lock_ObtainMutex(&unp->mx);
8471         unp->userp = cm_NewUser();
8472         lock_ReleaseMutex(&unp->mx);
8473         osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8474     }  else     {
8475         osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
8476     }
8477     userp = unp->userp;
8478     cm_HoldUser(userp);
8479     smb_ReleaseUsername(unp);
8480     return userp;
8481 }
8482