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