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