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