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