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