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