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