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