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