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