DEVEL15-windows-smb-set-eof-20060825
[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,  
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     fidp->scp = scp;
2367     /* and the user */
2368     fidp->userp = userp;
2369         
2370     /* compute open mode */
2371     if (openMode != 1) 
2372         fidp->flags |= SMB_FID_OPENREAD;
2373     if (openMode == 1 || openMode == 2)
2374         fidp->flags |= SMB_FID_OPENWRITE;
2375
2376     /* remember that the file was newly created */
2377     if (created)
2378         fidp->flags |= SMB_FID_CREATED;
2379
2380     lock_ReleaseMutex(&fidp->mx);
2381
2382     smb_ReleaseFID(fidp);
2383         
2384     cm_Open(scp, 0, userp);
2385
2386     /* copy out remainder of the parms */
2387     parmSlot = 0;
2388     outp->parmsp[parmSlot++] = fidp->fid;
2389     lock_ObtainMutex(&scp->mx);
2390     if (extraInfo) {
2391         outp->parmsp[parmSlot++] = smb_Attributes(scp);
2392         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2393         outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2394         outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2395         outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2396         outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2397         outp->parmsp[parmSlot++] = openMode;
2398         outp->parmsp[parmSlot++] = 0;   /* file type 0 ==> normal file or dir */
2399         outp->parmsp[parmSlot++] = 0;   /* IPC junk */
2400     }   
2401     /* and the final "always present" stuff */
2402     outp->parmsp[parmSlot++] = openAction;
2403     /* next write out the "unique" ID */
2404     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff); 
2405     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff); 
2406     outp->parmsp[parmSlot++] = 0; 
2407     if (returnEALength) {
2408         outp->parmsp[parmSlot++] = 0; 
2409         outp->parmsp[parmSlot++] = 0; 
2410     }   
2411     lock_ReleaseMutex(&scp->mx);
2412     outp->totalData = 0;                /* total # of data bytes */
2413     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
2414
2415     smb_SendTran2Packet(vcp, outp, op);
2416
2417     smb_FreeTran2Packet(outp);
2418
2419     cm_ReleaseUser(userp);
2420     /* leave scp held since we put it in fidp->scp */
2421     return 0;
2422 }   
2423
2424 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2425 {
2426     osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2427     return CM_ERROR_BADOP;
2428 }
2429
2430 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2431 {
2432     osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2433     return CM_ERROR_BADOP;
2434 }
2435
2436 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2437 {
2438     unsigned short fid;
2439     unsigned short infolevel;
2440
2441     infolevel = p->parmsp[0];
2442     fid = p->parmsp[1];
2443     osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2444     
2445     return CM_ERROR_BADOP;
2446 }
2447
2448 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2449 {
2450     smb_tran2Packet_t *outp;
2451     smb_tran2QFSInfo_t qi;
2452     int responseSize;
2453     static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2454         
2455     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2456
2457     switch (p->parmsp[0]) {
2458     case SMB_INFO_ALLOCATION: 
2459         responseSize = sizeof(qi.u.allocInfo); 
2460         break;
2461     case SMB_INFO_VOLUME: 
2462         responseSize = sizeof(qi.u.volumeInfo); 
2463         break;
2464     case SMB_QUERY_FS_VOLUME_INFO: 
2465         responseSize = sizeof(qi.u.FSvolumeInfo); 
2466         break;
2467     case SMB_QUERY_FS_SIZE_INFO: 
2468         responseSize = sizeof(qi.u.FSsizeInfo); 
2469         break;
2470     case SMB_QUERY_FS_DEVICE_INFO: 
2471         responseSize = sizeof(qi.u.FSdeviceInfo); 
2472         break;
2473     case SMB_QUERY_FS_ATTRIBUTE_INFO: 
2474         responseSize = sizeof(qi.u.FSattributeInfo); 
2475         break;
2476     case SMB_INFO_UNIX:         /* CIFS Unix Info */
2477     case SMB_INFO_MACOS:        /* Mac FS Info */
2478     default: 
2479         return CM_ERROR_BADOP;
2480     }
2481
2482     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2483     switch (p->parmsp[0]) {
2484     case SMB_INFO_ALLOCATION: 
2485         /* alloc info */
2486         qi.u.allocInfo.FSID = 0;
2487         qi.u.allocInfo.sectorsPerAllocUnit = 1;
2488         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2489         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2490         qi.u.allocInfo.bytesPerSector = 1024;
2491         break;
2492
2493     case SMB_INFO_VOLUME: 
2494         /* volume info */
2495         qi.u.volumeInfo.vsn = 1234;
2496         qi.u.volumeInfo.vnCount = 4;
2497         /* we're supposed to pad it out with zeroes to the end */
2498         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2499         memcpy(qi.u.volumeInfo.label, "AFS", 4);
2500         break;
2501
2502     case SMB_QUERY_FS_VOLUME_INFO: 
2503         /* FS volume info */
2504         memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2505         qi.u.FSvolumeInfo.vsn = 1234;
2506         qi.u.FSvolumeInfo.vnCount = 8;
2507         memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2508         break;
2509
2510     case SMB_QUERY_FS_SIZE_INFO: 
2511         /* FS size info */
2512         qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2513         qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2514         qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2515         qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2516         qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2517         qi.u.FSsizeInfo.bytesPerSector = 1024;
2518         break;
2519
2520     case SMB_QUERY_FS_DEVICE_INFO: 
2521         /* FS device info */
2522         qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2523         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2524         break;
2525
2526     case SMB_QUERY_FS_ATTRIBUTE_INFO: 
2527         /* FS attribute info */
2528         /* attributes, defined in WINNT.H:
2529          *      FILE_CASE_SENSITIVE_SEARCH      0x1
2530          *      FILE_CASE_PRESERVED_NAMES       0x2
2531          *      FILE_VOLUME_QUOTAS              0x10
2532          *      <no name defined>               0x4000
2533          *         If bit 0x4000 is not set, Windows 95 thinks
2534          *         we can't handle long (non-8.3) names,
2535          *         despite our protestations to the contrary.
2536          */
2537         qi.u.FSattributeInfo.attributes = 0x4003;
2538         qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2539         qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2540         memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2541         break;
2542     }   
2543         
2544     /* copy out return data, and set corresponding sizes */
2545     outp->totalParms = 0;
2546     outp->totalData = responseSize;
2547     memcpy(outp->datap, &qi, responseSize);
2548
2549     /* send and free the packets */
2550     smb_SendTran2Packet(vcp, outp, op);
2551     smb_FreeTran2Packet(outp);
2552
2553     return 0;
2554 }
2555
2556 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2557 {
2558     osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2559     return CM_ERROR_BADOP;
2560 }
2561
2562 struct smb_ShortNameRock {
2563     char *maskp;
2564     unsigned int vnode;
2565     char *shortName;
2566     size_t shortNameLen;
2567 };      
2568
2569 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2570                          osi_hyper_t *offp)
2571 {       
2572     struct smb_ShortNameRock *rockp;
2573     char *shortNameEnd;
2574
2575     rockp = vrockp;
2576     /* compare both names and vnodes, though probably just comparing vnodes
2577      * would be safe enough.
2578      */
2579     if (cm_stricmp(dep->name, rockp->maskp) != 0)
2580         return 0;
2581     if (ntohl(dep->fid.vnode) != rockp->vnode)
2582         return 0;
2583     /* This is the entry */
2584     cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2585     rockp->shortNameLen = shortNameEnd - rockp->shortName;
2586     return CM_ERROR_STOPNOW;
2587 }       
2588
2589 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2590         char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2591 {
2592     struct smb_ShortNameRock rock;
2593     char *lastNamep;
2594     cm_space_t *spacep;
2595     cm_scache_t *dscp;
2596     int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2597     long code = 0;
2598     osi_hyper_t thyper;
2599
2600     spacep = cm_GetSpace();
2601     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2602
2603     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2604                      reqp, &dscp);
2605     cm_FreeSpace(spacep);
2606     if (code) 
2607         return code;
2608
2609 #ifdef DFS_SUPPORT
2610     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2611         cm_ReleaseSCache(dscp);
2612         cm_ReleaseUser(userp);
2613         return CM_ERROR_PATH_NOT_COVERED;
2614     }
2615 #endif /* DFS_SUPPORT */
2616
2617     if (!lastNamep) lastNamep = pathp;
2618     else lastNamep++;
2619     thyper.LowPart = 0;
2620     thyper.HighPart = 0;
2621     rock.shortName = shortName;
2622     rock.vnode = vnode;
2623     rock.maskp = lastNamep;
2624     code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2625
2626     cm_ReleaseSCache(dscp);
2627
2628     if (code == 0)
2629         return CM_ERROR_NOSUCHFILE;
2630     if (code == CM_ERROR_STOPNOW) {
2631         *shortNameLenp = rock.shortNameLen;
2632         return 0;
2633     }
2634     return code;
2635 }
2636
2637 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2638 {
2639     smb_tran2Packet_t *outp;
2640     afs_uint32 dosTime;
2641     FILETIME ft;
2642     unsigned short infoLevel;
2643     smb_tran2QPathInfo_t qpi;
2644     int responseSize;
2645     unsigned short attributes;
2646     unsigned long extAttributes;
2647     char shortName[13];
2648     unsigned int len;
2649     cm_user_t *userp;
2650     cm_space_t *spacep;
2651     cm_scache_t *scp, *dscp;
2652     int delonclose = 0;
2653     long code = 0;
2654     char *pathp;
2655     char *tidPathp;
2656     char *lastComp;
2657     cm_req_t req;
2658
2659     cm_InitReq(&req);
2660
2661     infoLevel = p->parmsp[0];
2662     if (infoLevel == SMB_INFO_IS_NAME_VALID) 
2663         responseSize = 0;
2664     else if (infoLevel == SMB_INFO_STANDARD) 
2665         responseSize = sizeof(qpi.u.QPstandardInfo);
2666     else if (infoLevel == SMB_INFO_QUERY_EA_SIZE) 
2667         responseSize = sizeof(qpi.u.QPeaSizeInfo);
2668     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2669         responseSize = sizeof(qpi.u.QPfileBasicInfo);
2670     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2671         responseSize = sizeof(qpi.u.QPfileStandardInfo);
2672     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2673         responseSize = sizeof(qpi.u.QPfileEaInfo);
2674     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
2675         responseSize = sizeof(qpi.u.QPfileNameInfo);
2676     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) 
2677         responseSize = sizeof(qpi.u.QPfileAllInfo);
2678     else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) 
2679         responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2680     else {
2681         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2682                   p->opcode, infoLevel);
2683         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
2684         return 0;
2685     }
2686
2687     pathp = (char *)(&p->parmsp[3]);
2688     if (smb_StoreAnsiFilenames)
2689         OemToChar(pathp,pathp);
2690     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2691               osi_LogSaveString(smb_logp, pathp));
2692
2693     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2694
2695     if (infoLevel > 0x100)
2696         outp->totalParms = 2;
2697     else
2698         outp->totalParms = 0;
2699     outp->totalData = responseSize;
2700         
2701     /* now, if we're at infoLevel 6, we're only being asked to check
2702      * the syntax, so we just OK things now.  In particular, we're *not*
2703      * being asked to verify anything about the state of any parent dirs.
2704      */
2705     if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2706         smb_SendTran2Packet(vcp, outp, opx);
2707         smb_FreeTran2Packet(outp);
2708         return 0;
2709     }   
2710         
2711     userp = smb_GetTran2User(vcp, p);
2712     if (!userp) {
2713         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2714         smb_FreeTran2Packet(outp);
2715         return CM_ERROR_BADSMB;
2716     }
2717
2718     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2719     if(code) {
2720         cm_ReleaseUser(userp);
2721         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2722         smb_FreeTran2Packet(outp);
2723         return 0;
2724     }
2725
2726     /*
2727      * XXX Strange hack XXX
2728      *
2729      * As of Patch 7 (13 January 98), we are having the following problem:
2730      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2731      * requests to look up "desktop.ini" in all the subdirectories.
2732      * This can cause zillions of timeouts looking up non-existent cells
2733      * and volumes, especially in the top-level directory.
2734      *
2735      * We have not found any way to avoid this or work around it except
2736      * to explicitly ignore the requests for mount points that haven't
2737      * yet been evaluated and for directories that haven't yet been
2738      * fetched.
2739      */
2740     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2741         spacep = cm_GetSpace();
2742         smb_StripLastComponent(spacep->data, &lastComp, pathp);
2743 #ifndef SPECIAL_FOLDERS
2744         /* Make sure that lastComp is not NULL */
2745         if (lastComp) {
2746             if (stricmp(lastComp, "\\desktop.ini") == 0) {
2747                 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2748                                  CM_FLAG_CASEFOLD
2749                                  | CM_FLAG_DIRSEARCH
2750                                  | CM_FLAG_FOLLOW,
2751                                  userp, tidPathp, &req, &dscp);
2752                 if (code == 0) {
2753 #ifdef DFS_SUPPORT
2754                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2755                         if ( WANTS_DFS_PATHNAMES(p) )
2756                             code = CM_ERROR_PATH_NOT_COVERED;
2757                         else
2758                             code = CM_ERROR_BADSHARENAME;
2759                     } else
2760 #endif /* DFS_SUPPORT */
2761                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2762                         code = CM_ERROR_NOSUCHFILE;
2763                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2764                         cm_buf_t *bp = buf_Find(dscp, &hzero);
2765                         if (bp)
2766                             buf_Release(bp);
2767                         else
2768                             code = CM_ERROR_NOSUCHFILE;
2769                     }
2770                     cm_ReleaseSCache(dscp);
2771                     if (code) {
2772                         cm_FreeSpace(spacep);
2773                         cm_ReleaseUser(userp);
2774                         smb_SendTran2Error(vcp, p, opx, code);
2775                         smb_FreeTran2Packet(outp);
2776                         return 0;
2777                     }
2778                 }
2779             }
2780         }
2781 #endif /* SPECIAL_FOLDERS */
2782
2783         cm_FreeSpace(spacep);
2784     }
2785
2786     /* now do namei and stat, and copy out the info */
2787     code = cm_NameI(cm_data.rootSCachep, pathp,
2788                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2789
2790     if (code) {
2791         cm_ReleaseUser(userp);
2792         smb_SendTran2Error(vcp, p, opx, code);
2793         smb_FreeTran2Packet(outp);
2794         return 0;
2795     }
2796
2797 #ifdef DFS_SUPPORT
2798     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2799         cm_ReleaseSCache(scp);
2800         cm_ReleaseUser(userp);
2801         if ( WANTS_DFS_PATHNAMES(p) )
2802             code = CM_ERROR_PATH_NOT_COVERED;
2803         else
2804             code = CM_ERROR_BADSHARENAME;
2805         smb_SendTran2Error(vcp, p, opx, code);
2806         smb_FreeTran2Packet(outp);
2807         return 0;
2808     }
2809 #endif /* DFS_SUPPORT */
2810
2811     lock_ObtainMutex(&scp->mx);
2812     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2813                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2814     if (code) goto done;
2815         
2816     /* now we have the status in the cache entry, and everything is locked.
2817      * Marshall the output data.
2818      */
2819     /* for info level 108, figure out short name */
2820     if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2821         code = cm_GetShortName(pathp, userp, &req,
2822                                 tidPathp, scp->fid.vnode, shortName,
2823                                 (size_t *) &len);
2824         if (code) {
2825             goto done;
2826         }
2827
2828         qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2829         mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2830
2831         goto done;
2832     }
2833     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2834         len = strlen(lastComp);
2835         qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2836         mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2837
2838         goto done;
2839     }
2840     else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2841         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2842         qpi.u.QPstandardInfo.creationDateTime = dosTime;
2843         qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2844         qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2845         qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2846         qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2847         attributes = smb_Attributes(scp);
2848         qpi.u.QPstandardInfo.attributes = attributes;
2849         qpi.u.QPstandardInfo.eaSize = 0;
2850     }
2851     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2852         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2853         qpi.u.QPfileBasicInfo.creationTime = ft;
2854         qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2855         qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2856         qpi.u.QPfileBasicInfo.changeTime = ft;
2857         extAttributes = smb_ExtAttributes(scp);
2858         qpi.u.QPfileBasicInfo.attributes = extAttributes;
2859         qpi.u.QPfileBasicInfo.reserved = 0;
2860     }
2861     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2862         smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2863         if (fidp) {
2864             lock_ObtainMutex(&fidp->mx);
2865             delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2866             lock_ReleaseMutex(&fidp->mx);
2867             smb_ReleaseFID(fidp);
2868         }
2869
2870         qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2871         qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2872         qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2873         qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2874         qpi.u.QPfileStandardInfo.directory = 
2875             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2876               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2877               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2878         qpi.u.QPfileStandardInfo.reserved = 0;
2879     }
2880     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2881         qpi.u.QPfileEaInfo.eaSize = 0;
2882     }
2883     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2884         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2885         qpi.u.QPfileAllInfo.creationTime = ft;
2886         qpi.u.QPfileAllInfo.lastAccessTime = ft;
2887         qpi.u.QPfileAllInfo.lastWriteTime = ft;
2888         qpi.u.QPfileAllInfo.changeTime = ft;
2889         extAttributes = smb_ExtAttributes(scp);
2890         qpi.u.QPfileAllInfo.attributes = extAttributes;
2891         qpi.u.QPfileAllInfo.allocationSize = scp->length;
2892         qpi.u.QPfileAllInfo.endOfFile = scp->length;
2893         qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2894         qpi.u.QPfileAllInfo.deletePending = 0;
2895         qpi.u.QPfileAllInfo.directory = 
2896             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2897               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2898               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2899         qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2900         qpi.u.QPfileAllInfo.indexNumber.LowPart  = scp->fid.volume;
2901         qpi.u.QPfileAllInfo.eaSize = 0;
2902         qpi.u.QPfileAllInfo.accessFlags = 0;
2903         qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2904         qpi.u.QPfileAllInfo.indexNumber2.LowPart  = scp->fid.unique;
2905         qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2906         qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2907         qpi.u.QPfileAllInfo.mode = 0;
2908         qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2909         len = strlen(lastComp);
2910         qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2911         mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2912     }
2913
2914     /* send and free the packets */
2915   done:
2916     lock_ReleaseMutex(&scp->mx);
2917     cm_ReleaseSCache(scp);
2918     cm_ReleaseUser(userp);
2919     if (code == 0) {
2920         memcpy(outp->datap, &qpi, responseSize);
2921         smb_SendTran2Packet(vcp, outp, opx);
2922     } else {
2923         smb_SendTran2Error(vcp, p, opx, code);
2924     }
2925     smb_FreeTran2Packet(outp);
2926
2927     return 0;
2928 }
2929
2930 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2931 {
2932 #if 0
2933     osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2934     return CM_ERROR_BADOP;
2935 #else
2936     long code = 0;
2937     smb_fid_t *fidp;
2938     unsigned short infoLevel;
2939     char * pathp;
2940     smb_tran2Packet_t *outp;
2941     smb_tran2QPathInfo_t *spi;
2942     cm_user_t *userp;
2943     cm_scache_t *scp, *dscp;
2944     cm_req_t req;
2945     cm_space_t *spacep;
2946     char *tidPathp;
2947     char *lastComp;
2948
2949     cm_InitReq(&req);
2950
2951     infoLevel = p->parmsp[0];
2952     osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2953     if (infoLevel != SMB_INFO_STANDARD && 
2954         infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2955         infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2956         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2957                   p->opcode, infoLevel);
2958         smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2959         return 0;
2960     }
2961
2962     pathp = (char *)(&p->parmsp[3]);
2963     if (smb_StoreAnsiFilenames)
2964         OemToChar(pathp,pathp);
2965     osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
2966               osi_LogSaveString(smb_logp, pathp));
2967
2968     userp = smb_GetTran2User(vcp, p);
2969     if (!userp) {
2970         osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
2971         code = CM_ERROR_BADSMB;
2972         goto done;
2973     }   
2974
2975     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2976     if (code == CM_ERROR_TIDIPC) {
2977         /* Attempt to use a TID allocated for IPC.  The client
2978          * is probably looking for DCE RPC end points which we
2979          * don't support OR it could be looking to make a DFS
2980          * referral request. 
2981          */
2982         osi_Log0(smb_logp, "Tran2Open received IPC TID");
2983         cm_ReleaseUser(userp);
2984         return CM_ERROR_NOSUCHPATH;
2985     }
2986
2987     /*
2988     * XXX Strange hack XXX
2989     *
2990     * As of Patch 7 (13 January 98), we are having the following problem:
2991     * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2992     * requests to look up "desktop.ini" in all the subdirectories.
2993     * This can cause zillions of timeouts looking up non-existent cells
2994     * and volumes, especially in the top-level directory.
2995     *
2996     * We have not found any way to avoid this or work around it except
2997     * to explicitly ignore the requests for mount points that haven't
2998     * yet been evaluated and for directories that haven't yet been
2999     * fetched.
3000     */
3001     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3002         spacep = cm_GetSpace();
3003         smb_StripLastComponent(spacep->data, &lastComp, pathp);
3004 #ifndef SPECIAL_FOLDERS
3005         /* Make sure that lastComp is not NULL */
3006         if (lastComp) {
3007             if (stricmp(lastComp, "\\desktop.ini") == 0) {
3008                 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3009                                  CM_FLAG_CASEFOLD
3010                                  | CM_FLAG_DIRSEARCH
3011                                  | CM_FLAG_FOLLOW,
3012                                  userp, tidPathp, &req, &dscp);
3013                 if (code == 0) {
3014 #ifdef DFS_SUPPORT
3015                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3016                         if ( WANTS_DFS_PATHNAMES(p) )
3017                             code = CM_ERROR_PATH_NOT_COVERED;
3018                         else
3019                             code = CM_ERROR_BADSHARENAME;
3020                     } else
3021 #endif /* DFS_SUPPORT */
3022                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3023                         code = CM_ERROR_NOSUCHFILE;
3024                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3025                         cm_buf_t *bp = buf_Find(dscp, &hzero);
3026                         if (bp)
3027                             buf_Release(bp);
3028                         else
3029                             code = CM_ERROR_NOSUCHFILE;
3030                     }
3031                     cm_ReleaseSCache(dscp);
3032                     if (code) {
3033                         cm_FreeSpace(spacep);
3034                         cm_ReleaseUser(userp);
3035                         smb_SendTran2Error(vcp, p, opx, code);
3036                         return 0;
3037                     }
3038                 }
3039             }
3040         }
3041 #endif /* SPECIAL_FOLDERS */
3042
3043         cm_FreeSpace(spacep);
3044     }
3045
3046     /* now do namei and stat, and copy out the info */
3047     code = cm_NameI(cm_data.rootSCachep, pathp,
3048                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3049     if (code) {
3050         cm_ReleaseUser(userp);
3051         smb_SendTran2Error(vcp, p, opx, code);
3052         return 0;
3053     }
3054
3055     fidp = smb_FindFIDByScache(vcp, scp);
3056     if (!fidp) {
3057         cm_ReleaseUser(userp);
3058         cm_ReleaseSCache(scp);
3059         smb_SendTran2Error(vcp, p, opx, code);
3060         return 0;
3061     }
3062
3063     lock_ObtainMutex(&fidp->mx);
3064     if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3065         lock_ReleaseMutex(&fidp->mx);
3066         smb_ReleaseFID(fidp);
3067         cm_ReleaseUser(userp);
3068         cm_ReleaseSCache(scp);
3069         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3070         return 0;
3071     }
3072     lock_ReleaseMutex(&fidp->mx);
3073
3074     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3075
3076     outp->totalParms = 2;
3077     outp->totalData = 0;
3078
3079     spi = (smb_tran2QPathInfo_t *)p->datap;
3080     if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3081         cm_attr_t attr;
3082
3083         /* lock the vnode with a callback; we need the current status
3084          * to determine what the new status is, in some cases.
3085          */
3086         lock_ObtainMutex(&scp->mx);
3087         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3088                           CM_SCACHESYNC_GETSTATUS
3089                          | CM_SCACHESYNC_NEEDCALLBACK);
3090         lock_ReleaseMutex(&scp->mx);
3091         if (code) {
3092             goto done;
3093         }
3094
3095         lock_ObtainMutex(&fidp->mx);
3096         lock_ObtainMutex(&scp->mx);
3097
3098         /* prepare for setattr call */
3099         attr.mask = CM_ATTRMASK_LENGTH;
3100         attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3101         attr.length.HighPart = 0;
3102
3103         if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3104             smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3105             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3106             fidp->flags |= SMB_FID_MTIMESETDONE;
3107         }
3108                 
3109         if (spi->u.QPstandardInfo.attributes != 0) {
3110             if ((scp->unixModeBits & 0222)
3111                  && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3112                 /* make a writable file read-only */
3113                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3114                 attr.unixModeBits = scp->unixModeBits & ~0222;
3115             }
3116             else if ((scp->unixModeBits & 0222) == 0
3117                       && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3118                 /* make a read-only file writable */
3119                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3120                 attr.unixModeBits = scp->unixModeBits | 0222;
3121             }
3122         }
3123         lock_ReleaseMutex(&scp->mx);
3124         lock_ReleaseMutex(&fidp->mx);
3125
3126         /* call setattr */
3127         if (attr.mask)
3128             code = cm_SetAttr(scp, &attr, userp, &req);
3129         else
3130             code = 0;
3131     }               
3132     else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3133         /* we don't support EAs */
3134         code = CM_ERROR_INVAL;
3135     }       
3136
3137   done:
3138     cm_ReleaseSCache(scp);
3139     cm_ReleaseUser(userp);
3140     smb_ReleaseFID(fidp);
3141     if (code == 0) 
3142         smb_SendTran2Packet(vcp, outp, opx);
3143     else 
3144         smb_SendTran2Error(vcp, p, opx, code);
3145     smb_FreeTran2Packet(outp);
3146
3147     return 0;
3148 #endif
3149 }
3150
3151 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3152 {
3153     smb_tran2Packet_t *outp;
3154     FILETIME ft;
3155     unsigned long attributes;
3156     unsigned short infoLevel;
3157     int responseSize;
3158     unsigned short fid;
3159     int delonclose = 0;
3160     cm_user_t *userp;
3161     smb_fid_t *fidp;
3162     cm_scache_t *scp;
3163     smb_tran2QFileInfo_t qfi;
3164     long code = 0;
3165     cm_req_t req;
3166
3167     cm_InitReq(&req);
3168
3169     fid = p->parmsp[0];
3170     fidp = smb_FindFID(vcp, fid, 0);
3171
3172     if (fidp == NULL) {
3173         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3174         return 0;
3175     }
3176
3177     infoLevel = p->parmsp[1];
3178     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) 
3179         responseSize = sizeof(qfi.u.QFbasicInfo);
3180     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) 
3181         responseSize = sizeof(qfi.u.QFstandardInfo);
3182     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3183         responseSize = sizeof(qfi.u.QFeaInfo);
3184     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
3185         responseSize = sizeof(qfi.u.QFfileNameInfo);
3186     else {
3187         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3188                   p->opcode, infoLevel);
3189         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3190         smb_ReleaseFID(fidp);
3191         return 0;
3192     }
3193     osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3194
3195     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3196
3197     if (infoLevel > 0x100)
3198         outp->totalParms = 2;
3199     else
3200         outp->totalParms = 0;
3201     outp->totalData = responseSize;
3202
3203     userp = smb_GetTran2User(vcp, p);
3204     if (!userp) {
3205         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3206         code = CM_ERROR_BADSMB;
3207         goto done;
3208     }   
3209
3210     lock_ObtainMutex(&fidp->mx);
3211     delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3212     scp = fidp->scp;
3213     cm_HoldSCache(scp);
3214     lock_ReleaseMutex(&fidp->mx);
3215     lock_ObtainMutex(&scp->mx);
3216     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3217                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3218     if (code) 
3219         goto done;
3220
3221     /* now we have the status in the cache entry, and everything is locked.
3222      * Marshall the output data.
3223      */
3224     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3225         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3226         qfi.u.QFbasicInfo.creationTime = ft;
3227         qfi.u.QFbasicInfo.lastAccessTime = ft;
3228         qfi.u.QFbasicInfo.lastWriteTime = ft;
3229         qfi.u.QFbasicInfo.lastChangeTime = ft;
3230         attributes = smb_ExtAttributes(scp);
3231         qfi.u.QFbasicInfo.attributes = attributes;
3232     }
3233     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3234         qfi.u.QFstandardInfo.allocationSize = scp->length;
3235         qfi.u.QFstandardInfo.endOfFile = scp->length;
3236         qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3237         qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3238         qfi.u.QFstandardInfo.directory = 
3239             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3240               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3241               scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3242     }
3243     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3244         qfi.u.QFeaInfo.eaSize = 0;
3245     }
3246     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3247         unsigned long len;
3248         char *name;
3249
3250         lock_ReleaseMutex(&scp->mx);
3251         lock_ObtainMutex(&fidp->mx);
3252         lock_ObtainMutex(&scp->mx);
3253         if (fidp->NTopen_wholepathp)
3254             name = fidp->NTopen_wholepathp;
3255         else
3256             name = "\\";        /* probably can't happen */
3257         lock_ReleaseMutex(&fidp->mx);
3258         len = (unsigned long)strlen(name);
3259         outp->totalData = ((len+1)*2) + 4;      /* this is actually what we want to return */
3260         qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3261         mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3262     }
3263
3264     /* send and free the packets */
3265   done:
3266     lock_ReleaseMutex(&scp->mx);
3267     cm_ReleaseSCache(scp);
3268     cm_ReleaseUser(userp);
3269     smb_ReleaseFID(fidp);
3270     if (code == 0) {
3271         memcpy(outp->datap, &qfi, responseSize);
3272         smb_SendTran2Packet(vcp, outp, opx);
3273     } else {
3274         smb_SendTran2Error(vcp, p, opx, code);
3275     }
3276     smb_FreeTran2Packet(outp);
3277
3278     return 0;
3279 }       
3280
3281 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3282 {
3283     long code = 0;
3284     unsigned short fid;
3285     smb_fid_t *fidp;
3286     unsigned short infoLevel;
3287     smb_tran2Packet_t *outp;
3288     cm_user_t *userp;
3289     cm_scache_t *scp;
3290     cm_req_t req;
3291
3292     cm_InitReq(&req);
3293
3294     fid = p->parmsp[0];
3295     fidp = smb_FindFID(vcp, fid, 0);
3296
3297     if (fidp == NULL) {
3298         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3299         return 0;
3300     }
3301
3302     infoLevel = p->parmsp[1];
3303     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3304     if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3305         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3306                   p->opcode, infoLevel);
3307         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3308         smb_ReleaseFID(fidp);
3309         return 0;
3310     }
3311
3312     lock_ObtainMutex(&fidp->mx);
3313     if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3314         lock_ReleaseMutex(&fidp->mx);
3315         smb_ReleaseFID(fidp);
3316         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3317         return 0;
3318     }
3319     if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO || 
3320          infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3321          && !(fidp->flags & SMB_FID_OPENWRITE)) {
3322         lock_ReleaseMutex(&fidp->mx);
3323         smb_ReleaseFID(fidp);
3324         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3325         return 0;
3326     }
3327
3328     scp = fidp->scp;
3329     cm_HoldSCache(scp);
3330     lock_ReleaseMutex(&fidp->mx);
3331
3332     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3333
3334     outp->totalParms = 2;
3335     outp->totalData = 0;
3336
3337     userp = smb_GetTran2User(vcp, p);
3338     if (!userp) {
3339         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3340         code = CM_ERROR_BADSMB;
3341         goto done;
3342     }   
3343
3344     if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3345         FILETIME lastMod;
3346         unsigned int attribute;
3347         cm_attr_t attr;
3348         smb_tran2QFileInfo_t *sfi;
3349
3350         sfi = (smb_tran2QFileInfo_t *)p->datap;
3351
3352         /* lock the vnode with a callback; we need the current status
3353          * to determine what the new status is, in some cases.
3354          */
3355         lock_ObtainMutex(&scp->mx);
3356         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3357                           CM_SCACHESYNC_GETSTATUS
3358                          | CM_SCACHESYNC_NEEDCALLBACK);
3359         lock_ReleaseMutex(&scp->mx);
3360         if (code)
3361             goto done;
3362
3363         lock_ObtainMutex(&fidp->mx);
3364         lock_ObtainMutex(&scp->mx);
3365
3366         /* prepare for setattr call */
3367         attr.mask = 0;
3368
3369         lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3370         /* when called as result of move a b, lastMod is (-1, -1). 
3371          * If the check for -1 is not present, timestamp
3372          * of the resulting file will be 1969 (-1)
3373          */
3374         if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
3375              lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3376             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3377             smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3378             fidp->flags |= SMB_FID_MTIMESETDONE;
3379         }
3380                 
3381         attribute = sfi->u.QFbasicInfo.attributes;
3382         if (attribute != 0) {
3383             if ((scp->unixModeBits & 0222)
3384                  && (attribute & SMB_ATTR_READONLY) != 0) {
3385                 /* make a writable file read-only */
3386                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3387                 attr.unixModeBits = scp->unixModeBits & ~0222;
3388             }
3389             else if ((scp->unixModeBits & 0222) == 0
3390                       && (attribute & SMB_ATTR_READONLY) == 0) {
3391                 /* make a read-only file writable */
3392                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3393                 attr.unixModeBits = scp->unixModeBits | 0222;
3394             }
3395         }
3396         lock_ReleaseMutex(&scp->mx);
3397         lock_ReleaseMutex(&fidp->mx);
3398
3399         /* call setattr */
3400         if (attr.mask)
3401             code = cm_SetAttr(scp, &attr, userp, &req);
3402         else
3403             code = 0;
3404     }
3405     else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3406         if (*((char *)(p->datap))) {    /* File is Deleted */
3407             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3408                                      &req);
3409             if (code == 0) {
3410                 lock_ObtainMutex(&fidp->mx);
3411                 fidp->flags |= SMB_FID_DELONCLOSE;
3412                 lock_ReleaseMutex(&fidp->mx);
3413             }
3414         }               
3415         else {  
3416             code = 0;
3417             lock_ObtainMutex(&fidp->mx);
3418             fidp->flags &= ~SMB_FID_DELONCLOSE;
3419             lock_ReleaseMutex(&fidp->mx);
3420         }
3421     }       
3422     else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3423              infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3424         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3425         cm_attr_t attr;
3426
3427         attr.mask = CM_ATTRMASK_LENGTH;
3428         attr.length.LowPart = size.LowPart;
3429         attr.length.HighPart = size.HighPart;
3430         code = cm_SetAttr(scp, &attr, userp, &req);
3431     }       
3432
3433   done:
3434     cm_ReleaseSCache(scp);
3435     cm_ReleaseUser(userp);
3436     smb_ReleaseFID(fidp);
3437     if (code == 0) 
3438         smb_SendTran2Packet(vcp, outp, opx);
3439     else 
3440         smb_SendTran2Error(vcp, p, opx, code);
3441     smb_FreeTran2Packet(outp);
3442
3443     return 0;
3444 }
3445
3446 long 
3447 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3448 {
3449     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3450     return CM_ERROR_BADOP;
3451 }
3452
3453 long 
3454 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3455 {
3456     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3457     return CM_ERROR_BADOP;
3458 }
3459
3460 long 
3461 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3462 {
3463     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3464     return CM_ERROR_BADOP;
3465 }
3466
3467 long 
3468 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3469 {
3470     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3471     return CM_ERROR_BADOP;
3472 }
3473
3474 long 
3475 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3476 {
3477     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3478     return CM_ERROR_BADOP;
3479 }
3480
3481 long 
3482 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3483 {
3484     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3485     return CM_ERROR_BADOP;
3486 }
3487
3488 struct smb_v2_referral {
3489     USHORT ServerType;
3490     USHORT ReferralFlags;
3491     ULONG  Proximity;
3492     ULONG  TimeToLive;
3493     USHORT DfsPathOffset;
3494     USHORT DfsAlternativePathOffset;
3495     USHORT NetworkAddressOffset;
3496 };
3497
3498 long 
3499 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3500 {
3501     /* This is a UNICODE only request (bit15 of Flags2) */
3502     /* The TID must be IPC$ */
3503
3504     /* The documentation for the Flags response field is contradictory */
3505
3506     /* Use Version 1 Referral Element Format */
3507     /* ServerType = 0; indicates the next server should be queried for the file */
3508     /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3509     /* Node = UnicodeString of UNC path of the next share name */
3510 #ifdef DFS_SUPPORT
3511     long code = 0;
3512     int maxReferralLevel = 0;
3513     char requestFileName[1024] = "";
3514     smb_tran2Packet_t *outp = 0;
3515     cm_user_t *userp = 0;
3516     cm_req_t req;
3517     CPINFO CodePageInfo;
3518     int i, nbnLen, reqLen;
3519     int idx;
3520
3521     cm_InitReq(&req);
3522
3523     maxReferralLevel = p->parmsp[0];
3524
3525     GetCPInfo(CP_ACP, &CodePageInfo);
3526     WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1, 
3527                         requestFileName, 1024, NULL, NULL);
3528
3529     osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]", 
3530              maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3531
3532     nbnLen = strlen(cm_NetbiosName);
3533     reqLen = strlen(requestFileName);
3534
3535     if (reqLen == nbnLen + 5 &&
3536         requestFileName[0] == '\\' &&
3537         !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3538         requestFileName[nbnLen+1] == '\\' &&
3539         (!_strnicmp("all",&requestFileName[nbnLen+2],3) || 
3540           !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3541     {
3542         USHORT * sp;
3543         struct smb_v2_referral * v2ref;
3544         outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3545
3546         sp = (USHORT *)outp->datap;
3547         idx = 0;
3548         sp[idx++] = reqLen;   /* path consumed */
3549         sp[idx++] = 1;        /* number of referrals */
3550         sp[idx++] = 0x03;     /* flags */
3551 #ifdef DFS_VERSION_1
3552         sp[idx++] = 1;        /* Version Number */
3553         sp[idx++] = reqLen + 4;  /* Referral Size */ 
3554         sp[idx++] = 1;        /* Type = SMB Server */
3555         sp[idx++] = 0;        /* Do not strip path consumed */
3556         for ( i=0;i<=reqLen; i++ )
3557             sp[i+idx] = requestFileName[i];
3558 #else /* DFS_VERSION_2 */
3559         sp[idx++] = 2;      /* Version Number */
3560         sp[idx++] = sizeof(struct smb_v2_referral);     /* Referral Size */
3561         idx += (sizeof(struct smb_v2_referral) / 2);
3562         v2ref = (struct smb_v2_referral *) &sp[5];
3563         v2ref->ServerType = 1;  /* SMB Server */
3564         v2ref->ReferralFlags = 0x03;
3565         v2ref->Proximity = 0;   /* closest */
3566         v2ref->TimeToLive = 3600; /* seconds */
3567         v2ref->DfsPathOffset = idx * 2;
3568         v2ref->DfsAlternativePathOffset = idx * 2;
3569         v2ref->NetworkAddressOffset = 0;
3570         for ( i=0;i<=reqLen; i++ )
3571             sp[i+idx] = requestFileName[i];
3572 #endif
3573     } else {
3574         userp = smb_GetTran2User(vcp, p);
3575         if (!userp) {
3576             osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3577             code = CM_ERROR_BADSMB;
3578             goto done;
3579         }   
3580
3581                 /* not done yet */
3582         code = CM_ERROR_NOSUCHPATH;
3583     }
3584
3585   done:
3586     if (userp)
3587         cm_ReleaseUser(userp);
3588     if (code == 0) 
3589         smb_SendTran2Packet(vcp, outp, op);
3590     else 
3591         smb_SendTran2Error(vcp, p, op, code);
3592     if (outp)
3593         smb_FreeTran2Packet(outp);
3594  
3595     return 0;
3596 #else /* DFS_SUPPORT */
3597     osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED"); 
3598     return CM_ERROR_BADOP;
3599 #endif /* DFS_SUPPORT */
3600 }
3601
3602 long 
3603 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3604 {
3605     /* This is a UNICODE only request (bit15 of Flags2) */
3606
3607     /* There is nothing we can do about this operation.  The client is going to
3608      * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3609      * Unfortunately, there is really nothing we can do about it other then log it 
3610      * somewhere.  Even then I don't think there is anything for us to do.
3611      * So let's return an error value.
3612      */
3613
3614     osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3615     return CM_ERROR_BADOP;
3616 }
3617
3618 long 
3619 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3620         smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3621         cm_req_t *reqp)
3622 {
3623     long code = 0;
3624     cm_scache_t *scp;
3625     cm_scache_t *targetScp;                     /* target if scp is a symlink */
3626     char *dptr;
3627     afs_uint32 dosTime;
3628     FILETIME ft;
3629     int shortTemp;
3630     unsigned short attr;
3631     unsigned long lattr;
3632     smb_dirListPatch_t *patchp;
3633     smb_dirListPatch_t *npatchp;
3634         
3635     for(patchp = *dirPatchespp; patchp; patchp =
3636          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3637                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3638         if (code) continue;
3639         lock_ObtainMutex(&scp->mx);
3640         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3641                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3642         if (code) { 
3643             lock_ReleaseMutex(&scp->mx);
3644             cm_ReleaseSCache(scp);
3645
3646             dptr = patchp->dptr;
3647
3648             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3649                errors in the client. */
3650             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3651                 /* 1969-12-31 23:59:59 +00 */
3652                 ft.dwHighDateTime = 0x19DB200;
3653                 ft.dwLowDateTime = 0x5BB78980;
3654
3655                 /* copy to Creation Time */
3656                 *((FILETIME *)dptr) = ft;
3657                 dptr += 8;
3658
3659                 /* copy to Last Access Time */
3660                 *((FILETIME *)dptr) = ft;
3661                 dptr += 8;
3662
3663                 /* copy to Last Write Time */
3664                 *((FILETIME *)dptr) = ft;
3665                 dptr += 8;
3666
3667                 /* copy to Change Time */
3668                 *((FILETIME *)dptr) = ft;
3669                 dptr += 24;
3670
3671                 /* merge in hidden attribute */
3672                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3673                     *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3674                 }
3675                 dptr += 4;
3676             } else {
3677                 /* 1969-12-31 23:59:58 +00*/
3678                 dosTime = 0xEBBFBF7D;
3679
3680                 /* and copy out date */
3681                 shortTemp = (dosTime>>16) & 0xffff;
3682                 *((u_short *)dptr) = shortTemp;
3683                 dptr += 2;
3684
3685                 /* copy out creation time */
3686                 shortTemp = dosTime & 0xffff;
3687                 *((u_short *)dptr) = shortTemp;
3688                 dptr += 2;
3689
3690                 /* and copy out date */
3691                 shortTemp = (dosTime>>16) & 0xffff;
3692                 *((u_short *)dptr) = shortTemp;
3693                 dptr += 2;
3694                         
3695                 /* copy out access time */
3696                 shortTemp = dosTime & 0xffff;
3697                 *((u_short *)dptr) = shortTemp;
3698                 dptr += 2;
3699
3700                 /* and copy out date */
3701                 shortTemp = (dosTime>>16) & 0xffff;
3702                 *((u_short *)dptr) = shortTemp;
3703                 dptr += 2;
3704                         
3705                 /* copy out mod time */
3706                 shortTemp = dosTime & 0xffff;
3707                 *((u_short *)dptr) = shortTemp;
3708                 dptr += 10;
3709
3710                 /* merge in hidden (dot file) attribute */
3711                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3712                     attr = SMB_ATTR_HIDDEN;
3713                     *dptr++ = attr & 0xff;
3714                     *dptr++ = (attr >> 8) & 0xff;
3715                 }       
3716             }
3717             continue;
3718         }
3719                 
3720         /* now watch for a symlink */
3721         code = 0;
3722         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3723             lock_ReleaseMutex(&scp->mx);
3724             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3725             if (code == 0) {
3726                 /* we have a more accurate file to use (the
3727                  * target of the symbolic link).  Otherwise,
3728                  * we'll just use the symlink anyway.
3729                  */
3730                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3731                           scp, targetScp);
3732                 cm_ReleaseSCache(scp);
3733                 scp = targetScp;
3734             }
3735             lock_ObtainMutex(&scp->mx);
3736         }
3737
3738         dptr = patchp->dptr;
3739
3740         if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3741             /* get filetime */
3742             smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3743
3744             /* copy to Creation Time */
3745             *((FILETIME *)dptr) = ft;
3746             dptr += 8;
3747
3748             /* copy to Last Access Time */
3749             *((FILETIME *)dptr) = ft;
3750             dptr += 8;
3751
3752             /* copy to Last Write Time */
3753             *((FILETIME *)dptr) = ft;
3754             dptr += 8;
3755
3756             /* copy to Change Time */
3757             *((FILETIME *)dptr) = ft;
3758             dptr += 8;
3759
3760             /* Use length for both file length and alloc length */
3761             *((LARGE_INTEGER *)dptr) = scp->length;
3762             dptr += 8;
3763             *((LARGE_INTEGER *)dptr) = scp->length;
3764             dptr += 8;
3765
3766             /* Copy attributes */
3767             lattr = smb_ExtAttributes(scp);
3768             if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3769                 if (lattr == SMB_ATTR_NORMAL)
3770                     lattr = SMB_ATTR_DIRECTORY;
3771                 else
3772                     lattr |= SMB_ATTR_DIRECTORY;
3773             }
3774             /* merge in hidden (dot file) attribute */
3775             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3776                 if (lattr == SMB_ATTR_NORMAL)
3777                     lattr = SMB_ATTR_HIDDEN;
3778                 else
3779                     lattr |= SMB_ATTR_HIDDEN;
3780             }
3781             *((u_long *)dptr) = lattr;
3782             dptr += 4;
3783         } else {
3784             /* get dos time */
3785             smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3786
3787             /* and copy out date */
3788             shortTemp = (dosTime>>16) & 0xffff;
3789             *((u_short *)dptr) = shortTemp;
3790             dptr += 2;
3791
3792             /* copy out creation time */
3793             shortTemp = dosTime & 0xffff;
3794             *((u_short *)dptr) = shortTemp;
3795             dptr += 2;
3796
3797             /* and copy out date */
3798             shortTemp = (dosTime>>16) & 0xffff;
3799             *((u_short *)dptr) = shortTemp;
3800             dptr += 2;
3801
3802             /* copy out access time */
3803             shortTemp = dosTime & 0xffff;
3804             *((u_short *)dptr) = shortTemp;
3805             dptr += 2;
3806
3807             /* and copy out date */
3808             shortTemp = (dosTime>>16) & 0xffff;
3809             *((u_short *)dptr) = shortTemp;
3810             dptr += 2;
3811
3812             /* copy out mod time */
3813             shortTemp = dosTime & 0xffff;
3814             *((u_short *)dptr) = shortTemp;
3815             dptr += 2;
3816
3817             /* copy out file length and alloc length,
3818              * using the same for both
3819              */
3820             *((u_long *)dptr) = scp->length.LowPart;
3821             dptr += 4;
3822             *((u_long *)dptr) = scp->length.LowPart;
3823             dptr += 4;
3824
3825             /* finally copy out attributes as short */
3826             attr = smb_Attributes(scp);
3827             /* merge in hidden (dot file) attribute */
3828             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3829                 if (lattr == SMB_ATTR_NORMAL)
3830                     lattr = SMB_ATTR_HIDDEN;
3831                 else
3832                     lattr |= SMB_ATTR_HIDDEN;
3833             }
3834             *dptr++ = attr & 0xff;
3835             *dptr++ = (attr >> 8) & 0xff;
3836         }
3837
3838         lock_ReleaseMutex(&scp->mx);
3839         cm_ReleaseSCache(scp);
3840     }
3841         
3842     /* now free the patches */
3843     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3844         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3845         free(patchp);
3846     }
3847         
3848     /* and mark the list as empty */
3849     *dirPatchespp = NULL;
3850
3851     return code;
3852 }
3853
3854 #ifndef USE_OLD_MATCHING
3855 // char table for case insensitive comparison
3856 char mapCaseTable[256];
3857
3858 VOID initUpperCaseTable(VOID) 
3859 {
3860     int i;
3861     for (i = 0; i < 256; ++i) 
3862        mapCaseTable[i] = toupper(i);
3863     // make '"' match '.' 
3864     mapCaseTable[(int)'"'] = toupper('.');
3865     // make '<' match '*' 
3866     mapCaseTable[(int)'<'] = toupper('*');
3867     // make '>' match '?' 
3868     mapCaseTable[(int)'>'] = toupper('?');    
3869 }
3870
3871 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3872 // name 'name'.
3873 // Note : this procedure works recursively calling itself.
3874 // Parameters
3875 // PSZ pattern    : string containing metacharacters.
3876 // PSZ name       : file name to be compared with 'pattern'.
3877 // Return value
3878 // BOOL : TRUE/FALSE (match/mistmatch)
3879
3880 BOOL 
3881 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold) 
3882 {
3883     PSZ pename;         // points to the last 'name' character
3884     PSZ p;
3885     pename = name + strlen(name) - 1;
3886     while (*name) {
3887         switch (*pattern) {
3888         case '?':
3889             ++pattern;
3890             if (*name == '.')
3891                 continue;
3892             ++name;
3893             break;
3894          case '*':
3895             ++pattern;
3896             if (*pattern == '\0')
3897                 return TRUE;
3898             for (p = pename; p >= name; --p) {
3899                 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3900                      !casefold && (*p == *pattern)) &&
3901                      szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3902                     return TRUE;
3903             } /* endfor */
3904             return FALSE;
3905         default:
3906             if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3907                 (!casefold && *name != *pattern))
3908                 return FALSE;
3909             ++pattern, ++name;
3910             break;
3911         } /* endswitch */
3912     } /* endwhile */ 
3913
3914     /* if all we have left are wildcards, then we match */
3915     for (;*pattern; pattern++) {
3916         if (*pattern != '*' && *pattern != '?')
3917             return FALSE;
3918     }
3919     return TRUE;
3920 }
3921
3922 /* do a case-folding search of the star name mask with the name in namep.
3923  * Return 1 if we match, otherwise 0.
3924  */
3925 int smb_V3MatchMask(char *namep, char *maskp, int flags) 
3926 {
3927     char * newmask;
3928     int    i, j, star, qmark, casefold, retval;
3929
3930     /* make sure we only match 8.3 names, if requested */
3931     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
3932         return 0;
3933     
3934     casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3935
3936     /* optimize the pattern:
3937      * if there is a mixture of '?' and '*',
3938      * for example  the sequence "*?*?*?*"
3939      * must be turned into the form "*"
3940      */
3941     newmask = (char *)malloc(strlen(maskp)+1);
3942     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3943         switch ( maskp[i] ) {
3944         case '?':
3945         case '>':
3946             qmark++;
3947             break;
3948         case '<':
3949         case '*':
3950             star++;
3951             break;
3952         default:
3953             if ( star ) {
3954                 newmask[j++] = '*';
3955             } else if ( qmark ) {
3956                 while ( qmark-- )
3957                     newmask[j++] = '?';
3958             }
3959             newmask[j++] = maskp[i];
3960             star = 0;
3961             qmark = 0;
3962         }
3963     }
3964     if ( star ) {
3965         newmask[j++] = '*';
3966     } else if ( qmark ) {
3967         while ( qmark-- )
3968             newmask[j++] = '?';
3969     }
3970     newmask[j++] = '\0';
3971
3972     retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3973
3974     free(newmask);
3975     return retval;
3976 }
3977
3978 #else /* USE_OLD_MATCHING */
3979 /* do a case-folding search of the star name mask with the name in namep.
3980  * Return 1 if we match, otherwise 0.
3981  */
3982 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3983 {
3984     unsigned char tcp1, tcp2;   /* Pattern characters */
3985     unsigned char tcn1;         /* Name characters */
3986     int sawDot = 0, sawStar = 0, req8dot3 = 0;
3987     char *starNamep, *starMaskp;
3988     static char nullCharp[] = {0};
3989     int casefold = flags & CM_FLAG_CASEFOLD;
3990
3991     /* make sure we only match 8.3 names, if requested */
3992     req8dot3 = (flags & CM_FLAG_8DOT3);
3993     if (req8dot3 && !cm_Is8Dot3(namep)) 
3994         return 0;
3995
3996     /* loop */
3997     while (1) {
3998         /* Next pattern character */
3999         tcp1 = *maskp++;
4000
4001         /* Next name character */
4002         tcn1 = *namep;
4003
4004         if (tcp1 == 0) {
4005             /* 0 - end of pattern */
4006             if (tcn1 == 0)
4007                 return 1;
4008             else
4009                 return 0;
4010         }
4011         else if (tcp1 == '.' || tcp1 == '"') {
4012             if (sawDot) {
4013                 if (tcn1 == '.') {
4014                     namep++;
4015                     continue;
4016                 } else
4017                     return 0;
4018             }
4019             else {
4020                 /*
4021                  * first dot in pattern;
4022                  * must match dot or end of name
4023                  */
4024                 sawDot = 1;
4025                 if (tcn1 == 0)
4026                     continue;
4027                 else if (tcn1 == '.') {
4028                     sawStar = 0;
4029                     namep++;
4030                     continue;
4031                 }
4032                 else
4033                     return 0;
4034             }
4035         }
4036         else if (tcp1 == '?') {
4037             if (tcn1 == 0 || tcn1 == '.')
4038                 return 0;
4039             namep++;
4040             continue;
4041         }
4042         else if (tcp1 == '>') {
4043             if (tcn1 != 0 && tcn1 != '.')
4044                 namep++;
4045             continue;
4046         }
4047         else if (tcp1 == '*' || tcp1 == '<') {
4048             tcp2 = *maskp++;
4049             if (tcp2 == 0)
4050                 return 1;
4051             else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4052                 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4053                     tcn1 = *++namep;
4054                 if (tcn1 == 0) {
4055                     if (sawDot)
4056                         return 0;
4057                     else
4058                         continue;
4059                 }
4060                 else {
4061                     namep++;
4062                     continue;
4063                 }
4064             }
4065             else {
4066                 /*
4067                  * pattern character after '*' is not null or
4068                  * period.  If it is '?' or '>', we are not
4069                  * going to understand it.  If it is '*' or
4070                  * '<', we are going to skip over it.  None of
4071                  * these are likely, I hope.
4072                  */
4073                 /* skip over '*' and '<' */
4074                 while (tcp2 == '*' || tcp2 == '<')
4075                     tcp2 = *maskp++;
4076
4077                 /* skip over characters that don't match tcp2 */
4078                 while (req8dot3 && tcn1 != '.' && tcn1 != 0 && 
4079                         ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
4080                           (!casefold && tcn1 != tcp2)))
4081                     tcn1 = *++namep;
4082
4083                 /* No match */
4084                 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4085                     return 0;
4086
4087                 /* Remember where we are */
4088                 sawStar = 1;
4089                 starMaskp = maskp;
4090                 starNamep = namep;
4091
4092                 namep++;
4093                 continue;
4094             }
4095         }
4096         else {
4097             /* tcp1 is not a wildcard */
4098             if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
4099                  (!casefold && tcn1 == tcp1)) {
4100                 /* they match */
4101                 namep++;
4102                 continue;
4103             }
4104             /* if trying to match a star pattern, go back */
4105             if (sawStar) {
4106                 maskp = starMaskp - 2;
4107                 namep = starNamep + 1;
4108                 sawStar = 0;
4109                 continue;
4110             }
4111             /* that's all */
4112             return 0;
4113         }
4114     }
4115 }
4116 #endif /* USE_OLD_MATCHING */
4117
4118 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4119 {
4120     int attribute;
4121     long nextCookie;
4122     char *tp;
4123     long code = 0, code2 = 0;
4124     char *pathp;
4125     cm_dirEntry_t *dep;
4126     int maxCount;
4127     smb_dirListPatch_t *dirListPatchesp;
4128     smb_dirListPatch_t *curPatchp;
4129     cm_buf_t *bufferp;
4130     long temp;
4131     long orbytes;                       /* # of bytes in this output record */
4132     long ohbytes;                       /* # of bytes, except file name */
4133     long onbytes;                       /* # of bytes in name, incl. term. null */
4134     osi_hyper_t dirLength;
4135     osi_hyper_t bufferOffset;
4136     osi_hyper_t curOffset;
4137     osi_hyper_t thyper;
4138     smb_dirSearch_t *dsp;
4139     cm_scache_t *scp;
4140     long entryInDir;
4141     long entryInBuffer;
4142     cm_pageHeader_t *pageHeaderp;
4143     cm_user_t *userp = NULL;
4144     int slotInPage;
4145     int returnedNames;
4146     long nextEntryCookie;
4147     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
4148     char *op;                   /* output data ptr */
4149     char *origOp;                       /* original value of op */
4150     cm_space_t *spacep;         /* for pathname buffer */
4151     long maxReturnData;         /* max # of return data */
4152     long maxReturnParms;                /* max # of return parms */
4153     long bytesInBuffer;         /* # data bytes in the output buffer */
4154     int starPattern;
4155     char *maskp;                        /* mask part of path */
4156     int infoLevel;
4157     int searchFlags;
4158     int eos;
4159     smb_tran2Packet_t *outp;    /* response packet */
4160     char *tidPathp;
4161     int align;
4162     char shortName[13];         /* 8.3 name if needed */
4163     int NeedShortName;
4164     int foundInexact;
4165     char *shortNameEnd;
4166     int fileType;
4167     cm_fid_t fid;
4168     cm_req_t req;
4169     char * s;
4170
4171     cm_InitReq(&req);
4172
4173     eos = 0;
4174     if (p->opcode == 1) {
4175         /* find first; obtain basic parameters from request */
4176         attribute = p->parmsp[0];
4177         maxCount = p->parmsp[1];
4178         infoLevel = p->parmsp[3];
4179         searchFlags = p->parmsp[2];
4180         dsp = smb_NewDirSearch(1);
4181         dsp->attribute = attribute;
4182         pathp = ((char *) p->parmsp) + 12;      /* points to path */
4183         if (smb_StoreAnsiFilenames)
4184             OemToChar(pathp,pathp);
4185         nextCookie = 0;
4186         maskp = strrchr(pathp, '\\');
4187         if (maskp == NULL) 
4188             maskp = pathp;
4189         else 
4190             maskp++;    /* skip over backslash */
4191         strcpy(dsp->mask, maskp);       /* and save mask */
4192         /* track if this is likely to match a lot of entries */
4193         starPattern = smb_V3IsStarMask(maskp);
4194     }
4195     else {
4196         osi_assert(p->opcode == 2);
4197         /* find next; obtain basic parameters from request or open dir file */
4198         dsp = smb_FindDirSearch(p->parmsp[0]);
4199         maxCount = p->parmsp[1];
4200         infoLevel = p->parmsp[2];
4201         nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
4202         searchFlags = p->parmsp[5];
4203         if (!dsp) {
4204             osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
4205                      p->parmsp[0], nextCookie);
4206             return CM_ERROR_BADFD;
4207         }
4208         attribute = dsp->attribute;
4209         pathp = NULL;
4210         maskp = dsp->mask;
4211         starPattern = 1;        /* assume, since required a Find Next */
4212     }
4213
4214     switch ( infoLevel ) {
4215     case SMB_INFO_STANDARD:
4216         s = "InfoStandard";
4217         break;
4218     case SMB_INFO_QUERY_EA_SIZE:
4219         s = "InfoQueryEaSize";
4220         break;
4221     case SMB_INFO_QUERY_EAS_FROM_LIST:
4222         s = "InfoQueryEasFromList";
4223         break;
4224     case SMB_FIND_FILE_DIRECTORY_INFO:
4225         s = "FindFileDirectoryInfo";
4226         break;
4227     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
4228         s = "FindFileFullDirectoryInfo";
4229         break;
4230     case SMB_FIND_FILE_NAMES_INFO:
4231         s = "FindFileNamesInfo";
4232         break;
4233     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
4234         s = "FindFileBothDirectoryInfo";
4235         break;
4236     default:
4237         s = "unknownInfoLevel";
4238     }
4239
4240     osi_Log1(smb_logp, "T2 search dir info level: %s", s);
4241
4242     osi_Log4(smb_logp,
4243               "T2 search dir attr 0x%x, info level 0x%x, max count %d, flags 0x%x",
4244               attribute, infoLevel, maxCount, searchFlags);
4245
4246     osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
4247               p->opcode, dsp->cookie, nextCookie);
4248
4249     if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4250         searchFlags &= ~4;      /* no resume keys */
4251
4252     dirListPatchesp = NULL;
4253
4254     maxReturnData = p->maxReturnData;
4255     if (p->opcode == 1) /* find first */
4256         maxReturnParms = 10;    /* bytes */
4257     else    
4258         maxReturnParms = 8;     /* bytes */
4259
4260 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
4261     if (maxReturnData > 6000) 
4262         maxReturnData = 6000;
4263 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
4264
4265     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
4266                                       maxReturnData);
4267
4268     osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
4269              maxCount, osi_LogSaveString(smb_logp, pathp));
4270         
4271     /* bail out if request looks bad */
4272     if (p->opcode == 1 && !pathp) {
4273         smb_ReleaseDirSearch(dsp);
4274         smb_FreeTran2Packet(outp);
4275         return CM_ERROR_BADSMB;
4276     }
4277         
4278     osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
4279              dsp->cookie, nextCookie, attribute);
4280
4281     userp = smb_GetTran2User(vcp, p);
4282     if (!userp) {
4283         osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
4284         smb_ReleaseDirSearch(dsp);
4285         smb_FreeTran2Packet(outp);
4286         return CM_ERROR_BADSMB;
4287     }
4288
4289     /* try to get the vnode for the path name next */
4290     lock_ObtainMutex(&dsp->mx);
4291     if (dsp->scp) {
4292         scp = dsp->scp;
4293         cm_HoldSCache(scp);
4294         code = 0;
4295     } else {
4296         spacep = cm_GetSpace();
4297         smb_StripLastComponent(spacep->data, NULL, pathp);
4298         code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
4299         if (code) {
4300             cm_ReleaseUser(userp);
4301             smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
4302             smb_FreeTran2Packet(outp);
4303             lock_ReleaseMutex(&dsp->mx);
4304             smb_DeleteDirSearch(dsp);
4305             smb_ReleaseDirSearch(dsp);
4306             return 0;
4307         }
4308         code = cm_NameI(cm_data.rootSCachep, spacep->data,
4309                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4310                         userp, tidPathp, &req, &scp);
4311         cm_FreeSpace(spacep);
4312
4313         if (code == 0) {
4314 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
4315             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4316                 cm_ReleaseSCache(scp);
4317                 cm_ReleaseUser(userp);
4318                 if ( WANTS_DFS_PATHNAMES(p) )
4319                     code = CM_ERROR_PATH_NOT_COVERED;
4320                 else
4321                     code = CM_ERROR_BADSHARENAME;
4322                 smb_SendTran2Error(vcp, p, opx, code);
4323                 smb_FreeTran2Packet(outp);
4324                 lock_ReleaseMutex(&dsp->mx);
4325                 smb_DeleteDirSearch(dsp);
4326                 smb_ReleaseDirSearch(dsp);
4327                 return 0;
4328             }
4329 #endif /* DFS_SUPPORT */
4330             dsp->scp = scp;
4331             /* we need one hold for the entry we just stored into,
4332              * and one for our own processing.  When we're done
4333              * with this function, we'll drop the one for our own
4334              * processing.  We held it once from the namei call,
4335              * and so we do another hold now.
4336              */
4337             cm_HoldSCache(scp);
4338             lock_ObtainMutex(&scp->mx);
4339             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
4340                  LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4341                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4342                 dsp->flags |= SMB_DIRSEARCH_BULKST;
4343             }
4344             lock_ReleaseMutex(&scp->mx);
4345         } 
4346     }
4347     lock_ReleaseMutex(&dsp->mx);
4348     if (code) {
4349         cm_ReleaseUser(userp);
4350         smb_FreeTran2Packet(outp);
4351         smb_DeleteDirSearch(dsp);
4352         smb_ReleaseDirSearch(dsp);
4353         return code;
4354     }
4355
4356     /* get the directory size */
4357     lock_ObtainMutex(&scp->mx);
4358     code = cm_SyncOp(scp, NULL, userp, &req, 0,
4359                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4360     if (code) {
4361         lock_ReleaseMutex(&scp->mx);
4362         cm_ReleaseSCache(scp);
4363         cm_ReleaseUser(userp);
4364         smb_FreeTran2Packet(outp);
4365         smb_DeleteDirSearch(dsp);
4366         smb_ReleaseDirSearch(dsp);
4367         return code;
4368     }
4369
4370   startsearch:
4371     dirLength = scp->length;
4372     bufferp = NULL;
4373     bufferOffset.LowPart = bufferOffset.HighPart = 0;
4374     curOffset.HighPart = 0;
4375     curOffset.LowPart = nextCookie;
4376     origOp = outp->datap;
4377
4378     foundInexact = 0;
4379     code = 0;
4380     returnedNames = 0;
4381     bytesInBuffer = 0;
4382     while (1) {
4383         op = origOp;
4384         if (searchFlags & 4)
4385             /* skip over resume key */
4386             op += 4;
4387
4388         /* make sure that curOffset.LowPart doesn't point to the first
4389          * 32 bytes in the 2nd through last dir page, and that it doesn't
4390          * point at the first 13 32-byte chunks in the first dir page,
4391          * since those are dir and page headers, and don't contain useful
4392          * information.
4393          */
4394         temp = curOffset.LowPart & (2048-1);
4395         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4396             /* we're in the first page */
4397             if (temp < 13*32) temp = 13*32;
4398         }
4399         else {
4400             /* we're in a later dir page */
4401             if (temp < 32) temp = 32;
4402         }
4403                 
4404         /* make sure the low order 5 bits are zero */
4405         temp &= ~(32-1);
4406                 
4407         /* now put temp bits back ito curOffset.LowPart */
4408         curOffset.LowPart &= ~(2048-1);
4409         curOffset.LowPart |= temp;
4410
4411         /* check if we've passed the dir's EOF */
4412         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4413             osi_Log0(smb_logp, "T2 search dir passed eof");
4414             eos = 1;
4415             break;
4416         }
4417
4418         /* check if we've returned all the names that will fit in the
4419          * response packet; we check return count as well as the number
4420          * of bytes requested.  We check the # of bytes after we find
4421          * the dir entry, since we'll need to check its size.
4422          */
4423         if (returnedNames >= maxCount) {
4424             osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4425                       returnedNames, maxCount);
4426             break;
4427         }
4428
4429         /* see if we can use the bufferp we have now; compute in which
4430          * page the current offset would be, and check whether that's
4431          * the offset of the buffer we have.  If not, get the buffer.
4432          */
4433         thyper.HighPart = curOffset.HighPart;
4434         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4435         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4436             /* wrong buffer */
4437             if (bufferp) {
4438                 buf_Release(bufferp);
4439                 bufferp = NULL;
4440             }       
4441             lock_ReleaseMutex(&scp->mx);
4442             lock_ObtainRead(&scp->bufCreateLock);
4443             code = buf_Get(scp, &thyper, &bufferp);
4444             lock_ReleaseRead(&scp->bufCreateLock);
4445             lock_ObtainMutex(&dsp->mx);
4446
4447             /* now, if we're doing a star match, do bulk fetching
4448              * of all of the status info for files in the dir.
4449              */
4450             if (starPattern) {
4451                 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4452                                            infoLevel, userp,
4453                                            &req);
4454                 lock_ObtainMutex(&scp->mx);
4455                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4456                     LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4457                     /* Don't bulk stat if risking timeout */
4458                     int now = GetTickCount();
4459                     if (now - req.startTime > RDRtimeout) {
4460                         scp->bulkStatProgress = thyper;
4461                         scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4462                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4463                     } else
4464                         code = cm_TryBulkStat(scp, &thyper, userp, &req);
4465                 }
4466             } else {
4467                 lock_ObtainMutex(&scp->mx);
4468             }
4469             lock_ReleaseMutex(&dsp->mx);
4470             if (code) {
4471                 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4472                 break;
4473             }
4474
4475             bufferOffset = thyper;
4476
4477             /* now get the data in the cache */
4478             while (1) {
4479                 code = cm_SyncOp(scp, bufferp, userp, &req,
4480                                  PRSFS_LOOKUP,
4481                                  CM_SCACHESYNC_NEEDCALLBACK
4482                                  | CM_SCACHESYNC_READ);
4483                 if (code) {
4484                     osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4485                     break;
4486                 }
4487                                 
4488                 if (cm_HaveBuffer(scp, bufferp, 0)) {
4489                     osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4490                     break;
4491                 }
4492
4493                 /* otherwise, load the buffer and try again */
4494                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4495                                     &req);
4496                 if (code) {
4497                     osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d", 
4498                               scp, bufferp, code);
4499                     break;
4500                 }
4501             }
4502             if (code) {
4503                 buf_Release(bufferp);
4504                 bufferp = NULL;
4505                 break;
4506             }
4507         }       /* if (wrong buffer) ... */
4508                 
4509         /* now we have the buffer containing the entry we're interested
4510          * in; copy it out if it represents a non-deleted entry.
4511          */
4512         entryInDir = curOffset.LowPart & (2048-1);
4513         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4514
4515         /* page header will help tell us which entries are free.  Page
4516          * header can change more often than once per buffer, since
4517          * AFS 3 dir page size may be less than (but not more than)
4518          * a buffer package buffer.
4519          */
4520         /* only look intra-buffer */
4521         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4522         temp &= ~(2048 - 1);    /* turn off intra-page bits */
4523         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4524
4525         /* now determine which entry we're looking at in the page.
4526          * If it is free (there's a free bitmap at the start of the
4527          * dir), we should skip these 32 bytes.
4528          */
4529         slotInPage = (entryInDir & 0x7e0) >> 5;
4530         if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4531             (1 << (slotInPage & 0x7)))) {
4532             /* this entry is free */
4533             numDirChunks = 1;   /* only skip this guy */
4534             goto nextEntry;
4535         }
4536
4537         tp = bufferp->datap + entryInBuffer;
4538         dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
4539
4540         /* while we're here, compute the next entry's location, too,
4541          * since we'll need it when writing out the cookie into the dir
4542          * listing stream.
4543          *
4544          * XXXX Probably should do more sanity checking.
4545          */
4546         numDirChunks = cm_NameEntries(dep->name, &onbytes);
4547                 
4548         /* compute offset of cookie representing next entry */
4549         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4550
4551         /* Need 8.3 name? */
4552         NeedShortName = 0;
4553         if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO
4554              && dep->fid.vnode != 0
4555              && !cm_Is8Dot3(dep->name)) {
4556             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4557             NeedShortName = 1;
4558         }
4559
4560         osi_Log4(smb_logp, "T2 search dir vn %u uniq %u name %s (%s)",
4561                   dep->fid.vnode, dep->fid.unique, 
4562                   osi_LogSaveString(smb_logp, dep->name),
4563                   NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4564
4565         /* When matching, we are using doing a case fold if we have a wildcard mask.
4566          * If we get a non-wildcard match, it's a lookup for a specific file. 
4567          */
4568         if (dep->fid.vnode != 0 && 
4569             (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4570              (NeedShortName &&
4571               smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4572
4573             /* Eliminate entries that don't match requested attributes */
4574             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
4575                  smb_IsDotFile(dep->name)) {
4576                 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4577                 goto nextEntry; /* no hidden files */
4578             }
4579             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
4580             {
4581                 /* We have already done the cm_TryBulkStat above */
4582                 fid.cell = scp->fid.cell;
4583                 fid.volume = scp->fid.volume;
4584                 fid.vnode = ntohl(dep->fid.vnode);
4585                 fid.unique = ntohl(dep->fid.unique);
4586                 fileType = cm_FindFileType(&fid);
4587                 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4588                  "has filetype %d", dep->name,
4589                  fileType);*/
4590                 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4591                     fileType == CM_SCACHETYPE_DFSLINK ||
4592                     fileType == CM_SCACHETYPE_INVALID)
4593                     osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4594                     goto nextEntry;
4595             }
4596
4597             /* finally check if this name will fit */
4598
4599             /* standard dir entry stuff */
4600             if (infoLevel < 0x101)
4601                 ohbytes = 23;   /* pre-NT */
4602             else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4603                 ohbytes = 12;   /* NT names only */
4604             else
4605                 ohbytes = 64;   /* NT */
4606
4607             if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO)
4608                 ohbytes += 26;  /* Short name & length */
4609
4610             if (searchFlags & 4) {
4611                 ohbytes += 4;   /* if resume key required */
4612             }   
4613
4614             if (infoLevel != SMB_INFO_STANDARD
4615                  && infoLevel != SMB_FIND_FILE_DIRECTORY_INFO
4616                  && infoLevel != SMB_FIND_FILE_NAMES_INFO)
4617                 ohbytes += 4;   /* EASIZE */
4618
4619             /* add header to name & term. null */
4620             orbytes = onbytes + ohbytes + 1;
4621
4622             /* now, we round up the record to a 4 byte alignment,
4623              * and we make sure that we have enough room here for
4624              * even the aligned version (so we don't have to worry
4625              * about an * overflow when we pad things out below).
4626              * That's the reason for the alignment arithmetic below.
4627              */
4628             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4629                 align = (4 - (orbytes & 3)) & 3;
4630             else
4631                 align = 0;
4632             if (orbytes + bytesInBuffer + align > maxReturnData) {
4633                 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4634                           maxReturnData);
4635                 break;
4636             }
4637
4638             /* this is one of the entries to use: it is not deleted
4639              * and it matches the star pattern we're looking for.
4640              * Put out the name, preceded by its length.
4641              */
4642             /* First zero everything else */
4643             memset(origOp, 0, ohbytes);
4644
4645             if (infoLevel <= SMB_FIND_FILE_DIRECTORY_INFO)
4646                 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4647             else if (infoLevel == SMB_FIND_FILE_NAMES_INFO)
4648                 *((u_long *)(op + 8)) = onbytes;
4649             else
4650                 *((u_long *)(op + 60)) = onbytes;
4651             strcpy(origOp+ohbytes, dep->name);
4652             if (smb_StoreAnsiFilenames)
4653                 CharToOem(origOp+ohbytes, origOp+ohbytes);
4654
4655             /* Short name if requested and needed */
4656             if (infoLevel == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
4657                 if (NeedShortName) {
4658                     strcpy(op + 70, shortName);
4659                     if (smb_StoreAnsiFilenames)
4660                         CharToOem(op + 70, op + 70);
4661                     *(op + 68) = (char)(shortNameEnd - shortName);
4662                 }
4663             }
4664
4665             /* now, adjust the # of entries copied */
4666             returnedNames++;
4667
4668             /* NextEntryOffset and FileIndex */
4669             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
4670                 int entryOffset = orbytes + align;
4671                 *((u_long *)op) = entryOffset;
4672                 *((u_long *)(op+4)) = nextEntryCookie;
4673             }
4674
4675             /* now we emit the attribute.  This is tricky, since
4676              * we need to really stat the file to find out what
4677              * type of entry we've got.  Right now, we're copying
4678              * out data from a buffer, while holding the scp
4679              * locked, so it isn't really convenient to stat
4680              * something now.  We'll put in a place holder
4681              * now, and make a second pass before returning this
4682              * to get the real attributes.  So, we just skip the
4683              * data for now, and adjust it later.  We allocate a
4684              * patch record to make it easy to find this point
4685              * later.  The replay will happen at a time when it is
4686              * safe to unlock the directory.
4687              */
4688             if (infoLevel != SMB_FIND_FILE_NAMES_INFO) {
4689                 curPatchp = malloc(sizeof(*curPatchp));
4690                 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4691                           &curPatchp->q);
4692                 curPatchp->dptr = op;
4693                 if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO)
4694                     curPatchp->dptr += 8;
4695
4696                 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4697                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4698                 }       
4699                 else    
4700                     curPatchp->flags = 0;
4701
4702                 curPatchp->fid.cell = scp->fid.cell;
4703                 curPatchp->fid.volume = scp->fid.volume;
4704                 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4705                 curPatchp->fid.unique = ntohl(dep->fid.unique);
4706
4707                 /* temp */
4708                 curPatchp->dep = dep;
4709             }   
4710
4711             if (searchFlags & 4)
4712                 /* put out resume key */
4713                 *((u_long *)origOp) = nextEntryCookie;
4714
4715             /* Adjust byte ptr and count */
4716             origOp += orbytes;  /* skip entire record */
4717             bytesInBuffer += orbytes;
4718
4719             /* and pad the record out */
4720             while (--align >= 0) {
4721                 *origOp++ = 0;
4722                 bytesInBuffer++;
4723             }
4724         }       /* if we're including this name */
4725         else if (!starPattern &&
4726                  !foundInexact &&
4727                  dep->fid.vnode != 0 &&
4728                  smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4729             /* We were looking for exact matches, but here's an inexact one*/
4730             foundInexact = 1;
4731         }
4732                 
4733       nextEntry:
4734         /* and adjust curOffset to be where the new cookie is */
4735         thyper.HighPart = 0;
4736         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4737         curOffset = LargeIntegerAdd(thyper, curOffset);
4738     } /* while copying data for dir listing */
4739
4740     /* If we didn't get a star pattern, we did an exact match during the first pass. 
4741      * If there were no exact matches found, we fail over to inexact matches by
4742      * marking the query as a star pattern (matches all case permutations), and
4743      * re-running the query. 
4744      */
4745     if (returnedNames == 0 && !starPattern && foundInexact) {
4746         osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4747         starPattern = 1;
4748         goto startsearch;
4749     }
4750
4751     /* release the mutex */
4752     lock_ReleaseMutex(&scp->mx);
4753     if (bufferp) 
4754         buf_Release(bufferp);
4755
4756     /* apply and free last set of patches; if not doing a star match, this
4757      * will be empty, but better safe (and freeing everything) than sorry.
4758      */
4759     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4760                               &req);
4761         
4762     /* now put out the final parameters */
4763     if (returnedNames == 0) 
4764         eos = 1;
4765     if (p->opcode == 1) {
4766         /* find first */
4767         outp->parmsp[0] = (unsigned short) dsp->cookie;
4768         outp->parmsp[1] = returnedNames;
4769         outp->parmsp[2] = eos;
4770         outp->parmsp[3] = 0;            /* nothing wrong with EAS */
4771         outp->parmsp[4] = 0;    
4772         /* don't need last name to continue
4773          * search, cookie is enough.  Normally,
4774          * this is the offset of the file name
4775          * of the last entry returned.
4776          */
4777         outp->totalParms = 10;  /* in bytes */
4778     }
4779     else {
4780         /* find next */
4781         outp->parmsp[0] = returnedNames;
4782         outp->parmsp[1] = eos;
4783         outp->parmsp[2] = 0;    /* EAS error */
4784         outp->parmsp[3] = 0;    /* last name, as above */
4785         outp->totalParms = 8;   /* in bytes */
4786     }   
4787
4788     /* return # of bytes in the buffer */
4789     outp->totalData = bytesInBuffer;
4790
4791     /* Return error code if unsuccessful on first request */
4792     if (code == 0 && p->opcode == 1 && returnedNames == 0)
4793         code = CM_ERROR_NOSUCHFILE;
4794
4795     osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4796              p->opcode, dsp->cookie, returnedNames, code);
4797
4798     /* if we're supposed to close the search after this request, or if
4799      * we're supposed to close the search if we're done, and we're done,
4800      * or if something went wrong, close the search.
4801      */
4802     /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4803     if ((searchFlags & 1) || (returnedNames == 0) || 
4804          ((searchFlags & 2) && eos) || code != 0)
4805         smb_DeleteDirSearch(dsp);
4806     if (code)
4807         smb_SendTran2Error(vcp, p, opx, code);
4808     else
4809         smb_SendTran2Packet(vcp, outp, opx);
4810
4811     smb_FreeTran2Packet(outp);
4812     smb_ReleaseDirSearch(dsp);
4813     cm_ReleaseSCache(scp);
4814     cm_ReleaseUser(userp);
4815     return 0;
4816 }
4817
4818 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4819 {
4820     int dirHandle;
4821     smb_dirSearch_t *dsp;
4822
4823     dirHandle = smb_GetSMBParm(inp, 0);
4824         
4825     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4826
4827     dsp = smb_FindDirSearch(dirHandle);
4828         
4829     if (!dsp)
4830         return CM_ERROR_BADFD;
4831         
4832     /* otherwise, we have an FD to destroy */
4833     smb_DeleteDirSearch(dsp);
4834     smb_ReleaseDirSearch(dsp);
4835         
4836     /* and return results */
4837     smb_SetSMBDataLength(outp, 0);
4838
4839     return 0;
4840 }
4841
4842 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4843 {
4844     smb_SetSMBDataLength(outp, 0);
4845     return 0;
4846 }
4847
4848 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4849 {
4850     char *pathp;
4851     long code = 0;
4852     cm_space_t *spacep;
4853     int excl;
4854     cm_user_t *userp;
4855     cm_scache_t *dscp;          /* dir we're dealing with */
4856     cm_scache_t *scp;           /* file we're creating */
4857     cm_attr_t setAttr;
4858     int initialModeBits;
4859     smb_fid_t *fidp;
4860     int attributes;
4861     char *lastNamep;
4862     afs_uint32 dosTime;
4863     int openFun;
4864     int trunc;
4865     int openMode;
4866     int extraInfo;
4867     int openAction;
4868     int parmSlot;                       /* which parm we're dealing with */
4869     char *tidPathp;
4870     cm_req_t req;
4871     int created = 0;
4872
4873     cm_InitReq(&req);
4874
4875     scp = NULL;
4876         
4877     extraInfo = (smb_GetSMBParm(inp, 2) & 1); /* return extra info */
4878     openFun = smb_GetSMBParm(inp, 8); /* open function */
4879     excl = ((openFun & 3) == 0);
4880     trunc = ((openFun & 3) == 2); /* truncate it */
4881     openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4882     openAction = 0;             /* tracks what we did */
4883
4884     attributes = smb_GetSMBParm(inp, 5);
4885     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4886
4887                                 /* compute initial mode bits based on read-only flag in attributes */
4888     initialModeBits = 0666;
4889     if (attributes & SMB_ATTR_READONLY) 
4890         initialModeBits &= ~0222;
4891         
4892     pathp = smb_GetSMBData(inp, NULL);
4893     if (smb_StoreAnsiFilenames)
4894         OemToChar(pathp,pathp);
4895
4896     spacep = inp->spacep;
4897     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4898
4899     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4900         /* special case magic file name for receiving IOCTL requests
4901          * (since IOCTL calls themselves aren't getting through).
4902          */
4903 #ifdef NOTSERVICE
4904         osi_Log0(smb_logp, "IOCTL Open");
4905 #endif
4906
4907         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4908         smb_SetupIoctlFid(fidp, spacep);
4909
4910         /* set inp->fid so that later read calls in same msg can find fid */
4911         inp->fid = fidp->fid;
4912         
4913         /* copy out remainder of the parms */
4914         parmSlot = 2;
4915         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4916         if (extraInfo) {
4917             smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4918             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* mod time */
4919             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4920             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* len */
4921             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4922             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4923             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4924             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4925         }   
4926         /* and the final "always present" stuff */
4927         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4928         /* next write out the "unique" ID */
4929         smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4930         smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4931         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4932         smb_SetSMBDataLength(outp, 0);
4933
4934         /* and clean up fid reference */
4935         smb_ReleaseFID(fidp);
4936         return 0;
4937     }
4938
4939 #ifdef DEBUG_VERBOSE
4940     {
4941         char *hexp, *asciip;
4942         asciip = (lastNamep ? lastNamep : pathp );
4943         hexp = osi_HexifyString(asciip);
4944         DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4945         free(hexp);
4946     }
4947 #endif
4948     userp = smb_GetUserFromVCP(vcp, inp);
4949
4950     dscp = NULL;
4951     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4952     if (code) {
4953         cm_ReleaseUser(userp);
4954         return CM_ERROR_NOSUCHPATH;
4955     }
4956     code = cm_NameI(cm_data.rootSCachep, pathp,
4957                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4958                     userp, tidPathp, &req, &scp);
4959
4960 #ifdef DFS_SUPPORT
4961     if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4962         cm_ReleaseSCache(scp);
4963         cm_ReleaseUser(userp);
4964         if ( WANTS_DFS_PATHNAMES(inp) )
4965             return CM_ERROR_PATH_NOT_COVERED;
4966         else
4967             return CM_ERROR_BADSHARENAME;
4968     }
4969 #endif /* DFS_SUPPORT */
4970
4971     if (code != 0) {
4972         code = cm_NameI(cm_data.rootSCachep, spacep->data,
4973                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4974                         userp, tidPathp, &req, &dscp);
4975         if (code) {
4976             cm_ReleaseUser(userp);
4977             return code;
4978         }
4979
4980 #ifdef DFS_SUPPORT
4981         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4982             cm_ReleaseSCache(dscp);
4983             cm_ReleaseUser(userp);
4984             if ( WANTS_DFS_PATHNAMES(inp) )
4985                 return CM_ERROR_PATH_NOT_COVERED;
4986             else
4987                 return CM_ERROR_BADSHARENAME;
4988         }
4989 #endif /* DFS_SUPPORT */
4990         /* otherwise, scp points to the parent directory.  Do a lookup,
4991          * and truncate the file if we find it, otherwise we create the
4992          * file.
4993          */
4994         if (!lastNamep) 
4995             lastNamep = pathp;
4996         else 
4997             lastNamep++;
4998         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4999                           &req, &scp);
5000         if (code && code != CM_ERROR_NOSUCHFILE) {
5001             cm_ReleaseSCache(dscp);
5002             cm_ReleaseUser(userp);
5003             return code;
5004         }
5005     }
5006         
5007     /* if we get here, if code is 0, the file exists and is represented by
5008      * scp.  Otherwise, we have to create it.  The dir may be represented
5009      * by dscp, or we may have found the file directly.  If code is non-zero,
5010      * scp is NULL.
5011      */
5012     if (code == 0) {
5013         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
5014         if (code) {
5015             if (dscp) cm_ReleaseSCache(dscp);
5016             cm_ReleaseSCache(scp);
5017             cm_ReleaseUser(userp);
5018             return code;
5019         }
5020
5021         if (excl) {
5022             /* oops, file shouldn't be there */
5023             if (dscp) 
5024                 cm_ReleaseSCache(dscp);
5025             cm_ReleaseSCache(scp);
5026             cm_ReleaseUser(userp);
5027             return CM_ERROR_EXISTS;
5028         }
5029
5030         if (trunc) {
5031             setAttr.mask = CM_ATTRMASK_LENGTH;
5032             setAttr.length.LowPart = 0;
5033             setAttr.length.HighPart = 0;
5034             code = cm_SetAttr(scp, &setAttr, userp, &req);
5035             openAction = 3;     /* truncated existing file */
5036         }
5037         else openAction = 1;    /* found existing file */
5038     }
5039     else if (!(openFun & SMB_ATTR_DIRECTORY)) {
5040         /* don't create if not found */
5041         if (dscp) cm_ReleaseSCache(dscp);
5042         cm_ReleaseUser(userp);
5043         return CM_ERROR_NOSUCHFILE;
5044     }
5045     else {
5046         osi_assert(dscp != NULL);
5047         osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
5048                  osi_LogSaveString(smb_logp, lastNamep));
5049         openAction = 2; /* created file */
5050         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5051         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5052         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5053                          &req);
5054         if (code == 0) {
5055             created = 1;
5056             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5057                 smb_NotifyChange(FILE_ACTION_ADDED,
5058                                  FILE_NOTIFY_CHANGE_FILE_NAME,
5059                                  dscp, lastNamep, NULL, TRUE);
5060         } else if (!excl && code == CM_ERROR_EXISTS) {
5061             /* not an exclusive create, and someone else tried
5062              * creating it already, then we open it anyway.  We
5063              * don't bother retrying after this, since if this next
5064              * fails, that means that the file was deleted after we
5065              * started this call.
5066              */
5067             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5068                              userp, &req, &scp);
5069             if (code == 0) {
5070                 if (trunc) {
5071                     setAttr.mask = CM_ATTRMASK_LENGTH;
5072                     setAttr.length.LowPart = 0;
5073                     setAttr.length.HighPart = 0;
5074                     code = cm_SetAttr(scp, &setAttr, userp, &req);
5075                 }   
5076             }   /* lookup succeeded */
5077         }
5078     }
5079         
5080     /* we don't need this any longer */
5081     if (dscp) 
5082         cm_ReleaseSCache(dscp);
5083
5084     if (code) {
5085         /* something went wrong creating or truncating the file */
5086         if (scp) 
5087             cm_ReleaseSCache(scp);
5088         cm_ReleaseUser(userp);
5089         return code;
5090     }
5091         
5092     /* make sure we're about to open a file */
5093     if (scp->fileType != CM_SCACHETYPE_FILE) {
5094         cm_ReleaseSCache(scp);
5095         cm_ReleaseUser(userp);
5096         return CM_ERROR_ISDIR;
5097     }
5098
5099     /* now all we have to do is open the file itself */
5100     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5101     osi_assert(fidp);
5102         
5103     cm_HoldUser(userp);
5104     lock_ObtainMutex(&fidp->mx);
5105     /* save a pointer to the vnode */
5106     fidp->scp = scp;
5107     /* also the user */
5108     fidp->userp = userp;
5109         
5110     /* compute open mode */
5111     if (openMode != 1) 
5112         fidp->flags |= SMB_FID_OPENREAD;
5113     if (openMode == 1 || openMode == 2)
5114         fidp->flags |= SMB_FID_OPENWRITE;
5115
5116     /* remember if the file was newly created */
5117     if (created)
5118         fidp->flags |= SMB_FID_CREATED;
5119
5120     lock_ReleaseMutex(&fidp->mx);
5121     smb_ReleaseFID(fidp);
5122         
5123     cm_Open(scp, 0, userp);
5124
5125     /* set inp->fid so that later read calls in same msg can find fid */
5126     inp->fid = fidp->fid;
5127         
5128     /* copy out remainder of the parms */
5129     parmSlot = 2;
5130     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5131     lock_ObtainMutex(&scp->mx);
5132     if (extraInfo) {
5133         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
5134         smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5135         smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
5136         smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
5137         smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
5138         smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
5139         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
5140         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
5141         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
5142     }
5143     /* and the final "always present" stuff */
5144     smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
5145     /* next write out the "unique" ID */
5146     smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
5147     smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
5148     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
5149     lock_ReleaseMutex(&scp->mx);
5150     smb_SetSMBDataLength(outp, 0);
5151
5152     osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
5153
5154     cm_ReleaseUser(userp);
5155     /* leave scp held since we put it in fidp->scp */
5156     return 0;
5157 }       
5158
5159 static void smb_GetLockParams(unsigned char LockType, 
5160                               char ** buf, 
5161                               unsigned int * ppid, 
5162                               LARGE_INTEGER * pOffset, 
5163                               LARGE_INTEGER * pLength)
5164 {
5165     if (LockType & LOCKING_ANDX_LARGE_FILES) {
5166         /* Large Files */
5167         *ppid = *((USHORT *) *buf);
5168         pOffset->HighPart = *((LONG *)(*buf + 4));
5169         pOffset->LowPart = *((DWORD *)(*buf + 8));
5170         pLength->HighPart = *((LONG *)(*buf + 12));
5171         pLength->LowPart = *((DWORD *)(*buf + 16));
5172         *buf += 20;
5173     }
5174     else {
5175         /* Not Large Files */
5176         *ppid = *((USHORT *) *buf);
5177         pOffset->HighPart = 0;
5178         pOffset->LowPart = *((DWORD *)(*buf + 2));
5179         pLength->HighPart = 0;
5180         pLength->LowPart = *((DWORD *)(*buf + 6));
5181         *buf += 10;
5182     }
5183 }
5184
5185 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5186 {
5187     cm_req_t req;
5188     cm_user_t *userp;
5189     unsigned short fid;
5190     smb_fid_t *fidp;
5191     cm_scache_t *scp;
5192     unsigned char LockType;
5193     unsigned short NumberOfUnlocks, NumberOfLocks;
5194     long Timeout;
5195     char *op;
5196     char *op_locks;
5197     LARGE_INTEGER LOffset, LLength;
5198     smb_waitingLockRequest_t *wlRequest = NULL;
5199     cm_file_lock_t *lockp;
5200     long code = 0;
5201     int i;
5202     cm_key_t key;
5203     unsigned int pid;
5204
5205     cm_InitReq(&req);
5206
5207     fid = smb_GetSMBParm(inp, 2);
5208     fid = smb_ChainFID(fid, inp);
5209
5210     fidp = smb_FindFID(vcp, fid, 0);
5211     if (!fidp)
5212         return CM_ERROR_BADFD;
5213     
5214     lock_ObtainMutex(&fidp->mx);
5215     if (fidp->flags & SMB_FID_IOCTL) {
5216         osi_Log0(smb_logp, "smb_ReceiveV3Locking BadFD");
5217         lock_ReleaseMutex(&fidp->mx);
5218         smb_ReleaseFID(fidp);
5219         return CM_ERROR_BADFD;
5220     }
5221     scp = fidp->scp;
5222     cm_HoldSCache(scp);
5223     lock_ReleaseMutex(&fidp->mx);
5224
5225     /* set inp->fid so that later read calls in same msg can find fid */
5226     inp->fid = fid;
5227
5228     userp = smb_GetUserFromVCP(vcp, inp);
5229
5230
5231     lock_ObtainMutex(&scp->mx);
5232     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5233                       CM_SCACHESYNC_NEEDCALLBACK
5234                          | CM_SCACHESYNC_GETSTATUS
5235                          | CM_SCACHESYNC_LOCK);
5236     if (code) {
5237         osi_Log1(smb_logp, "smb_ReceiveV3Locking SyncOp failure code 0x%x", code);
5238         goto doneSync;
5239     }
5240
5241     LockType = smb_GetSMBParm(inp, 3) & 0xff;
5242     Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
5243     NumberOfUnlocks = smb_GetSMBParm(inp, 6);
5244     NumberOfLocks = smb_GetSMBParm(inp, 7);
5245
5246     if ((LockType & LOCKING_ANDX_CANCEL_LOCK) ||
5247         (LockType & LOCKING_ANDX_CHANGE_LOCKTYPE)) {
5248
5249         /* We don't support these requests.  Apparently, we can safely
5250            not deal with them too. */
5251         osi_Log1(smb_logp, "smb_ReceiveV3Locking received unsupported request [%s]",
5252                  ((LockType & LOCKING_ANDX_CANCEL_LOCK)?
5253                   "LOCKING_ANDX_CANCEL_LOCK":
5254                   "LOCKING_ANDX_CHANGE_LOCKTYPE")); 
5255         /* No need to call osi_LogSaveString since these are string
5256            constants.*/
5257
5258         code = CM_ERROR_BADOP;
5259         goto done;
5260
5261     }
5262
5263     op = smb_GetSMBData(inp, NULL);
5264
5265     for (i=0; i<NumberOfUnlocks; i++) {
5266         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5267
5268         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5269
5270         code = cm_Unlock(scp, LockType, LOffset, LLength, key, userp, &req);
5271
5272         if (code) 
5273             goto done;
5274     }
5275
5276     op_locks = op;
5277
5278     for (i=0; i<NumberOfLocks; i++) {
5279         smb_GetLockParams(LockType, &op, &pid, &LOffset, &LLength);
5280
5281         key = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5282
5283         code = cm_Lock(scp, LockType, LOffset, LLength, key, (Timeout != 0),
5284                         userp, &req, &lockp);
5285
5286         if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
5287             smb_waitingLock_t * wLock;
5288
5289             /* Put on waiting list */
5290             if(wlRequest == NULL) {
5291                 int j;
5292                 char * opt;
5293                 cm_key_t tkey;
5294                 LARGE_INTEGER tOffset, tLength;
5295
5296                 wlRequest = malloc(sizeof(smb_waitingLockRequest_t));
5297
5298                 osi_assert(wlRequest != NULL);
5299
5300                 wlRequest->vcp = vcp;
5301                 smb_HoldVC(vcp);
5302                 wlRequest->scp = scp;
5303                 cm_HoldSCache(scp);
5304                 wlRequest->inp = smb_CopyPacket(inp);
5305                 wlRequest->outp = smb_CopyPacket(outp);
5306                 wlRequest->lockType = LockType;
5307                 wlRequest->timeRemaining = Timeout;
5308                 wlRequest->locks = NULL;
5309
5310                 /* The waiting lock request needs to have enough
5311                    information to undo all the locks in the request.
5312                    We do the following to store info about locks that
5313                    have already been granted.  Sure, we can get most
5314                    of the info from the packet, but the packet doesn't
5315                    hold the result of cm_Lock call.  In practice we
5316                    only receive packets with one or two locks, so we
5317                    are only wasting a few bytes here and there and
5318                    only for a limited period of time until the waiting
5319                    lock times out or is freed. */
5320
5321                 for(opt = op_locks, j=i; j > 0; j--) {
5322                     smb_GetLockParams(LockType, &opt, &pid, &tOffset, &tLength);
5323
5324                     tkey = cm_GenerateKey(vcp->vcID, pid, fidp->fid);
5325
5326                     wLock = malloc(sizeof(smb_waitingLock_t));
5327
5328                     osi_assert(wLock != NULL);
5329
5330                     wLock->key = tkey;
5331                     wLock->LOffset = tOffset;
5332                     wLock->LLength = tLength;
5333                     wLock->lockp = NULL;
5334                     wLock->state = SMB_WAITINGLOCKSTATE_DONE;
5335                     osi_QAdd((osi_queue_t **) &wlRequest->locks,
5336                              &wLock->q);
5337                 }
5338             }
5339
5340             wLock = malloc(sizeof(smb_waitingLock_t));
5341
5342             osi_assert(wLock != NULL);
5343
5344             wLock->key = key;
5345             wLock->LOffset = LOffset;
5346             wLock->LLength = LLength;
5347             wLock->lockp = lockp;
5348             wLock->state = SMB_WAITINGLOCKSTATE_WAITING;
5349             osi_QAdd((osi_queue_t **) &wlRequest->locks,
5350                      &wLock->q);
5351
5352             osi_Log1(smb_logp, "smb_ReceiveV3Locking WaitingLock created 0x%p",
5353                      wLock);
5354
5355             code = 0;
5356             continue;
5357         }
5358
5359         if (code) {
5360             osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Lock failure code 0x%x", code);
5361             break;
5362         }
5363     }
5364
5365     if (code) {
5366
5367         /* Since something went wrong with the lock number i, we now
5368            have to go ahead and release any locks acquired before the
5369            failure.  All locks before lock number i (of which there
5370            are i of them) have either been successful or are waiting.
5371            Either case requires calling cm_Unlock(). */
5372
5373         /* And purge the waiting lock */
5374         if(wlRequest != NULL) {
5375             smb_waitingLock_t * wl;
5376             smb_waitingLock_t * wlNext;
5377             long ul_code;
5378
5379             for(wl = wlRequest->locks; wl; wl = wlNext) {
5380
5381                 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
5382
5383                 ul_code = cm_Unlock(scp, LockType, wl->LOffset, wl->LLength, wl->key, userp, &req);
5384                 
5385                 if(ul_code != 0) {
5386                     osi_Log1(smb_logp, "smb_ReceiveV3Locking cm_Unlock returns code %d", ul_code);
5387                 } else {
5388                     osi_Log0(smb_logp, "smb_ReceiveV3Locking cm_Unlock successful");
5389                 }
5390
5391                 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
5392                 free(wl);
5393
5394             }
5395
5396             smb_ReleaseVC(wlRequest->vcp);
5397             cm_ReleaseSCache(wlRequest->scp);
5398             smb_FreePacket(wlRequest->inp);
5399             smb_FreePacket(wlRequest->outp);
5400
5401             free(wlRequest);
5402
5403             wlRequest = NULL;
5404         }
5405
5406     } else {
5407
5408         if (wlRequest != NULL) {
5409
5410             lock_ObtainWrite(&smb_globalLock);
5411             osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
5412                      &wlRequest->q);
5413             osi_Wakeup((LONG_PTR)&smb_allWaitingLocks);
5414             lock_ReleaseWrite(&smb_globalLock);
5415
5416             /* don't send reply immediately */
5417             outp->flags |= SMB_PACKETFLAG_NOSEND;
5418         }
5419
5420         smb_SetSMBDataLength(outp, 0);
5421     }
5422
5423   done:   
5424     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
5425
5426   doneSync:
5427     lock_ReleaseMutex(&scp->mx);
5428     cm_ReleaseSCache(scp);
5429     cm_ReleaseUser(userp);
5430     smb_ReleaseFID(fidp);
5431
5432     return code;
5433 }
5434
5435 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5436 {
5437     unsigned short fid;
5438     smb_fid_t *fidp;
5439     cm_scache_t *scp;
5440     long code = 0;
5441     afs_uint32 searchTime;
5442     cm_user_t *userp;
5443     cm_req_t req;
5444
5445     cm_InitReq(&req);
5446
5447     fid = smb_GetSMBParm(inp, 0);
5448     fid = smb_ChainFID(fid, inp);
5449         
5450     fidp = smb_FindFID(vcp, fid, 0);
5451     if (!fidp)
5452         return CM_ERROR_BADFD;
5453     
5454     lock_ObtainMutex(&fidp->mx);
5455     if (fidp->flags & SMB_FID_IOCTL) {
5456         lock_ReleaseMutex(&fidp->mx);
5457         smb_ReleaseFID(fidp);
5458         return CM_ERROR_BADFD;
5459     }
5460     scp = fidp->scp;
5461     cm_HoldSCache(scp);
5462     lock_ReleaseMutex(&fidp->mx);
5463         
5464     userp = smb_GetUserFromVCP(vcp, inp);
5465         
5466         
5467     /* otherwise, stat the file */
5468     lock_ObtainMutex(&scp->mx);
5469     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5470                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5471     if (code) 
5472         goto done;
5473
5474     /* decode times.  We need a search time, but the response to this
5475      * call provides the date first, not the time, as returned in the
5476      * searchTime variable.  So we take the high-order bits first.
5477      */
5478     smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
5479     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);       /* ctime */
5480     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
5481     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);       /* atime */
5482     smb_SetSMBParm(outp, 3, searchTime & 0xffff);
5483     smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);       /* mtime */
5484     smb_SetSMBParm(outp, 5, searchTime & 0xffff);
5485
5486     /* now handle file size and allocation size */
5487     smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);              /* file size */
5488     smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
5489     smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);              /* alloc size */
5490     smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
5491
5492     /* file attribute */
5493     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
5494         
5495     /* and finalize stuff */
5496     smb_SetSMBDataLength(outp, 0);
5497     code = 0;
5498
5499   done:
5500     lock_ReleaseMutex(&scp->mx);
5501     cm_ReleaseSCache(scp);
5502     cm_ReleaseUser(userp);
5503     smb_ReleaseFID(fidp);
5504     return code;
5505 }       
5506
5507 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5508 {
5509     unsigned short fid;
5510     smb_fid_t *fidp;
5511     cm_scache_t *scp;
5512     long code = 0;
5513     afs_uint32 searchTime;
5514     time_t unixTime;
5515     cm_user_t *userp;
5516     cm_attr_t attrs;
5517     cm_req_t req;
5518
5519     cm_InitReq(&req);
5520
5521     fid = smb_GetSMBParm(inp, 0);
5522     fid = smb_ChainFID(fid, inp);
5523         
5524     fidp = smb_FindFID(vcp, fid, 0);
5525     if (!fidp)
5526         return CM_ERROR_BADFD;
5527     
5528     lock_ObtainMutex(&fidp->mx);
5529     if (fidp->flags & SMB_FID_IOCTL) {
5530         lock_ReleaseMutex(&fidp->mx);
5531         smb_ReleaseFID(fidp);
5532         return CM_ERROR_BADFD;
5533     }
5534     scp = fidp->scp;
5535     cm_HoldSCache(scp);
5536     lock_ReleaseMutex(&fidp->mx);
5537         
5538     userp = smb_GetUserFromVCP(vcp, inp);
5539         
5540         
5541     /* now prepare to call cm_setattr.  This message only sets various times,
5542      * and AFS only implements mtime, and we'll set the mtime if that's
5543      * requested.  The others we'll ignore.
5544      */
5545     searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5546         
5547     if (searchTime != 0) {
5548         smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5549
5550         if ( unixTime != -1 ) {
5551             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5552             attrs.clientModTime = unixTime;
5553             code = cm_SetAttr(scp, &attrs, userp, &req);
5554
5555             osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5556         } else {
5557             osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5558         }
5559     }
5560     else 
5561         code = 0;
5562
5563     cm_ReleaseSCache(scp);
5564     cm_ReleaseUser(userp);
5565     smb_ReleaseFID(fidp);
5566     return code;
5567 }
5568
5569 long smb_ReceiveV3WriteX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5570 {
5571     osi_hyper_t offset;
5572     long count, written = 0, total_written = 0;
5573     unsigned short fd;
5574     unsigned pid;
5575     smb_fid_t *fidp;
5576     long code = 0;
5577     cm_user_t *userp;
5578     char *op;
5579     int inDataBlockCount;
5580
5581     fd = smb_GetSMBParm(inp, 2);
5582     count = smb_GetSMBParm(inp, 10);
5583
5584     offset.HighPart = 0;
5585     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5586
5587     if (*inp->wctp == 14) {
5588         /* we have a request with 64-bit file offsets */
5589 #ifdef AFS_LARGEFILES
5590         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
5591 #else
5592         if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
5593             /* uh oh */
5594             osi_Log0(smb_logp, "smb_ReceiveV3WriteX offset requires largefile support");
5595             /* we shouldn't have received this op if we didn't specify
5596                largefile support */
5597             return CM_ERROR_BADOP;
5598         }
5599 #endif
5600     }
5601
5602     op = inp->data + smb_GetSMBParm(inp, 11);
5603     inDataBlockCount = count;
5604
5605     osi_Log4(smb_logp, "smb_ReceiveV3WriteX fid %d, off 0x%x:%08x, size 0x%x",
5606              fd, offset.HighPart, offset.LowPart, count);
5607         
5608     fd = smb_ChainFID(fd, inp);
5609     fidp = smb_FindFID(vcp, fd, 0);
5610     if (!fidp)
5611         return CM_ERROR_BADFD;
5612         
5613     lock_ObtainMutex(&fidp->mx);
5614     if (fidp->flags & SMB_FID_IOCTL) {
5615         lock_ReleaseMutex(&fidp->mx);
5616         code = smb_IoctlV3Write(fidp, vcp, inp, outp);
5617         smb_ReleaseFID(fidp);
5618         return code;
5619     }
5620     lock_ReleaseMutex(&fidp->mx);
5621     userp = smb_GetUserFromVCP(vcp, inp);
5622
5623     /* special case: 0 bytes transferred means there is no data
5624        transferred.  A slight departure from SMB_COM_WRITE where this
5625        means that we are supposed to truncate the file at this
5626        position. */
5627
5628     {
5629         cm_key_t key;
5630         LARGE_INTEGER LOffset;
5631         LARGE_INTEGER LLength;
5632
5633         pid = ((smb_t *) inp)->pid;
5634         key = cm_GenerateKey(vcp->vcID, pid, fd);
5635
5636         LOffset.HighPart = offset.HighPart;
5637         LOffset.LowPart = offset.LowPart;
5638         LLength.HighPart = 0;
5639         LLength.LowPart = count;
5640
5641         lock_ObtainMutex(&fidp->scp->mx);
5642         code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
5643         lock_ReleaseMutex(&fidp->scp->mx);
5644
5645         if (code)
5646             goto done;
5647     }
5648
5649     /*
5650      * Work around bug in NT client
5651      *
5652      * When copying a file, the NT client should first copy the data,
5653      * then copy the last write time.  But sometimes the NT client does
5654      * these in the wrong order, so the data copies would inadvertently
5655      * cause the last write time to be overwritten.  We try to detect this,
5656      * and don't set client mod time if we think that would go against the
5657      * intention.
5658      */
5659     lock_ObtainMutex(&fidp->mx);
5660     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
5661         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5662         fidp->scp->clientModTime = time(NULL);
5663     }
5664     lock_ReleaseMutex(&fidp->mx);
5665
5666     code = 0;
5667     while ( code == 0 && count > 0 ) {
5668 #ifndef DJGPP
5669         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5670 #else /* DJGPP */
5671         code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5672 #endif /* !DJGPP */
5673         if (code == 0 && written == 0)
5674             code = CM_ERROR_PARTIALWRITE;
5675
5676         offset = LargeIntegerAdd(offset,
5677                                  ConvertLongToLargeInteger(written));
5678         count -= written;
5679         total_written += written;
5680         written = 0;
5681     }
5682
5683  done_writing:
5684     
5685     /* slots 0 and 1 are reserved for request chaining and will be
5686        filled in when we return. */
5687     smb_SetSMBParm(outp, 2, total_written);
5688     smb_SetSMBParm(outp, 3, 0); /* reserved */
5689     smb_SetSMBParm(outp, 4, 0); /* reserved */
5690     smb_SetSMBParm(outp, 5, 0); /* reserved */
5691     smb_SetSMBDataLength(outp, 0);
5692
5693  done:
5694     smb_ReleaseFID(fidp);
5695     cm_ReleaseUser(userp);
5696
5697     return code;
5698 }
5699
5700 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5701 {
5702     osi_hyper_t offset;
5703     long count;
5704     long finalCount = 0;
5705     unsigned short fd;
5706     unsigned pid;
5707     smb_fid_t *fidp;
5708     long code = 0;
5709     cm_user_t *userp;
5710     cm_key_t key;
5711     char *op;
5712         
5713     fd = smb_GetSMBParm(inp, 2);
5714     count = smb_GetSMBParm(inp, 5);
5715     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5716
5717     if (*inp->wctp == 12) {
5718         /* a request with 64-bit offsets */
5719 #ifdef AFS_LARGEFILES
5720         offset.HighPart = smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16);
5721
5722         if (LargeIntegerLessThanZero(offset)) {
5723             osi_Log2(smb_logp, "smb_ReceiveV3Read offset too large (0x%x:%08x)",
5724                      offset.HighPart, offset.LowPart);
5725             return CM_ERROR_BADSMB;
5726         }
5727 #else
5728         if ((smb_GetSMBParm(inp, 10) | (smb_GetSMBParm(inp, 11) << 16)) != 0) {
5729             osi_Log0(smb_logp, "smb_ReceiveV3Read offset is 64-bit.  Dropping");
5730             return CM_ERROR_BADSMB;
5731         } else {
5732             offset.HighPart = 0;
5733         }
5734 #endif
5735     } else {
5736         offset.HighPart = 0;
5737     }
5738
5739     osi_Log4(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x:%08x, size 0x%x",
5740              fd, offset.HighPart, offset.LowPart, count);
5741
5742     fd = smb_ChainFID(fd, inp);
5743     fidp = smb_FindFID(vcp, fd, 0);
5744     if (!fidp) {
5745         return CM_ERROR_BADFD;
5746     }
5747
5748     pid = ((smb_t *) inp)->pid;
5749     key = cm_GenerateKey(vcp->vcID, pid, fd);
5750     {
5751         LARGE_INTEGER LOffset, LLength;
5752
5753         LOffset.HighPart = offset.HighPart;
5754         LOffset.LowPart = offset.LowPart;
5755         LLength.HighPart = 0;
5756         LLength.LowPart = count;
5757
5758         lock_ObtainMutex(&fidp->scp->mx);
5759         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
5760         lock_ReleaseMutex(&fidp->scp->mx);
5761     }
5762
5763     if (code) {
5764         smb_ReleaseFID(fidp);
5765         return code;
5766     }
5767
5768     /* set inp->fid so that later read calls in same msg can find fid */
5769     inp->fid = fd;
5770
5771     lock_ObtainMutex(&fidp->mx);
5772     if (fidp->flags & SMB_FID_IOCTL) {
5773         lock_ReleaseMutex(&fidp->mx);
5774         code = smb_IoctlV3Read(fidp, vcp, inp, outp);
5775         smb_ReleaseFID(fidp);
5776         return code;
5777     }
5778     lock_ReleaseMutex(&fidp->mx);
5779
5780     userp = smb_GetUserFromVCP(vcp, inp);
5781
5782     /* 0 and 1 are reserved for request chaining, were setup by our caller,
5783      * and will be further filled in after we return.
5784      */
5785     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5786     smb_SetSMBParm(outp, 3, 0); /* resvd */
5787     smb_SetSMBParm(outp, 4, 0); /* resvd */
5788     smb_SetSMBParm(outp, 5, count);     /* # of bytes we're going to read */
5789     /* fill in #6 when we have all the parameters' space reserved */
5790     smb_SetSMBParm(outp, 7, 0); /* resv'd */
5791     smb_SetSMBParm(outp, 8, 0); /* resv'd */
5792     smb_SetSMBParm(outp, 9, 0); /* resv'd */
5793     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
5794     smb_SetSMBParm(outp, 11, 0);        /* reserved */
5795
5796     /* get op ptr after putting in the parms, since otherwise we don't
5797      * know where the data really is.
5798      */
5799     op = smb_GetSMBData(outp, NULL);
5800         
5801     /* now fill in offset from start of SMB header to first data byte (to op) */
5802     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5803
5804     /* set the packet data length the count of the # of bytes */
5805     smb_SetSMBDataLength(outp, count);
5806
5807 #ifndef DJGPP
5808     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5809 #else /* DJGPP */
5810     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5811 #endif /* !DJGPP */
5812
5813     /* fix some things up */
5814     smb_SetSMBParm(outp, 5, finalCount);
5815     smb_SetSMBDataLength(outp, finalCount);
5816
5817     smb_ReleaseFID(fidp);
5818
5819     cm_ReleaseUser(userp);
5820     return code;
5821 }   
5822         
5823 /*
5824  * Values for createDisp, copied from NTDDK.H
5825  */
5826 #define  FILE_SUPERSEDE 0       // (???)
5827 #define  FILE_OPEN      1       // (open)
5828 #define  FILE_CREATE    2       // (exclusive)
5829 #define  FILE_OPEN_IF   3       // (non-exclusive)
5830 #define  FILE_OVERWRITE 4       // (open & truncate, but do not create)
5831 #define  FILE_OVERWRITE_IF 5    // (open & truncate, or create)
5832
5833 /* Flags field */
5834 #define REQUEST_OPLOCK 2
5835 #define REQUEST_BATCH_OPLOCK 4
5836 #define OPEN_DIRECTORY 8
5837 #define EXTENDED_RESPONSE_REQUIRED 0x10
5838
5839 /* CreateOptions field. */
5840 #define FILE_DIRECTORY_FILE       0x0001
5841 #define FILE_WRITE_THROUGH        0x0002
5842 #define FILE_SEQUENTIAL_ONLY      0x0004
5843 #define FILE_NON_DIRECTORY_FILE   0x0040
5844 #define FILE_NO_EA_KNOWLEDGE      0x0200
5845 #define FILE_EIGHT_DOT_THREE_ONLY 0x0400
5846 #define FILE_RANDOM_ACCESS        0x0800
5847 #define FILE_DELETE_ON_CLOSE      0x1000
5848 #define FILE_OPEN_BY_FILE_ID      0x2000
5849
5850 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5851 {
5852     char *pathp, *realPathp;
5853     long code = 0;
5854     cm_space_t *spacep;
5855     cm_user_t *userp;
5856     cm_scache_t *dscp;          /* parent dir */
5857     cm_scache_t *scp;           /* file to create or open */
5858     cm_scache_t *targetScp;     /* if scp is a symlink */
5859     cm_attr_t setAttr;
5860     char *lastNamep;
5861     char *treeStartp;
5862     unsigned short nameLength;
5863     unsigned int flags;
5864     unsigned int requestOpLock;
5865     unsigned int requestBatchOpLock;
5866     unsigned int mustBeDir;
5867     unsigned int extendedRespRequired;
5868     unsigned int treeCreate;
5869     int realDirFlag;
5870     unsigned int desiredAccess;
5871     unsigned int extAttributes;
5872     unsigned int createDisp;
5873     unsigned int createOptions;
5874     unsigned int shareAccess;
5875     int initialModeBits;
5876     unsigned short baseFid;
5877     smb_fid_t *baseFidp;
5878     smb_fid_t *fidp;
5879     cm_scache_t *baseDirp;
5880     unsigned short openAction;
5881     int parmSlot;
5882     long fidflags;
5883     FILETIME ft;
5884     LARGE_INTEGER sz;
5885     char *tidPathp;
5886     BOOL foundscp;
5887     cm_req_t req;
5888     int created = 0;
5889
5890     cm_InitReq(&req);
5891
5892     /* This code is very long and has a lot of if-then-else clauses
5893      * scp and dscp get reused frequently and we need to ensure that 
5894      * we don't lose a reference.  Start by ensuring that they are NULL.
5895      */
5896     scp = NULL;
5897     dscp = NULL;
5898     treeCreate = FALSE;
5899     foundscp = FALSE;
5900
5901     nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5902     flags = smb_GetSMBOffsetParm(inp, 3, 1)
5903         | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5904     requestOpLock = flags & REQUEST_OPLOCK;
5905     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
5906     mustBeDir = flags & OPEN_DIRECTORY;
5907     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
5908
5909     /*
5910      * Why all of a sudden 32-bit FID?
5911      * We will reject all bits higher than 16.
5912      */
5913     if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5914         return CM_ERROR_INVAL;
5915     baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5916     desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5917         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5918     extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5919         | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5920     shareAccess = smb_GetSMBOffsetParm(inp, 15, 1)
5921         | (smb_GetSMBOffsetParm(inp, 16, 1) << 16);
5922     createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5923         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5924     createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5925         | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5926
5927     /* mustBeDir is never set; createOptions directory bit seems to be
5928      * more important
5929      */
5930     if (createOptions & FILE_DIRECTORY_FILE)
5931         realDirFlag = 1;
5932     else if (createOptions & FILE_NON_DIRECTORY_FILE)
5933         realDirFlag = 0;
5934     else
5935         realDirFlag = -1;
5936
5937     /*
5938      * compute initial mode bits based on read-only flag in
5939      * extended attributes
5940      */
5941     initialModeBits = 0666;
5942     if (extAttributes & SMB_ATTR_READONLY) 
5943         initialModeBits &= ~0222;
5944
5945     pathp = smb_GetSMBData(inp, NULL);
5946     /* Sometimes path is not null-terminated, so we make a copy. */
5947     realPathp = malloc(nameLength+1);
5948     memcpy(realPathp, pathp, nameLength);
5949     realPathp[nameLength] = 0;
5950     if (smb_StoreAnsiFilenames)
5951         OemToChar(realPathp,realPathp);
5952
5953     spacep = inp->spacep;
5954     smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5955
5956     osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5957     osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5958     osi_Log3(smb_logp,"... share=[%x] flags=[%x] lastNamep=[%s]", shareAccess, flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5959
5960     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5961         /* special case magic file name for receiving IOCTL requests
5962          * (since IOCTL calls themselves aren't getting through).
5963          */
5964         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5965         smb_SetupIoctlFid(fidp, spacep);
5966         osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5967
5968         /* set inp->fid so that later read calls in same msg can find fid */
5969         inp->fid = fidp->fid;
5970
5971         /* out parms */
5972         parmSlot = 2;
5973         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
5974         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5975         smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
5976         /* times */
5977         memset(&ft, 0, sizeof(ft));
5978         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5979         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5980         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5981         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5982         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
5983         sz.HighPart = 0x7fff; sz.LowPart = 0;
5984         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
5985         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
5986         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
5987         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
5988         smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
5989         smb_SetSMBDataLength(outp, 0);
5990
5991         /* clean up fid reference */
5992         smb_ReleaseFID(fidp);
5993         free(realPathp);
5994         return 0;
5995     }
5996
5997 #ifdef DEBUG_VERBOSE
5998     {
5999         char *hexp, *asciip;
6000         asciip = (lastNamep? lastNamep : realPathp);
6001         hexp = osi_HexifyString( asciip );
6002         DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
6003         free(hexp);
6004     }
6005 #endif
6006
6007     userp = smb_GetUserFromVCP(vcp, inp);
6008     if (!userp) {
6009         osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
6010         free(realPathp);
6011         return CM_ERROR_INVAL;
6012     }
6013
6014     if (baseFid == 0) {
6015         baseFidp = NULL;
6016         baseDirp = cm_data.rootSCachep;
6017         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6018         if (code == CM_ERROR_TIDIPC) {
6019             /* Attempt to use a TID allocated for IPC.  The client
6020              * is probably looking for DCE RPC end points which we
6021              * don't support OR it could be looking to make a DFS
6022              * referral request. 
6023              */
6024             osi_Log0(smb_logp, "NTCreateX received IPC TID");
6025 #ifndef DFS_SUPPORT
6026             free(realPathp);
6027             cm_ReleaseUser(userp);
6028             return CM_ERROR_NOSUCHFILE;
6029 #endif /* DFS_SUPPORT */
6030         }
6031     } else {
6032         baseFidp = smb_FindFID(vcp, baseFid, 0);
6033         if (!baseFidp) {
6034             osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
6035             free(realPathp);
6036             cm_ReleaseUser(userp);
6037             return CM_ERROR_INVAL;
6038         }       
6039         baseDirp = baseFidp->scp;
6040         tidPathp = NULL;
6041     }
6042
6043     osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
6044
6045     /* compute open mode */
6046     fidflags = 0;
6047     if (desiredAccess & DELETE)
6048         fidflags |= SMB_FID_OPENDELETE;
6049     if (desiredAccess & AFS_ACCESS_READ)
6050         fidflags |= SMB_FID_OPENREAD;
6051     if (desiredAccess & AFS_ACCESS_WRITE)
6052         fidflags |= SMB_FID_OPENWRITE;
6053     if (createOptions & FILE_DELETE_ON_CLOSE)
6054         fidflags |= SMB_FID_DELONCLOSE;
6055
6056     /* and the share mode */
6057     if (shareAccess & FILE_SHARE_READ)
6058         fidflags |= SMB_FID_SHARE_READ;
6059     if (shareAccess & FILE_SHARE_WRITE)
6060         fidflags |= SMB_FID_SHARE_WRITE;
6061
6062     osi_Log1(smb_logp, "NTCreateX fidflags 0x%x", fidflags);
6063     code = 0;
6064
6065     /* For an exclusive create, we want to do a case sensitive match for the last component. */
6066     if ( createDisp == FILE_CREATE || 
6067          createDisp == FILE_OVERWRITE ||
6068          createDisp == FILE_OVERWRITE_IF) {
6069         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6070                         userp, tidPathp, &req, &dscp);
6071         if (code == 0) {
6072 #ifdef DFS_SUPPORT
6073             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6074                 cm_ReleaseSCache(dscp);
6075                 cm_ReleaseUser(userp);
6076                 free(realPathp);
6077                 if (baseFidp) 
6078                     smb_ReleaseFID(baseFidp);
6079                 if ( WANTS_DFS_PATHNAMES(inp) )
6080                     return CM_ERROR_PATH_NOT_COVERED;
6081                 else
6082                     return CM_ERROR_BADSHARENAME;
6083             }
6084 #endif /* DFS_SUPPORT */
6085             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6086                              userp, &req, &scp);
6087             if (code == CM_ERROR_NOSUCHFILE) {
6088                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
6089                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6090                 if (code == 0 && realDirFlag == 1) {
6091                     cm_ReleaseSCache(scp);
6092                     cm_ReleaseSCache(dscp);
6093                     cm_ReleaseUser(userp);
6094                     free(realPathp);
6095                     if (baseFidp) 
6096                         smb_ReleaseFID(baseFidp);
6097                     return CM_ERROR_EXISTS;
6098                 }
6099             }
6100         }
6101         /* we have both scp and dscp */
6102     } else {
6103         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6104                         userp, tidPathp, &req, &scp);
6105 #ifdef DFS_SUPPORT
6106         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6107             cm_ReleaseSCache(scp);
6108             cm_ReleaseUser(userp);
6109             free(realPathp);
6110             if (baseFidp) 
6111                 smb_ReleaseFID(baseFidp);
6112             if ( WANTS_DFS_PATHNAMES(inp) )
6113                 return CM_ERROR_PATH_NOT_COVERED;
6114             else
6115                 return CM_ERROR_BADSHARENAME;
6116         }
6117 #endif /* DFS_SUPPORT */
6118         /* we might have scp but not dscp */
6119     }
6120
6121     if (scp)
6122         foundscp = TRUE;
6123     
6124     if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6125         /* look up parent directory */
6126         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
6127          * the immediate parent.  We have to work our way up realPathp until we hit something that we
6128          * recognize.
6129          */
6130
6131         /* we might or might not have scp */
6132
6133         if (dscp == NULL) {
6134             do {
6135                 char *tp;
6136
6137                 code = cm_NameI(baseDirp, spacep->data,
6138                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6139                              userp, tidPathp, &req, &dscp);
6140
6141 #ifdef DFS_SUPPORT
6142                 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6143                     if (scp)
6144                         cm_ReleaseSCache(scp);
6145                     cm_ReleaseSCache(dscp);
6146                     cm_ReleaseUser(userp);
6147                     free(realPathp);
6148                     if (baseFidp) 
6149                         smb_ReleaseFID(baseFidp);
6150                     if ( WANTS_DFS_PATHNAMES(inp) )
6151                         return CM_ERROR_PATH_NOT_COVERED;
6152                     else
6153                         return CM_ERROR_BADSHARENAME;
6154                 }
6155 #endif /* DFS_SUPPORT */
6156
6157                 if (code && 
6158                      (tp = strrchr(spacep->data,'\\')) &&
6159                      (createDisp == FILE_CREATE) &&
6160                      (realDirFlag == 1)) {
6161                     *tp++ = 0;
6162                     treeCreate = TRUE;
6163                     treeStartp = realPathp + (tp - spacep->data);
6164
6165                     if (*tp && !smb_IsLegalFilename(tp)) {
6166                         if (baseFidp) 
6167                             smb_ReleaseFID(baseFidp);
6168                         cm_ReleaseUser(userp);
6169                         free(realPathp);
6170                         if (scp)
6171                             cm_ReleaseSCache(scp);
6172                         return CM_ERROR_BADNTFILENAME;
6173                     }
6174                     code = 0;
6175                 }
6176             } while (dscp == NULL && code == 0);
6177         } else
6178             code = 0;
6179
6180         /* we might have scp and we might have dscp */
6181
6182         if (baseFidp)
6183             smb_ReleaseFID(baseFidp);
6184
6185         if (code) {
6186             osi_Log0(smb_logp,"NTCreateX parent not found");
6187             if (scp)
6188                 cm_ReleaseSCache(scp);
6189             if (dscp)
6190                 cm_ReleaseSCache(dscp);
6191             cm_ReleaseUser(userp);
6192             free(realPathp);
6193             return code;
6194         }
6195
6196         if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
6197             /* A file exists where we want a directory. */
6198             if (scp)
6199                 cm_ReleaseSCache(scp);
6200             cm_ReleaseSCache(dscp);
6201             cm_ReleaseUser(userp);
6202             free(realPathp);
6203             return CM_ERROR_EXISTS;
6204         }
6205
6206         if (!lastNamep) 
6207             lastNamep = realPathp;
6208         else 
6209             lastNamep++;
6210
6211         if (!smb_IsLegalFilename(lastNamep)) {
6212             if (scp)
6213                 cm_ReleaseSCache(scp);
6214             if (dscp)
6215                 cm_ReleaseSCache(dscp);
6216             cm_ReleaseUser(userp);
6217             free(realPathp);
6218             return CM_ERROR_BADNTFILENAME;
6219         }
6220
6221         if (!foundscp && !treeCreate) {
6222             if ( createDisp == FILE_CREATE || 
6223                  createDisp == FILE_OVERWRITE ||
6224                  createDisp == FILE_OVERWRITE_IF) 
6225             {
6226                 code = cm_Lookup(dscp, lastNamep,
6227                                   CM_FLAG_FOLLOW, userp, &req, &scp);
6228             } else {
6229                 code = cm_Lookup(dscp, lastNamep,
6230                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6231                                  userp, &req, &scp);
6232             }
6233             if (code && code != CM_ERROR_NOSUCHFILE) {
6234                 if (dscp)
6235                     cm_ReleaseSCache(dscp);
6236                 cm_ReleaseUser(userp);
6237                 free(realPathp);
6238                 return code;
6239             }
6240         }
6241         /* we have scp and dscp */
6242     } else {
6243         /* we have scp but not dscp */
6244         if (baseFidp)
6245             smb_ReleaseFID(baseFidp);
6246     }
6247
6248     /* if we get here, if code is 0, the file exists and is represented by
6249      * scp.  Otherwise, we have to create it.  The dir may be represented
6250      * by dscp, or we may have found the file directly.  If code is non-zero,
6251      * scp is NULL.
6252      */
6253     if (code == 0 && !treeCreate) {
6254         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
6255         if (code) {
6256             if (dscp)
6257                 cm_ReleaseSCache(dscp);
6258             if (scp)
6259                 cm_ReleaseSCache(scp);
6260             cm_ReleaseUser(userp);
6261             free(realPathp);
6262             return code;
6263         }
6264
6265         if (createDisp == FILE_CREATE) {
6266             /* oops, file shouldn't be there */
6267             if (dscp)
6268                 cm_ReleaseSCache(dscp);
6269             if (scp)
6270                 cm_ReleaseSCache(scp);
6271             cm_ReleaseUser(userp);
6272             free(realPathp);
6273             return CM_ERROR_EXISTS;
6274         }
6275
6276         if ( createDisp == FILE_OVERWRITE || 
6277              createDisp == FILE_OVERWRITE_IF) {
6278
6279             setAttr.mask = CM_ATTRMASK_LENGTH;
6280             setAttr.length.LowPart = 0;
6281             setAttr.length.HighPart = 0;
6282             /* now watch for a symlink */
6283             code = 0;
6284             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6285                 targetScp = 0;
6286                 osi_assert(dscp != NULL);
6287                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6288                 if (code == 0) {
6289                     /* we have a more accurate file to use (the
6290                      * target of the symbolic link).  Otherwise,
6291                      * we'll just use the symlink anyway.
6292                      */
6293                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
6294                               scp, targetScp);
6295                     cm_ReleaseSCache(scp);
6296                     scp = targetScp;
6297                 }
6298             }
6299             code = cm_SetAttr(scp, &setAttr, userp, &req);
6300             openAction = 3;     /* truncated existing file */
6301         }
6302         else 
6303             openAction = 1;     /* found existing file */
6304
6305     } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6306         /* don't create if not found */
6307         if (dscp)
6308             cm_ReleaseSCache(dscp);
6309         if (scp)
6310             cm_ReleaseSCache(scp);
6311         cm_ReleaseUser(userp);
6312         free(realPathp);
6313         return CM_ERROR_NOSUCHFILE;
6314     } else if (realDirFlag == 0 || realDirFlag == -1) {
6315         osi_assert(dscp != NULL);
6316         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
6317                   osi_LogSaveString(smb_logp, lastNamep));
6318         openAction = 2;         /* created file */
6319         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6320         setAttr.clientModTime = time(NULL);
6321         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
6322         if (code == 0) {
6323             created = 1;
6324             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6325                 smb_NotifyChange(FILE_ACTION_ADDED,
6326                                  FILE_NOTIFY_CHANGE_FILE_NAME,
6327                                  dscp, lastNamep, NULL, TRUE);
6328         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6329             /* Not an exclusive create, and someone else tried
6330              * creating it already, then we open it anyway.  We
6331              * don't bother retrying after this, since if this next
6332              * fails, that means that the file was deleted after we
6333              * started this call.
6334              */
6335             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6336                               userp, &req, &scp);
6337             if (code == 0) {
6338                 if (createDisp == FILE_OVERWRITE_IF) {
6339                     setAttr.mask = CM_ATTRMASK_LENGTH;
6340                     setAttr.length.LowPart = 0;
6341                     setAttr.length.HighPart = 0;
6342
6343                     /* now watch for a symlink */
6344                     code = 0;
6345                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6346                         targetScp = 0;
6347                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6348                         if (code == 0) {
6349                             /* we have a more accurate file to use (the
6350                              * target of the symbolic link).  Otherwise,
6351                              * we'll just use the symlink anyway.
6352                              */
6353                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
6354                                       scp, targetScp);
6355                             cm_ReleaseSCache(scp);
6356                             scp = targetScp;
6357                         }
6358                     }
6359                     code = cm_SetAttr(scp, &setAttr, userp, &req);
6360                 }
6361             }   /* lookup succeeded */
6362         }
6363     } else {
6364         char *tp, *pp;
6365         char *cp; /* This component */
6366         int clen = 0; /* length of component */
6367         cm_scache_t *tscp1, *tscp2;
6368         int isLast = 0;
6369
6370         /* create directory */
6371         if ( !treeCreate ) 
6372             treeStartp = lastNamep;
6373         osi_assert(dscp != NULL);
6374         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
6375                   osi_LogSaveString(smb_logp, treeStartp));
6376         openAction = 2;         /* created directory */
6377
6378         /* if the request is to create the root directory 
6379          * it will appear as a directory name of the nul-string
6380          * and a code of CM_ERROR_NOSUCHFILE
6381          */
6382         if ( !*treeStartp && code == CM_ERROR_NOSUCHFILE)
6383             code = CM_ERROR_EXISTS;
6384
6385         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6386         setAttr.clientModTime = time(NULL);
6387
6388         pp = treeStartp;
6389         cp = spacep->data;
6390         tscp1 = dscp;
6391         cm_HoldSCache(tscp1);
6392         tscp2 = NULL;
6393
6394         while (pp && *pp) {
6395             tp = strchr(pp, '\\');
6396             if (!tp) {
6397                 strcpy(cp,pp);
6398                 clen = (int)strlen(cp);
6399                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
6400             } else {
6401                 clen = (int)(tp - pp);
6402                 strncpy(cp,pp,clen);
6403                 *(cp + clen) = 0;
6404                 tp++;
6405             }
6406             pp = tp;
6407
6408             if (clen == 0) 
6409                 continue; /* the supplied path can't have consecutive slashes either , but */
6410
6411             /* cp is the next component to be created. */
6412             code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
6413             if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
6414                 smb_NotifyChange(FILE_ACTION_ADDED,
6415                                   FILE_NOTIFY_CHANGE_DIR_NAME,
6416                                   tscp1, cp, NULL, TRUE);
6417             if (code == 0 || 
6418                  (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6419                 /* Not an exclusive create, and someone else tried
6420                  * creating it already, then we open it anyway.  We
6421                  * don't bother retrying after this, since if this next
6422                  * fails, that means that the file was deleted after we
6423                  * started this call.
6424                  */
6425                 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
6426                                   userp, &req, &tscp2);
6427             }       
6428             if (code) 
6429                 break;
6430
6431             if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
6432                 cm_ReleaseSCache(tscp1);
6433                 tscp1 = tscp2; /* Newly created directory will be next parent */
6434                 /* the hold is transfered to tscp1 from tscp2 */
6435             }
6436         }
6437
6438         if (dscp)
6439             cm_ReleaseSCache(dscp);
6440         dscp = tscp1;
6441         if (scp)
6442             cm_ReleaseSCache(scp);
6443         scp = tscp2;
6444         /* 
6445          * if we get here and code == 0, then scp is the last directory created, and dscp is the
6446          * parent of scp.
6447          */
6448     }
6449
6450     if (code) {
6451         /* something went wrong creating or truncating the file */
6452         if (scp) 
6453             cm_ReleaseSCache(scp);
6454         if (dscp) 
6455             cm_ReleaseSCache(dscp);
6456         cm_ReleaseUser(userp);
6457         free(realPathp);
6458         return code;
6459     }
6460
6461     /* make sure we have file vs. dir right (only applies for single component case) */
6462     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6463         /* now watch for a symlink */
6464         code = 0;
6465         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6466             cm_scache_t * targetScp = 0;
6467             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6468             if (code == 0) {
6469                 /* we have a more accurate file to use (the
6470                 * target of the symbolic link).  Otherwise,
6471                 * we'll just use the symlink anyway.
6472                 */
6473                 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
6474                 cm_ReleaseSCache(scp);
6475                 scp = targetScp;
6476             }
6477         }
6478
6479         if (scp->fileType != CM_SCACHETYPE_FILE) {
6480             if (dscp)
6481                 cm_ReleaseSCache(dscp);
6482             cm_ReleaseSCache(scp);
6483             cm_ReleaseUser(userp);
6484             free(realPathp);
6485             return CM_ERROR_ISDIR;
6486         }
6487     }
6488
6489     /* (only applies to single component case) */
6490     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6491         cm_ReleaseSCache(scp);
6492         if (dscp)
6493             cm_ReleaseSCache(dscp);
6494         cm_ReleaseUser(userp);
6495         free(realPathp);
6496         return CM_ERROR_NOTDIR;
6497     }
6498
6499     /* open the file itself */
6500     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6501     osi_assert(fidp);
6502
6503     /* save a reference to the user */
6504     cm_HoldUser(userp);
6505     fidp->userp = userp;
6506
6507     /* If we are restricting sharing, we should do so with a suitable
6508        share lock. */
6509     if (scp->fileType == CM_SCACHETYPE_FILE &&
6510         !(fidflags & SMB_FID_SHARE_WRITE)) {
6511         cm_key_t key;
6512         LARGE_INTEGER LOffset, LLength;
6513         int sLockType;
6514
6515         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
6516         LOffset.LowPart = SMB_FID_QLOCK_LOW;
6517         LLength.HighPart = 0;
6518         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
6519
6520         if (fidflags & SMB_FID_SHARE_READ) {
6521             sLockType = LOCKING_ANDX_SHARED_LOCK;
6522         } else {
6523             sLockType = 0;
6524         }
6525
6526         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
6527         
6528         lock_ObtainMutex(&scp->mx);
6529         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
6530         lock_ReleaseMutex(&scp->mx);
6531
6532         if (code) {
6533             /* shouldn't this be smb_CloseFID() fidp->flags = SMB_FID_DELETE; */
6534             smb_CloseFID(vcp, fidp, NULL, 0);
6535             smb_ReleaseFID(fidp);
6536
6537             cm_ReleaseSCache(scp);
6538             if (dscp)
6539                 cm_ReleaseSCache(dscp);
6540             cm_ReleaseUser(userp);
6541             free(realPathp);
6542             
6543             return code;
6544         }
6545     }
6546
6547     lock_ObtainMutex(&fidp->mx);
6548     /* save a pointer to the vnode */
6549     fidp->scp = scp;    /* Hold transfered to fidp->scp and no longer needed */
6550
6551     fidp->flags = fidflags;
6552
6553     /* remember if the file was newly created */
6554     if (created)
6555         fidp->flags |= SMB_FID_CREATED;
6556
6557     /* save parent dir and pathname for delete or change notification */
6558     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6559         fidp->flags |= SMB_FID_NTOPEN;
6560         fidp->NTopen_dscp = dscp;
6561         cm_HoldSCache(dscp);
6562         fidp->NTopen_pathp = strdup(lastNamep);
6563     }
6564     fidp->NTopen_wholepathp = realPathp;
6565     lock_ReleaseMutex(&fidp->mx);
6566
6567     /* we don't need this any longer */
6568     if (dscp) {
6569         cm_ReleaseSCache(dscp);
6570         dscp = NULL;
6571     }
6572
6573     cm_Open(scp, 0, userp);
6574
6575     /* set inp->fid so that later read calls in same msg can find fid */
6576     inp->fid = fidp->fid;
6577
6578     /* out parms */
6579     parmSlot = 2;
6580     lock_ObtainMutex(&scp->mx);
6581     smb_SetSMBParmByte(outp, parmSlot, 0);      /* oplock */
6582     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
6583     smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
6584     smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6585     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6586     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6587     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6588     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
6589     smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
6590     parmSlot += 2;
6591     smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6592     smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
6593     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* filetype */
6594     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* dev state */
6595     smb_SetSMBParmByte(outp, parmSlot,
6596                         (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
6597                          scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
6598                          scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0); /* is a dir? */
6599     lock_ReleaseMutex(&scp->mx);
6600     smb_SetSMBDataLength(outp, 0);
6601
6602     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
6603               osi_LogSaveString(smb_logp, realPathp));
6604
6605     smb_ReleaseFID(fidp);
6606
6607     cm_ReleaseUser(userp);
6608
6609     /* Can't free realPathp if we get here since
6610        fidp->NTopen_wholepathp is pointing there */
6611
6612     /* leave scp held since we put it in fidp->scp */
6613     return 0;
6614 }       
6615
6616 /*
6617  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
6618  * Instead, ultimately, would like to use a subroutine for common code.
6619  */
6620 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6621 {
6622     char *pathp, *realPathp;
6623     long code = 0;
6624     cm_space_t *spacep;
6625     cm_user_t *userp;
6626     cm_scache_t *dscp;          /* parent dir */
6627     cm_scache_t *scp;           /* file to create or open */
6628     cm_scache_t *targetScp;     /* if scp is a symlink */
6629     cm_attr_t setAttr;
6630     char *lastNamep;
6631     unsigned long nameLength;
6632     unsigned int flags;
6633     unsigned int requestOpLock;
6634     unsigned int requestBatchOpLock;
6635     unsigned int mustBeDir;
6636     unsigned int extendedRespRequired;
6637     int realDirFlag;
6638     unsigned int desiredAccess;
6639 #ifdef DEBUG_VERBOSE    
6640     unsigned int allocSize;
6641 #endif
6642     unsigned int shareAccess;
6643     unsigned int extAttributes;
6644     unsigned int createDisp;
6645 #ifdef DEBUG_VERBOSE
6646     unsigned int sdLen;
6647 #endif
6648     unsigned int createOptions;
6649     int initialModeBits;
6650     unsigned short baseFid;
6651     smb_fid_t *baseFidp;
6652     smb_fid_t *fidp;
6653     cm_scache_t *baseDirp;
6654     unsigned short openAction;
6655     int parmSlot;
6656     long fidflags;
6657     FILETIME ft;
6658     char *tidPathp;
6659     BOOL foundscp;
6660     int parmOffset, dataOffset;
6661     char *parmp;
6662     ULONG *lparmp;
6663     char *outData;
6664     cm_req_t req;
6665     int created = 0;
6666
6667     cm_InitReq(&req);
6668
6669     foundscp = FALSE;
6670     scp = NULL;
6671
6672     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6673         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6674     parmp = inp->data + parmOffset;
6675     lparmp = (ULONG *) parmp;
6676
6677     flags = lparmp[0];
6678     requestOpLock = flags & REQUEST_OPLOCK;
6679     requestBatchOpLock = flags & REQUEST_BATCH_OPLOCK;
6680     mustBeDir = flags & OPEN_DIRECTORY;
6681     extendedRespRequired = flags & EXTENDED_RESPONSE_REQUIRED;
6682
6683     /*
6684      * Why all of a sudden 32-bit FID?
6685      * We will reject all bits higher than 16.
6686      */
6687     if (lparmp[1] & 0xFFFF0000)
6688         return CM_ERROR_INVAL;
6689     baseFid = (unsigned short)lparmp[1];
6690     desiredAccess = lparmp[2];
6691 #ifdef DEBUG_VERBOSE
6692     allocSize = lparmp[3];
6693 #endif /* DEBUG_VERSOSE */
6694     extAttributes = lparmp[5];
6695     shareAccess = lparmp[6];
6696     createDisp = lparmp[7];
6697     createOptions = lparmp[8];
6698 #ifdef DEBUG_VERBOSE
6699     sdLen = lparmp[9];
6700 #endif
6701     nameLength = lparmp[11];
6702
6703 #ifdef DEBUG_VERBOSE
6704     osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
6705     osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
6706     osi_Log1(smb_logp,"... flags[%x]",flags);
6707 #endif
6708
6709     /* mustBeDir is never set; createOptions directory bit seems to be
6710      * more important
6711      */
6712     if (createOptions & FILE_DIRECTORY_FILE)
6713         realDirFlag = 1;
6714     else if (createOptions & FILE_NON_DIRECTORY_FILE)
6715         realDirFlag = 0;
6716     else
6717         realDirFlag = -1;
6718
6719     /*
6720      * compute initial mode bits based on read-only flag in
6721      * extended attributes
6722      */
6723     initialModeBits = 0666;
6724     if (extAttributes & SMB_ATTR_READONLY) 
6725         initialModeBits &= ~0222;
6726
6727     pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
6728     /* Sometimes path is not null-terminated, so we make a copy. */
6729     realPathp = malloc(nameLength+1);
6730     memcpy(realPathp, pathp, nameLength);
6731     realPathp[nameLength] = 0;
6732     if (smb_StoreAnsiFilenames)
6733         OemToChar(realPathp,realPathp);
6734
6735     spacep = cm_GetSpace();
6736     smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
6737
6738     /*
6739      * Nothing here to handle SMB_IOCTL_FILENAME.
6740      * Will add it if necessary.
6741      */
6742
6743 #ifdef DEBUG_VERBOSE
6744     {
6745         char *hexp, *asciip;
6746         asciip = (lastNamep? lastNamep : realPathp);
6747         hexp = osi_HexifyString( asciip );
6748         DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
6749         free(hexp);
6750     }
6751 #endif
6752
6753     userp = smb_GetUserFromVCP(vcp, inp);
6754     if (!userp) {
6755         osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
6756         free(realPathp);
6757         return CM_ERROR_INVAL;
6758     }
6759
6760     if (baseFid == 0) {
6761         baseFidp = NULL;
6762         baseDirp = cm_data.rootSCachep;
6763         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6764         if (code == CM_ERROR_TIDIPC) {
6765             /* Attempt to use a TID allocated for IPC.  The client
6766              * is probably looking for DCE RPC end points which we
6767              * don't support OR it could be looking to make a DFS
6768              * referral request. 
6769              */
6770             osi_Log0(smb_logp, "NTTranCreate received IPC TID");
6771 #ifndef DFS_SUPPORT
6772             free(realPathp);
6773             cm_ReleaseUser(userp);
6774             return CM_ERROR_NOSUCHPATH;
6775 #endif 
6776         }
6777     } else {
6778         baseFidp = smb_FindFID(vcp, baseFid, 0);
6779         if (!baseFidp) {
6780             osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
6781             free(realPathp);
6782             cm_ReleaseUser(userp);
6783             return CM_ERROR_INVAL;
6784         }       
6785         baseDirp = baseFidp->scp;
6786         tidPathp = NULL;
6787     }
6788
6789     /* compute open mode */
6790     fidflags = 0;
6791     if (desiredAccess & DELETE)
6792         fidflags |= SMB_FID_OPENDELETE;
6793     if (desiredAccess & AFS_ACCESS_READ)
6794         fidflags |= SMB_FID_OPENREAD;
6795     if (desiredAccess & AFS_ACCESS_WRITE)
6796         fidflags |= SMB_FID_OPENWRITE;
6797     if (createOptions & FILE_DELETE_ON_CLOSE)
6798         fidflags |= SMB_FID_DELONCLOSE;
6799
6800     /* And the share mode */
6801     if (shareAccess & FILE_SHARE_READ)
6802         fidflags |= SMB_FID_SHARE_READ;
6803     if (shareAccess & FILE_SHARE_WRITE)
6804         fidflags |= SMB_FID_SHARE_WRITE;
6805
6806     dscp = NULL;
6807     code = 0;
6808     if ( createDisp == FILE_OPEN || 
6809          createDisp == FILE_OVERWRITE ||
6810          createDisp == FILE_OVERWRITE_IF) {
6811         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6812                         userp, tidPathp, &req, &dscp);
6813         if (code == 0) {
6814 #ifdef DFS_SUPPORT
6815             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6816                 cm_ReleaseSCache(dscp);
6817                 cm_ReleaseUser(userp);
6818                 free(realPathp);
6819                 if (baseFidp)
6820                     smb_ReleaseFID(baseFidp);
6821                 if ( WANTS_DFS_PATHNAMES(inp) )
6822                     return CM_ERROR_PATH_NOT_COVERED;
6823                 else
6824                     return CM_ERROR_BADSHARENAME;
6825             }
6826 #endif /* DFS_SUPPORT */
6827             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
6828                              userp, &req, &scp);
6829             if (code == CM_ERROR_NOSUCHFILE) {
6830                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
6831                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
6832                 if (code == 0 && realDirFlag == 1) {
6833                     cm_ReleaseSCache(scp);
6834                     cm_ReleaseSCache(dscp);
6835                     cm_ReleaseUser(userp);
6836                     free(realPathp);
6837                     if (baseFidp)
6838                         smb_ReleaseFID(baseFidp);
6839                     return CM_ERROR_EXISTS;
6840                 }
6841             }
6842         } else 
6843             dscp = NULL;
6844     } else {
6845         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6846                         userp, tidPathp, &req, &scp);
6847 #ifdef DFS_SUPPORT
6848         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6849             cm_ReleaseSCache(scp);
6850             cm_ReleaseUser(userp);
6851             free(realPathp);
6852             if (baseFidp)
6853                 smb_ReleaseFID(baseFidp);
6854             if ( WANTS_DFS_PATHNAMES(inp) )
6855                 return CM_ERROR_PATH_NOT_COVERED;
6856             else
6857                 return CM_ERROR_BADSHARENAME;
6858         }
6859 #endif /* DFS_SUPPORT */
6860     }
6861
6862     if (code == 0) 
6863         foundscp = TRUE;
6864
6865     if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6866         /* look up parent directory */
6867         if ( !dscp ) {
6868             code = cm_NameI(baseDirp, spacep->data,
6869                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6870                              userp, tidPathp, &req, &dscp);
6871 #ifdef DFS_SUPPORT
6872             if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6873                 cm_ReleaseSCache(dscp);
6874                 cm_ReleaseUser(userp);
6875                 free(realPathp);
6876                 if (baseFidp)
6877                     smb_ReleaseFID(baseFidp);
6878                 if ( WANTS_DFS_PATHNAMES(inp) )
6879                     return CM_ERROR_PATH_NOT_COVERED;
6880                 else
6881                     return CM_ERROR_BADSHARENAME;
6882             }
6883 #endif /* DFS_SUPPORT */
6884         } else
6885             code = 0;
6886         
6887         cm_FreeSpace(spacep);
6888
6889         if (baseFidp)
6890             smb_ReleaseFID(baseFidp);
6891
6892         if (code) {
6893             cm_ReleaseUser(userp);
6894             free(realPathp);
6895             return code;
6896         }
6897
6898         if (!lastNamep)
6899             lastNamep = realPathp;
6900         else 
6901             lastNamep++;
6902
6903         if (!smb_IsLegalFilename(lastNamep))
6904             return CM_ERROR_BADNTFILENAME;
6905
6906         if (!foundscp) {
6907             if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6908                 code = cm_Lookup(dscp, lastNamep,
6909                                   CM_FLAG_FOLLOW, userp, &req, &scp);
6910             } else {
6911                 code = cm_Lookup(dscp, lastNamep,
6912                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6913                                  userp, &req, &scp);
6914             }
6915             if (code && code != CM_ERROR_NOSUCHFILE) {
6916                 cm_ReleaseSCache(dscp);
6917                 cm_ReleaseUser(userp);
6918                 free(realPathp);
6919                 return code;
6920             }
6921         }
6922     } else {
6923         if (baseFidp)
6924             smb_ReleaseFID(baseFidp);
6925         cm_FreeSpace(spacep);
6926     }
6927
6928     /* if we get here, if code is 0, the file exists and is represented by
6929      * scp.  Otherwise, we have to create it.  The dir may be represented
6930      * by dscp, or we may have found the file directly.  If code is non-zero,
6931      * scp is NULL.
6932      */
6933     if (code == 0) {
6934         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6935                                &req);
6936         if (code) {     
6937             if (dscp) 
6938                 cm_ReleaseSCache(dscp);
6939             cm_ReleaseSCache(scp);
6940             cm_ReleaseUser(userp);
6941             free(realPathp);
6942             return code;
6943         }
6944
6945         if (createDisp == FILE_CREATE) {
6946             /* oops, file shouldn't be there */
6947             if (dscp) 
6948                 cm_ReleaseSCache(dscp);
6949             cm_ReleaseSCache(scp);
6950             cm_ReleaseUser(userp);
6951             free(realPathp);
6952             return CM_ERROR_EXISTS;
6953         }
6954
6955         if (createDisp == FILE_OVERWRITE ||
6956             createDisp == FILE_OVERWRITE_IF) {
6957             setAttr.mask = CM_ATTRMASK_LENGTH;
6958             setAttr.length.LowPart = 0;
6959             setAttr.length.HighPart = 0;
6960
6961             /* now watch for a symlink */
6962             code = 0;
6963             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6964                 targetScp = 0;
6965                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6966                 if (code == 0) {
6967                     /* we have a more accurate file to use (the
6968                     * target of the symbolic link).  Otherwise,
6969                     * we'll just use the symlink anyway.
6970                     */
6971                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
6972                               scp, targetScp);
6973                     cm_ReleaseSCache(scp);
6974                     scp = targetScp;
6975                 }
6976             }
6977             code = cm_SetAttr(scp, &setAttr, userp, &req);
6978             openAction = 3;     /* truncated existing file */
6979         }
6980         else openAction = 1;    /* found existing file */
6981     }
6982     else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6983         /* don't create if not found */
6984         if (dscp) 
6985             cm_ReleaseSCache(dscp);
6986         cm_ReleaseUser(userp);
6987         free(realPathp);
6988         return CM_ERROR_NOSUCHFILE;
6989     }
6990     else if (realDirFlag == 0 || realDirFlag == -1) {
6991         osi_assert(dscp != NULL);
6992         osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
6993                   osi_LogSaveString(smb_logp, lastNamep));
6994         openAction = 2;         /* created file */
6995         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6996         setAttr.clientModTime = time(NULL);
6997         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6998                           &req);
6999         if (code == 0) {
7000             created = 1;
7001             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7002                 smb_NotifyChange(FILE_ACTION_ADDED,
7003                                  FILE_NOTIFY_CHANGE_FILE_NAME,
7004                                  dscp, lastNamep, NULL, TRUE);
7005         } else if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
7006             /* Not an exclusive create, and someone else tried
7007              * creating it already, then we open it anyway.  We
7008              * don't bother retrying after this, since if this next
7009              * fails, that means that the file was deleted after we
7010              * started this call.
7011              */
7012             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7013                               userp, &req, &scp);
7014             if (code == 0) {
7015                 if (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                 }       
7038             }   /* lookup succeeded */
7039         }
7040     } else {
7041         /* create directory */
7042         osi_assert(dscp != NULL);
7043         osi_Log1(smb_logp,
7044                   "smb_ReceiveNTTranCreate creating directory %s",
7045                   osi_LogSaveString(smb_logp, lastNamep));
7046         openAction = 2;         /* created directory */
7047         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7048         setAttr.clientModTime = time(NULL);
7049         code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7050         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7051             smb_NotifyChange(FILE_ACTION_ADDED,
7052                               FILE_NOTIFY_CHANGE_DIR_NAME,
7053                               dscp, lastNamep, NULL, TRUE);
7054         if (code == 0 ||
7055             (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
7056             /* Not an exclusive create, and someone else tried
7057              * creating it already, then we open it anyway.  We
7058              * don't bother retrying after this, since if this next
7059              * fails, that means that the file was deleted after we
7060              * started this call.
7061              */
7062             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
7063                               userp, &req, &scp);
7064         }       
7065     }
7066
7067     if (code) {
7068         /* something went wrong creating or truncating the file */
7069         if (scp) 
7070             cm_ReleaseSCache(scp);
7071         cm_ReleaseUser(userp);
7072         free(realPathp);
7073         return code;
7074     }
7075
7076     /* make sure we have file vs. dir right */
7077     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
7078         /* now watch for a symlink */
7079         code = 0;
7080         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
7081             targetScp = 0;
7082             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
7083             if (code == 0) {
7084                 /* we have a more accurate file to use (the
7085                 * target of the symbolic link).  Otherwise,
7086                 * we'll just use the symlink anyway.
7087                 */
7088                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
7089                           scp, targetScp);
7090                 cm_ReleaseSCache(scp);
7091                 scp = targetScp;
7092             }
7093         }
7094
7095         if (scp->fileType != CM_SCACHETYPE_FILE) {
7096             cm_ReleaseSCache(scp);
7097             cm_ReleaseUser(userp);
7098             free(realPathp);
7099             return CM_ERROR_ISDIR;
7100         }
7101     }
7102
7103     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
7104         cm_ReleaseSCache(scp);
7105         cm_ReleaseUser(userp);
7106         free(realPathp);
7107         return CM_ERROR_NOTDIR;
7108     }
7109
7110     /* open the file itself */
7111     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7112     osi_assert(fidp);
7113
7114     /* save a reference to the user */
7115     cm_HoldUser(userp);
7116     fidp->userp = userp;
7117
7118     /* If we are restricting sharing, we should do so with a suitable
7119        share lock. */
7120     if (scp->fileType == CM_SCACHETYPE_FILE &&
7121         !(fidflags & SMB_FID_SHARE_WRITE)) {
7122         cm_key_t key;
7123         LARGE_INTEGER LOffset, LLength;
7124         int sLockType;
7125
7126         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
7127         LOffset.LowPart = SMB_FID_QLOCK_LOW;
7128         LLength.HighPart = 0;
7129         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
7130
7131         if (fidflags & SMB_FID_SHARE_READ) {
7132             sLockType = LOCKING_ANDX_SHARED_LOCK;
7133         } else {
7134             sLockType = 0;
7135         }
7136
7137         key = cm_GenerateKey(vcp->vcID, SMB_FID_QLOCK_PID, fidp->fid);
7138         
7139         lock_ObtainMutex(&scp->mx);
7140         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
7141         lock_ReleaseMutex(&scp->mx);
7142
7143         if (code) {
7144             /* Shouldn't this be smb_CloseFID()?  fidp->flags = SMB_FID_DELETE; */
7145             smb_CloseFID(vcp, fidp, NULL, 0);
7146             smb_ReleaseFID(fidp);
7147
7148             cm_ReleaseSCache(scp);
7149             cm_ReleaseUser(userp);
7150             free(realPathp);
7151             
7152             return CM_ERROR_SHARING_VIOLATION;
7153         }
7154     }
7155
7156     lock_ObtainMutex(&fidp->mx);
7157     /* save a pointer to the vnode */
7158     fidp->scp = scp;
7159
7160     fidp->flags = fidflags;
7161
7162     /* remember if the file was newly created */
7163     if (created)
7164         fidp->flags |= SMB_FID_CREATED;
7165
7166     /* save parent dir and pathname for deletion or change notification */
7167     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
7168         fidp->flags |= SMB_FID_NTOPEN;
7169         fidp->NTopen_dscp = dscp;
7170         cm_HoldSCache(dscp);
7171         fidp->NTopen_pathp = strdup(lastNamep);
7172     }
7173     fidp->NTopen_wholepathp = realPathp;
7174     lock_ReleaseMutex(&fidp->mx);
7175
7176     /* we don't need this any longer */
7177     if (dscp) 
7178         cm_ReleaseSCache(dscp);
7179
7180     cm_Open(scp, 0, userp);
7181
7182     /* set inp->fid so that later read calls in same msg can find fid */
7183     inp->fid = fidp->fid;
7184
7185     /* check whether we are required to send an extended response */
7186     if (!extendedRespRequired) {
7187         /* out parms */
7188         parmOffset = 8*4 + 39;
7189         parmOffset += 1;        /* pad to 4 */
7190         dataOffset = parmOffset + 70;
7191
7192         parmSlot = 1;
7193         outp->oddByte = 1;
7194         /* Total Parameter Count */
7195         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7196         /* Total Data Count */
7197         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7198         /* Parameter Count */
7199         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
7200         /* Parameter Offset */
7201         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7202         /* Parameter Displacement */
7203         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7204         /* Data Count */
7205         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7206         /* Data Offset */
7207         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7208         /* Data Displacement */
7209         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7210         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
7211         smb_SetSMBDataLength(outp, 70);
7212
7213         lock_ObtainMutex(&scp->mx);
7214         outData = smb_GetSMBData(outp, NULL);
7215         outData++;                      /* round to get to parmOffset */
7216         *outData = 0; outData++;        /* oplock */
7217         *outData = 0; outData++;        /* reserved */
7218         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7219         *((ULONG *)outData) = openAction; outData += 4;
7220         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
7221         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7222         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
7223         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
7224         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
7225         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
7226         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7227         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7228         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7229         *((USHORT *)outData) = 0; outData += 2; /* filetype */
7230         *((USHORT *)outData) = 0; outData += 2; /* dev state */
7231         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7232                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7233                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7234         outData += 2;   /* is a dir? */
7235         lock_ReleaseMutex(&scp->mx);
7236     } else {
7237         /* out parms */
7238         parmOffset = 8*4 + 39;
7239         parmOffset += 1;        /* pad to 4 */
7240         dataOffset = parmOffset + 104;
7241         
7242         parmSlot = 1;
7243         outp->oddByte = 1;
7244         /* Total Parameter Count */
7245         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7246         /* Total Data Count */
7247         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7248         /* Parameter Count */
7249         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
7250         /* Parameter Offset */
7251         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7252         /* Parameter Displacement */
7253         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7254         /* Data Count */
7255         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7256         /* Data Offset */
7257         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7258         /* Data Displacement */
7259         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7260         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
7261         smb_SetSMBDataLength(outp, 105);
7262         
7263         lock_ObtainMutex(&scp->mx);
7264         outData = smb_GetSMBData(outp, NULL);
7265         outData++;                      /* round to get to parmOffset */
7266         *outData = 0; outData++;        /* oplock */
7267         *outData = 1; outData++;        /* response type */
7268         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
7269         *((ULONG *)outData) = openAction; outData += 4;
7270         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
7271         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
7272         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
7273         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
7274         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
7275         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
7276         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
7277         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
7278         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
7279         *((USHORT *)outData) = 0; outData += 2; /* filetype */
7280         *((USHORT *)outData) = 0; outData += 2; /* dev state */
7281         *((USHORT *)outData) = ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
7282                                 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
7283                                 scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
7284         outData += 1;   /* is a dir? */
7285         memset(outData,0,24); outData += 24; /* Volume ID and file ID */
7286         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
7287         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
7288         lock_ReleaseMutex(&scp->mx);
7289     }
7290
7291     osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
7292
7293     smb_ReleaseFID(fidp);
7294
7295     cm_ReleaseUser(userp);
7296
7297     /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
7298     /* leave scp held since we put it in fidp->scp */
7299     return 0;
7300 }
7301
7302 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
7303         smb_packet_t *outp)
7304 {
7305     smb_packet_t *savedPacketp;
7306     ULONG filter; USHORT fid, watchtree;
7307     smb_fid_t *fidp;
7308     cm_scache_t *scp;
7309         
7310     filter = smb_GetSMBParm(inp, 19) |
7311              (smb_GetSMBParm(inp, 20) << 16);
7312     fid = smb_GetSMBParm(inp, 21);
7313     watchtree = smb_GetSMBParm(inp, 22) && 0xffff;  /* TODO: should this be 0xff ? */
7314
7315     fidp = smb_FindFID(vcp, fid, 0);
7316     if (!fidp) {
7317         osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
7318         return CM_ERROR_BADFD;
7319     }
7320
7321     savedPacketp = smb_CopyPacket(inp);
7322     smb_HoldVC(vcp);
7323     if (savedPacketp->vcp)
7324         smb_ReleaseVC(savedPacketp->vcp);
7325     savedPacketp->vcp = vcp;
7326     lock_ObtainMutex(&smb_Dir_Watch_Lock);
7327     savedPacketp->nextp = smb_Directory_Watches;
7328     smb_Directory_Watches = savedPacketp;
7329     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7330
7331     osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
7332              filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
7333
7334     scp = fidp->scp;
7335     lock_ObtainMutex(&scp->mx);
7336     if (watchtree)
7337         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
7338     else
7339         scp->flags |= CM_SCACHEFLAG_WATCHED;
7340     lock_ReleaseMutex(&scp->mx);
7341     smb_ReleaseFID(fidp);
7342
7343     outp->flags |= SMB_PACKETFLAG_NOSEND;
7344     return 0;
7345 }
7346
7347 unsigned char nullSecurityDesc[36] = {
7348     0x01,                               /* security descriptor revision */
7349     0x00,                               /* reserved, should be zero */
7350     0x00, 0x80,                         /* security descriptor control;
7351                                          * 0x8000 : self-relative format */
7352     0x14, 0x00, 0x00, 0x00,             /* offset of owner SID */
7353     0x1c, 0x00, 0x00, 0x00,             /* offset of group SID */
7354     0x00, 0x00, 0x00, 0x00,             /* offset of DACL would go here */
7355     0x00, 0x00, 0x00, 0x00,             /* offset of SACL would go here */
7356     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7357                                         /* "null SID" owner SID */
7358     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
7359                                         /* "null SID" group SID */
7360 };      
7361
7362 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7363 {
7364     int parmOffset, parmCount, dataOffset, dataCount;
7365     int parmSlot;
7366     int maxData;
7367     char *outData;
7368     char *parmp;
7369     USHORT *sparmp;
7370     ULONG *lparmp;
7371     USHORT fid;
7372     ULONG securityInformation;
7373
7374     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
7375         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
7376     parmp = inp->data + parmOffset;
7377     sparmp = (USHORT *) parmp;
7378     lparmp = (ULONG *) parmp;
7379
7380     fid = sparmp[0];
7381     securityInformation = lparmp[1];
7382
7383     maxData = smb_GetSMBOffsetParm(inp, 7, 1)
7384         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
7385
7386     if (maxData < 36)
7387         dataCount = 0;
7388     else
7389         dataCount = 36;
7390
7391     /* out parms */
7392     parmOffset = 8*4 + 39;
7393     parmOffset += 1;    /* pad to 4 */
7394     parmCount = 4;
7395     dataOffset = parmOffset + parmCount;
7396
7397     parmSlot = 1;
7398     outp->oddByte = 1;
7399     /* Total Parameter Count */
7400     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7401     /* Total Data Count */
7402     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7403     /* Parameter Count */
7404     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
7405     /* Parameter Offset */
7406     smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
7407     /* Parameter Displacement */
7408     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7409     /* Data Count */
7410     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
7411     /* Data Offset */
7412     smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
7413     /* Data Displacement */
7414     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
7415     smb_SetSMBParmByte(outp, parmSlot, 0);      /* Setup Count */
7416     smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
7417
7418     outData = smb_GetSMBData(outp, NULL);
7419     outData++;                  /* round to get to parmOffset */
7420     *((ULONG *)outData) = 36; outData += 4;     /* length */
7421
7422     if (maxData >= 36) {
7423         memcpy(outData, nullSecurityDesc, 36);
7424         outData += 36;
7425         return 0;
7426     } else
7427         return CM_ERROR_BUFFERTOOSMALL;
7428 }
7429
7430 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7431 {
7432     unsigned short function;
7433
7434     function = smb_GetSMBParm(inp, 18);
7435
7436     osi_Log1(smb_logp, "SMB NT Transact function %d", function);
7437
7438     /* We can handle long names */
7439     if (vcp->flags & SMB_VCFLAG_USENT)
7440         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
7441         
7442     switch (function) {
7443     case 1: 
7444         return smb_ReceiveNTTranCreate(vcp, inp, outp);
7445     case 2:
7446         osi_Log0(smb_logp, "SMB NT Transact Ioctl - not implemented");
7447         break;
7448     case 3:
7449         osi_Log0(smb_logp, "SMB NT Transact SetSecurityDesc - not implemented");
7450         break;
7451     case 4:
7452         return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
7453     case 5:
7454         osi_Log0(smb_logp, "SMB NT Transact Rename - not implemented");
7455         break;
7456     case 6:
7457         return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
7458     }
7459     return CM_ERROR_INVAL;
7460 }
7461
7462 /*
7463  * smb_NotifyChange -- find relevant change notification messages and
7464  *                     reply to them
7465  *
7466  * If we don't know the file name (i.e. a callback break), filename is
7467  * NULL, and we return a zero-length list.
7468  */
7469 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
7470         cm_scache_t *dscp, char *filename, char *otherFilename,
7471         BOOL isDirectParent)
7472 {
7473     smb_packet_t *watch, *lastWatch, *nextWatch;
7474     ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
7475     char *outData, *oldOutData;
7476     ULONG filter;
7477     USHORT fid, wtree;
7478     ULONG maxLen;
7479     BOOL twoEntries = FALSE;
7480     ULONG otherNameLen, oldParmCount = 0;
7481     DWORD otherAction;
7482     smb_fid_t *fidp;
7483
7484     /* Get ready for rename within directory */
7485     if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
7486         twoEntries = TRUE;
7487         otherAction = FILE_ACTION_RENAMED_NEW_NAME;
7488     }
7489
7490     osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
7491              osi_LogSaveString(smb_logp,filename),dscp);
7492
7493     lock_ObtainMutex(&smb_Dir_Watch_Lock);
7494     watch = smb_Directory_Watches;
7495     while (watch) {
7496         filter = smb_GetSMBParm(watch, 19)
7497             | (smb_GetSMBParm(watch, 20) << 16);
7498         fid = smb_GetSMBParm(watch, 21);
7499         wtree = smb_GetSMBParm(watch, 22) & 0xffff;  /* TODO: should this be 0xff ? */
7500         maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
7501             | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
7502
7503         /*
7504          * Strange hack - bug in NT Client and NT Server that we
7505          * must emulate?
7506          */
7507         if (filter == 3 && wtree)
7508             filter = 0x17;
7509
7510         fidp = smb_FindFID(watch->vcp, fid, 0);
7511         if (!fidp) {
7512             osi_Log1(smb_logp," no fidp for fid[%d]",fid);
7513             lastWatch = watch;
7514             watch = watch->nextp;
7515             continue;
7516         }       
7517         if (fidp->scp != dscp
7518              || (filter & notifyFilter) == 0
7519              || (!isDirectParent && !wtree)) {
7520             osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
7521             smb_ReleaseFID(fidp);
7522             lastWatch = watch;
7523             watch = watch->nextp;
7524             continue;
7525         }
7526         smb_ReleaseFID(fidp);
7527
7528         osi_Log4(smb_logp,
7529                   "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
7530                   fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
7531
7532         nextWatch = watch->nextp;
7533         if (watch == smb_Directory_Watches)
7534             smb_Directory_Watches = nextWatch;
7535         else
7536             lastWatch->nextp = nextWatch;
7537
7538         /* Turn off WATCHED flag in dscp */
7539         lock_ObtainMutex(&dscp->mx);
7540         if (wtree)
7541             dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7542         else
7543             dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
7544         lock_ReleaseMutex(&dscp->mx);
7545
7546         /* Convert to response packet */
7547         ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
7548         ((smb_t *) watch)->wct = 0;
7549
7550         /* out parms */
7551         if (filename == NULL)
7552             parmCount = 0;
7553         else {
7554             nameLen = (ULONG)strlen(filename);
7555             parmCount = 3*4 + nameLen*2;
7556             parmCount = (parmCount + 3) & ~3;   /* pad to 4 */
7557             if (twoEntries) {
7558                 otherNameLen = (ULONG)strlen(otherFilename);
7559                 oldParmCount = parmCount;
7560                 parmCount += 3*4 + otherNameLen*2;
7561                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
7562             }
7563             if (maxLen < parmCount)
7564                 parmCount = 0;  /* not enough room */
7565         }
7566         parmOffset = 8*4 + 39;
7567         parmOffset += 1;                        /* pad to 4 */
7568         dataOffset = parmOffset + parmCount;
7569
7570         parmSlot = 1;
7571         watch->oddByte = 1;
7572         /* Total Parameter Count */
7573         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7574         /* Total Data Count */
7575         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7576         /* Parameter Count */
7577         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
7578         /* Parameter Offset */
7579         smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
7580         /* Parameter Displacement */
7581         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7582         /* Data Count */
7583         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7584         /* Data Offset */
7585         smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
7586         /* Data Displacement */
7587         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
7588         smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
7589         smb_SetSMBDataLength(watch, parmCount + 1);
7590
7591         if (parmCount != 0) {
7592             char * p;
7593             outData = smb_GetSMBData(watch, NULL);
7594             outData++;  /* round to get to parmOffset */
7595             oldOutData = outData;
7596             *((DWORD *)outData) = oldParmCount; outData += 4;
7597             /* Next Entry Offset */
7598             *((DWORD *)outData) = action; outData += 4;
7599             /* Action */
7600             *((DWORD *)outData) = nameLen*2; outData += 4;
7601             /* File Name Length */
7602             p = strdup(filename);
7603             if (smb_StoreAnsiFilenames)
7604                 CharToOem(p,p);
7605             mbstowcs((WCHAR *)outData, p, nameLen);
7606             free(p);
7607             /* File Name */
7608             if (twoEntries) {
7609                 outData = oldOutData + oldParmCount;
7610                 *((DWORD *)outData) = 0; outData += 4;
7611                 /* Next Entry Offset */
7612                 *((DWORD *)outData) = otherAction; outData += 4;
7613                 /* Action */
7614                 *((DWORD *)outData) = otherNameLen*2;
7615                 outData += 4;   /* File Name Length */
7616                 p = strdup(otherFilename);
7617                 if (smb_StoreAnsiFilenames)
7618                     CharToOem(p,p);
7619                 mbstowcs((WCHAR *)outData, p, otherNameLen);    /* File Name */
7620                 free(p);
7621             }       
7622         }       
7623
7624         /*
7625          * If filename is null, we don't know the cause of the
7626          * change notification.  We return zero data (see above),
7627          * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
7628          * (= 0x010C).  We set the error code here by hand, without
7629          * modifying wct and bcc.
7630          */
7631         if (filename == NULL) {
7632             ((smb_t *) watch)->rcls = 0x0C;
7633             ((smb_t *) watch)->reh = 0x01;
7634             ((smb_t *) watch)->errLow = 0;
7635             ((smb_t *) watch)->errHigh = 0;
7636             /* Set NT Status codes flag */
7637             ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7638         }
7639
7640         smb_SendPacket(watch->vcp, watch);
7641         smb_FreePacket(watch);
7642         watch = nextWatch;
7643     }
7644     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7645 }       
7646
7647 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7648 {
7649     unsigned char *replyWctp;
7650     smb_packet_t *watch, *lastWatch;
7651     USHORT fid, watchtree;
7652     smb_fid_t *fidp;
7653     cm_scache_t *scp;
7654
7655     osi_Log0(smb_logp, "SMB3 receive NT cancel");
7656
7657     lock_ObtainMutex(&smb_Dir_Watch_Lock);
7658     watch = smb_Directory_Watches;
7659     while (watch) {
7660         if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
7661              && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
7662              && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
7663              && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
7664             if (watch == smb_Directory_Watches)
7665                 smb_Directory_Watches = watch->nextp;
7666             else
7667                 lastWatch->nextp = watch->nextp;
7668             lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7669
7670             /* Turn off WATCHED flag in scp */
7671             fid = smb_GetSMBParm(watch, 21);
7672             watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
7673
7674             if (vcp != watch->vcp)
7675                 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x", 
7676                           vcp, watch->vcp);
7677
7678             fidp = smb_FindFID(vcp, fid, 0);
7679             if (fidp) {
7680                 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s", 
7681                           fid, watchtree,
7682                           osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
7683
7684                 scp = fidp->scp;
7685                 lock_ObtainMutex(&scp->mx);
7686                 if (watchtree)
7687                     scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
7688                 else
7689                     scp->flags &= ~CM_SCACHEFLAG_WATCHED;
7690                 lock_ReleaseMutex(&scp->mx);
7691                 smb_ReleaseFID(fidp);
7692             } else {
7693                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
7694             }
7695
7696             /* assume STATUS32; return 0xC0000120 (CANCELED) */
7697             replyWctp = watch->wctp;
7698             *replyWctp++ = 0;
7699             *replyWctp++ = 0;
7700             *replyWctp++ = 0;
7701             ((smb_t *)watch)->rcls = 0x20;
7702             ((smb_t *)watch)->reh = 0x1;
7703             ((smb_t *)watch)->errLow = 0;
7704             ((smb_t *)watch)->errHigh = 0xC0;
7705             ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7706             smb_SendPacket(vcp, watch);
7707             smb_FreePacket(watch);
7708             return 0;
7709         }
7710         lastWatch = watch;
7711         watch = watch->nextp;
7712     }
7713     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
7714
7715     return 0;
7716 }
7717
7718 /*
7719  * NT rename also does hard links.
7720  */
7721
7722 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
7723 #define RENAME_FLAG_HARD_LINK                0x103
7724 #define RENAME_FLAG_RENAME                   0x104
7725 #define RENAME_FLAG_COPY                     0x105
7726
7727 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7728 {
7729     char *oldPathp, *newPathp;
7730     long code = 0;
7731     char * tp;
7732     int attrs;
7733     int rename_type;
7734
7735     attrs = smb_GetSMBParm(inp, 0);
7736     rename_type = smb_GetSMBParm(inp, 1);
7737
7738     if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
7739         osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
7740         return CM_ERROR_NOACCESS;
7741     }
7742
7743     tp = smb_GetSMBData(inp, NULL);
7744     oldPathp = smb_ParseASCIIBlock(tp, &tp);
7745     if (smb_StoreAnsiFilenames)
7746         OemToChar(oldPathp,oldPathp);
7747     newPathp = smb_ParseASCIIBlock(tp, &tp);
7748     if (smb_StoreAnsiFilenames)
7749         OemToChar(newPathp,newPathp);
7750
7751     osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
7752              osi_LogSaveString(smb_logp, oldPathp),
7753              osi_LogSaveString(smb_logp, newPathp),
7754              ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
7755
7756     if (rename_type == RENAME_FLAG_RENAME) {
7757         code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
7758     } else { /* RENAME_FLAG_HARD_LINK */
7759         code = smb_Link(vcp,inp,oldPathp,newPathp);
7760     }
7761     return code;
7762 }
7763
7764 void smb3_Init()
7765 {
7766     lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
7767 }
7768
7769 cm_user_t *smb_FindCMUserByName(char *usern, char *machine, afs_uint32 flags)
7770 {
7771     smb_username_t *unp;
7772     cm_user_t *     userp;
7773
7774     unp = smb_FindUserByName(usern, machine, flags);
7775     if (!unp->userp) {
7776         lock_ObtainMutex(&unp->mx);
7777         unp->userp = cm_NewUser();
7778         lock_ReleaseMutex(&unp->mx);
7779         osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7780     }  else     {
7781         osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
7782     }
7783     userp = unp->userp;
7784     cm_HoldUser(userp);
7785     smb_ReleaseUsername(unp);
7786     return userp;
7787 }
7788