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