4d436d152a8dee3fed11bbecaf3f930ef5b89262
[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     time_t 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     time_t 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,
3058                                              &lastMod);
3059             fidp->flags |= SMB_FID_MTIMESETDONE;
3060         }
3061                 
3062         attribute = *((u_long *)(p->datap + 32));
3063         if (attribute != 0) {
3064             if ((scp->unixModeBits & 0222)
3065                  && (attribute & 1) != 0) {
3066                 /* make a writable file read-only */
3067                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3068                 attr.unixModeBits = scp->unixModeBits & ~0222;
3069             }
3070             else if ((scp->unixModeBits & 0222) == 0
3071                       && (attribute & 1) == 0) {
3072                 /* make a read-only file writable */
3073                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3074                 attr.unixModeBits = scp->unixModeBits | 0222;
3075             }
3076         }
3077         lock_ReleaseMutex(&scp->mx);
3078
3079         /* call setattr */
3080         if (attr.mask)
3081             code = cm_SetAttr(scp, &attr, userp, &req);
3082         else
3083             code = 0;
3084     }               
3085     else if (infoLevel == SMB_QUERY_FILE_EA_INFO || infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3086         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3087         cm_attr_t attr;
3088
3089         attr.mask = CM_ATTRMASK_LENGTH;
3090         attr.length.LowPart = size.LowPart;
3091         attr.length.HighPart = size.HighPart;
3092         code = cm_SetAttr(scp, &attr, userp, &req);
3093     }       
3094     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3095         if (*((char *)(p->datap))) {
3096             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3097                                      &req);
3098             if (code == 0)          
3099                 fidp->flags |= SMB_FID_DELONCLOSE;
3100         }               
3101         else {  
3102             code = 0;
3103             fidp->flags &= ~SMB_FID_DELONCLOSE;
3104         }
3105     }       
3106
3107   done:
3108     cm_ReleaseUser(userp);
3109     smb_ReleaseFID(fidp);
3110     if (code == 0) 
3111         smb_SendTran2Packet(vcp, outp, op);
3112     else 
3113         smb_SendTran2Error(vcp, p, op, code);
3114     smb_FreeTran2Packet(outp);
3115
3116     return 0;
3117 }
3118
3119 long 
3120 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3121 {
3122     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3123     return CM_ERROR_BADOP;
3124 }
3125
3126 long 
3127 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3128 {
3129     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3130     return CM_ERROR_BADOP;
3131 }
3132
3133 long 
3134 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3135 {
3136     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3137     return CM_ERROR_BADOP;
3138 }
3139
3140 long 
3141 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3142 {
3143     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3144     return CM_ERROR_BADOP;
3145 }
3146
3147 long 
3148 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3149 {
3150     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3151     return CM_ERROR_BADOP;
3152 }
3153
3154 long 
3155 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3156 {
3157     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3158     return CM_ERROR_BADOP;
3159 }
3160
3161 struct smb_v2_referral {
3162     USHORT ServerType;
3163     USHORT ReferralFlags;
3164     ULONG  Proximity;
3165     ULONG  TimeToLive;
3166     USHORT DfsPathOffset;
3167     USHORT DfsAlternativePathOffset;
3168     USHORT NetworkAddressOffset;
3169 };
3170
3171 long 
3172 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3173 {
3174     /* This is a UNICODE only request (bit15 of Flags2) */
3175     /* The TID must be IPC$ */
3176
3177     /* The documentation for the Flags response field is contradictory */
3178
3179     /* Use Version 1 Referral Element Format */
3180     /* ServerType = 0; indicates the next server should be queried for the file */
3181     /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3182     /* Node = UnicodeString of UNC path of the next share name */
3183 #ifdef DFS_SUPPORT
3184     long code = 0;
3185     int maxReferralLevel = 0;
3186     char requestFileName[1024] = "";
3187     smb_tran2Packet_t *outp = 0;
3188     cm_user_t *userp = 0;
3189     cm_scache_t *scp;
3190     cm_req_t req;
3191     CPINFO CodePageInfo;
3192     int i, nbnLen, reqLen;
3193     int idx;
3194
3195     cm_InitReq(&req);
3196
3197     maxReferralLevel = p->parmsp[0];
3198
3199     GetCPInfo(CP_ACP, &CodePageInfo);
3200     WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1, 
3201                         requestFileName, 1024, NULL, NULL);
3202
3203     osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]", 
3204              maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3205
3206     nbnLen = strlen(cm_NetbiosName);
3207     reqLen = strlen(requestFileName);
3208
3209     if (reqLen == nbnLen + 5 &&
3210         requestFileName[0] == '\\' &&
3211         !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3212         requestFileName[nbnLen+1] == '\\' &&
3213         !_strnicmp("all",&requestFileName[nbnLen+2],3)) 
3214     {
3215         USHORT * sp;
3216         struct smb_v2_referral * v2ref;
3217         outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3218
3219         sp = (USHORT *)outp->datap;
3220         idx = 0;
3221         sp[idx++] = reqLen;   /* path consumed */
3222         sp[idx++] = 1;        /* number of referrals */
3223         sp[idx++] = 0x03;     /* flags */
3224 #ifdef DFS_VERSION_1
3225         sp[idx++] = 1;        /* Version Number */
3226         sp[idx++] = reqLen + 4;  /* Referral Size */ 
3227         sp[idx++] = 1;        /* Type = SMB Server */
3228         sp[idx++] = 0;        /* Do not strip path consumed */
3229         for ( i=0;i<=reqLen; i++ )
3230             sp[i+idx] = requestFileName[i];
3231 #else /* DFS_VERSION_2 */
3232         sp[idx++] = 2;      /* Version Number */
3233         sp[idx++] = sizeof(struct smb_v2_referral);     /* Referral Size */
3234         idx += (sizeof(struct smb_v2_referral) / 2);
3235         v2ref = (struct smb_v2_referral *) &sp[5];
3236         v2ref->ServerType = 1;  /* SMB Server */
3237         v2ref->ReferralFlags = 0x03;
3238         v2ref->Proximity = 0;   /* closest */
3239         v2ref->TimeToLive = 3600; /* seconds */
3240         v2ref->DfsPathOffset = idx * 2;
3241         v2ref->DfsAlternativePathOffset = idx * 2;
3242         v2ref->NetworkAddressOffset = 0;
3243         for ( i=0;i<=reqLen; i++ )
3244             sp[i+idx] = requestFileName[i];
3245 #endif
3246     } else {
3247         userp = smb_GetTran2User(vcp, p);
3248         if (!userp) {
3249             osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3250             code = CM_ERROR_BADSMB;
3251             goto done;
3252         }   
3253
3254                 /* not done yet */
3255         code = CM_ERROR_NOSUCHPATH;
3256     }
3257
3258   done:
3259     if (userp)
3260         cm_ReleaseUser(userp);
3261     if (code == 0) 
3262         smb_SendTran2Packet(vcp, outp, op);
3263     else 
3264         smb_SendTran2Error(vcp, p, op, code);
3265     if (outp)
3266         smb_FreeTran2Packet(outp);
3267  
3268     return 0;
3269 #else /* DFS_SUPPORT */
3270     osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED"); 
3271     return CM_ERROR_BADOP;
3272 #endif /* DFS_SUPPORT */
3273 }
3274
3275 long 
3276 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3277 {
3278     /* This is a UNICODE only request (bit15 of Flags2) */
3279
3280     /* There is nothing we can do about this operation.  The client is going to
3281      * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3282      * Unfortunately, there is really nothing we can do about it other then log it 
3283      * somewhere.  Even then I don't think there is anything for us to do.
3284      * So let's return an error value.
3285      */
3286
3287     osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3288     return CM_ERROR_BADOP;
3289 }
3290
3291 long 
3292 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3293         smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3294         cm_req_t *reqp)
3295 {
3296     long code = 0;
3297     cm_scache_t *scp;
3298     cm_scache_t *targetScp;                     /* target if scp is a symlink */
3299     char *dptr;
3300     time_t dosTime;
3301     FILETIME ft;
3302     int shortTemp;
3303     unsigned short attr;
3304     unsigned long lattr;
3305     smb_dirListPatch_t *patchp;
3306     smb_dirListPatch_t *npatchp;
3307         
3308     for(patchp = *dirPatchespp; patchp; patchp =
3309          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3310                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3311         if (code) continue;
3312         lock_ObtainMutex(&scp->mx);
3313         code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3314                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3315         if (code) { 
3316             lock_ReleaseMutex(&scp->mx);
3317             cm_ReleaseSCache(scp);
3318
3319             dptr = patchp->dptr;
3320
3321             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3322                errors in the client. */
3323             if (infoLevel >= 0x101) {
3324                 /* 1969-12-31 23:59:59 +00 */
3325                 ft.dwHighDateTime = 0x19DB200;
3326                 ft.dwLowDateTime = 0x5BB78980;
3327
3328                 /* copy to Creation Time */
3329                 *((FILETIME *)dptr) = ft;
3330                 dptr += 8;
3331
3332                 /* copy to Last Access Time */
3333                 *((FILETIME *)dptr) = ft;
3334                 dptr += 8;
3335
3336                 /* copy to Last Write Time */
3337                 *((FILETIME *)dptr) = ft;
3338                 dptr += 8;
3339
3340                 /* copy to Change Time */
3341                 *((FILETIME *)dptr) = ft;
3342                 dptr += 24;
3343
3344                 /* merge in hidden attribute */
3345                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3346                     *((u_long *)dptr) = SMB_ATTR_HIDDEN;
3347                 }
3348                 dptr += 4;
3349             } else {
3350                 /* 1969-12-31 23:59:58 +00*/
3351                 dosTime = 0xEBBFBF7D;
3352
3353                 /* and copy out date */
3354                 shortTemp = (dosTime>>16) & 0xffff;
3355                 *((u_short *)dptr) = shortTemp;
3356                 dptr += 2;
3357
3358                 /* copy out creation time */
3359                 shortTemp = dosTime & 0xffff;
3360                 *((u_short *)dptr) = shortTemp;
3361                 dptr += 2;
3362
3363                 /* and copy out date */
3364                 shortTemp = (dosTime>>16) & 0xffff;
3365                 *((u_short *)dptr) = shortTemp;
3366                 dptr += 2;
3367                         
3368                 /* copy out access time */
3369                 shortTemp = dosTime & 0xffff;
3370                 *((u_short *)dptr) = shortTemp;
3371                 dptr += 2;
3372
3373                 /* and copy out date */
3374                 shortTemp = (dosTime>>16) & 0xffff;
3375                 *((u_short *)dptr) = shortTemp;
3376                 dptr += 2;
3377                         
3378                 /* copy out mod time */
3379                 shortTemp = dosTime & 0xffff;
3380                 *((u_short *)dptr) = shortTemp;
3381                 dptr += 10;
3382
3383                 /* merge in hidden (dot file) attribute */
3384                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3385                     attr = SMB_ATTR_HIDDEN;
3386                     *dptr++ = attr & 0xff;
3387                     *dptr++ = (attr >> 8) & 0xff;
3388                 }       
3389             }
3390             continue;
3391         }
3392                 
3393         /* now watch for a symlink */
3394         code = 0;
3395         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3396             lock_ReleaseMutex(&scp->mx);
3397             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3398             if (code == 0) {
3399                 /* we have a more accurate file to use (the
3400                  * target of the symbolic link).  Otherwise,
3401                  * we'll just use the symlink anyway.
3402                  */
3403                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3404                           scp, targetScp);
3405                 cm_ReleaseSCache(scp);
3406                 scp = targetScp;
3407             }
3408             lock_ObtainMutex(&scp->mx);
3409         }
3410
3411         dptr = patchp->dptr;
3412
3413         if (infoLevel >= 0x101) {
3414             /* get filetime */
3415             smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3416
3417             /* copy to Creation Time */
3418             *((FILETIME *)dptr) = ft;
3419             dptr += 8;
3420
3421             /* copy to Last Access Time */
3422             *((FILETIME *)dptr) = ft;
3423             dptr += 8;
3424
3425             /* copy to Last Write Time */
3426             *((FILETIME *)dptr) = ft;
3427             dptr += 8;
3428
3429             /* copy to Change Time */
3430             *((FILETIME *)dptr) = ft;
3431             dptr += 8;
3432
3433             /* Use length for both file length and alloc length */
3434             *((LARGE_INTEGER *)dptr) = scp->length;
3435             dptr += 8;
3436             *((LARGE_INTEGER *)dptr) = scp->length;
3437             dptr += 8;
3438
3439             /* Copy attributes */
3440             lattr = smb_ExtAttributes(scp);
3441             if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3442                 if (lattr == SMB_ATTR_NORMAL)
3443                     lattr = SMB_ATTR_DIRECTORY;
3444                 else
3445                     lattr |= SMB_ATTR_DIRECTORY;
3446             }
3447             /* merge in hidden (dot file) attribute */
3448             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3449                 if (lattr == SMB_ATTR_NORMAL)
3450                     lattr = SMB_ATTR_HIDDEN;
3451                 else
3452                     lattr |= SMB_ATTR_HIDDEN;
3453             }
3454             *((u_long *)dptr) = lattr;
3455             dptr += 4;
3456         } else {
3457             /* get dos time */
3458             smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3459
3460             /* and copy out date */
3461             shortTemp = (dosTime>>16) & 0xffff;
3462             *((u_short *)dptr) = shortTemp;
3463             dptr += 2;
3464
3465             /* copy out creation time */
3466             shortTemp = dosTime & 0xffff;
3467             *((u_short *)dptr) = shortTemp;
3468             dptr += 2;
3469
3470             /* and copy out date */
3471             shortTemp = (dosTime>>16) & 0xffff;
3472             *((u_short *)dptr) = shortTemp;
3473             dptr += 2;
3474
3475             /* copy out access time */
3476             shortTemp = dosTime & 0xffff;
3477             *((u_short *)dptr) = shortTemp;
3478             dptr += 2;
3479
3480             /* and copy out date */
3481             shortTemp = (dosTime>>16) & 0xffff;
3482             *((u_short *)dptr) = shortTemp;
3483             dptr += 2;
3484
3485             /* copy out mod time */
3486             shortTemp = dosTime & 0xffff;
3487             *((u_short *)dptr) = shortTemp;
3488             dptr += 2;
3489
3490             /* copy out file length and alloc length,
3491              * using the same for both
3492              */
3493             *((u_long *)dptr) = scp->length.LowPart;
3494             dptr += 4;
3495             *((u_long *)dptr) = scp->length.LowPart;
3496             dptr += 4;
3497
3498             /* finally copy out attributes as short */
3499             attr = smb_Attributes(scp);
3500             /* merge in hidden (dot file) attribute */
3501             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3502                 if (lattr == SMB_ATTR_NORMAL)
3503                     lattr = SMB_ATTR_HIDDEN;
3504                 else
3505                     lattr |= SMB_ATTR_HIDDEN;
3506             }
3507             *dptr++ = attr & 0xff;
3508             *dptr++ = (attr >> 8) & 0xff;
3509         }
3510
3511         lock_ReleaseMutex(&scp->mx);
3512         cm_ReleaseSCache(scp);
3513     }
3514         
3515     /* now free the patches */
3516     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3517         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3518         free(patchp);
3519     }
3520         
3521     /* and mark the list as empty */
3522     *dirPatchespp = NULL;
3523
3524     return code;
3525 }
3526
3527 #ifndef USE_OLD_MATCHING
3528 // char table for case insensitive comparison
3529 char mapCaseTable[256];
3530
3531 VOID initUpperCaseTable(VOID) 
3532 {
3533     int i;
3534     for (i = 0; i < 256; ++i) 
3535        mapCaseTable[i] = toupper(i);
3536     // make '"' match '.' 
3537     mapCaseTable[(int)'"'] = toupper('.');
3538     // make '<' match '*' 
3539     mapCaseTable[(int)'<'] = toupper('*');
3540     // make '>' match '?' 
3541     mapCaseTable[(int)'>'] = toupper('?');    
3542 }
3543
3544 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3545 // name 'name'.
3546 // Note : this procedure works recursively calling itself.
3547 // Parameters
3548 // PSZ pattern    : string containing metacharacters.
3549 // PSZ name       : file name to be compared with 'pattern'.
3550 // Return value
3551 // BOOL : TRUE/FALSE (match/mistmatch)
3552
3553 BOOL 
3554 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold) 
3555 {
3556     PSZ pename;         // points to the last 'name' character
3557     PSZ p;
3558     pename = name + strlen(name) - 1;
3559     while (*name) {
3560         switch (*pattern) {
3561         case '?':
3562             if (*name == '.') 
3563                 return FALSE;
3564             ++pattern, ++name;
3565             break;
3566          case '*':
3567             ++pattern;
3568             if (*pattern == '\0')
3569                 return TRUE;
3570             for (p = pename; p >= name; --p) {
3571                 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3572                      !casefold && (*p == *pattern)) &&
3573                      szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3574                     return TRUE;
3575             } /* endfor */
3576             return FALSE;
3577         default:
3578             if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3579                 (!casefold && *name != *pattern))
3580                 return FALSE;
3581             ++pattern, ++name;
3582             break;
3583         } /* endswitch */
3584     } /* endwhile */ 
3585
3586     if (*pattern == '\0' || *pattern == '*' && *(pattern+1) == '\0')
3587         return TRUE;
3588     else 
3589         return FALSE;
3590 }
3591
3592 /* do a case-folding search of the star name mask with the name in namep.
3593  * Return 1 if we match, otherwise 0.
3594  */
3595 int smb_V3MatchMask(char *namep, char *maskp, int flags) 
3596 {
3597     char * newmask;
3598     int    i, j, star, qmark, casefold, retval;
3599
3600     /* make sure we only match 8.3 names, if requested */
3601     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
3602         return 0;
3603     
3604     casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3605
3606     /* optimize the pattern:
3607      * if there is a mixture of '?' and '*',
3608      * for example  the sequence "*?*?*?*"
3609      * must be turned into the form "*"
3610      */
3611     newmask = (char *)malloc(strlen(maskp)+1);
3612     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
3613         switch ( maskp[i] ) {
3614         case '?':
3615         case '>':
3616             qmark++;
3617             break;
3618         case '<':
3619         case '*':
3620             star++;
3621             break;
3622         default:
3623             if ( star ) {
3624                 newmask[j++] = '*';
3625             } else if ( qmark ) {
3626                 while ( qmark-- )
3627                     newmask[j++] = '?';
3628             }
3629             newmask[j++] = maskp[i];
3630             star = 0;
3631             qmark = 0;
3632         }
3633     }
3634     if ( star ) {
3635         newmask[j++] = '*';
3636     } else if ( qmark ) {
3637         while ( qmark-- )
3638             newmask[j++] = '?';
3639     }
3640     newmask[j++] = '\0';
3641
3642     retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
3643
3644     free(newmask);
3645     return retval;
3646 }
3647
3648 #else /* USE_OLD_MATCHING */
3649 /* do a case-folding search of the star name mask with the name in namep.
3650  * Return 1 if we match, otherwise 0.
3651  */
3652 int smb_V3MatchMask(char *namep, char *maskp, int flags)
3653 {
3654     unsigned char tcp1, tcp2;   /* Pattern characters */
3655     unsigned char tcn1;         /* Name characters */
3656     int sawDot = 0, sawStar = 0, req8dot3 = 0;
3657     char *starNamep, *starMaskp;
3658     static char nullCharp[] = {0};
3659     int casefold = flags & CM_FLAG_CASEFOLD;
3660
3661     /* make sure we only match 8.3 names, if requested */
3662     req8dot3 = (flags & CM_FLAG_8DOT3);
3663     if (req8dot3 && !cm_Is8Dot3(namep)) 
3664         return 0;
3665
3666     /* loop */
3667     while (1) {
3668         /* Next pattern character */
3669         tcp1 = *maskp++;
3670
3671         /* Next name character */
3672         tcn1 = *namep;
3673
3674         if (tcp1 == 0) {
3675             /* 0 - end of pattern */
3676             if (tcn1 == 0)
3677                 return 1;
3678             else
3679                 return 0;
3680         }
3681         else if (tcp1 == '.' || tcp1 == '"') {
3682             if (sawDot) {
3683                 if (tcn1 == '.') {
3684                     namep++;
3685                     continue;
3686                 } else
3687                     return 0;
3688             }
3689             else {
3690                 /*
3691                  * first dot in pattern;
3692                  * must match dot or end of name
3693                  */
3694                 sawDot = 1;
3695                 if (tcn1 == 0)
3696                     continue;
3697                 else if (tcn1 == '.') {
3698                     sawStar = 0;
3699                     namep++;
3700                     continue;
3701                 }
3702                 else
3703                     return 0;
3704             }
3705         }
3706         else if (tcp1 == '?') {
3707             if (tcn1 == 0 || tcn1 == '.')
3708                 return 0;
3709             namep++;
3710             continue;
3711         }
3712         else if (tcp1 == '>') {
3713             if (tcn1 != 0 && tcn1 != '.')
3714                 namep++;
3715             continue;
3716         }
3717         else if (tcp1 == '*' || tcp1 == '<') {
3718             tcp2 = *maskp++;
3719             if (tcp2 == 0)
3720                 return 1;
3721             else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
3722                 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
3723                     tcn1 = *++namep;
3724                 if (tcn1 == 0) {
3725                     if (sawDot)
3726                         return 0;
3727                     else
3728                         continue;
3729                 }
3730                 else {
3731                     namep++;
3732                     continue;
3733                 }
3734             }
3735             else {
3736                 /*
3737                  * pattern character after '*' is not null or
3738                  * period.  If it is '?' or '>', we are not
3739                  * going to understand it.  If it is '*' or
3740                  * '<', we are going to skip over it.  None of
3741                  * these are likely, I hope.
3742                  */
3743                 /* skip over '*' and '<' */
3744                 while (tcp2 == '*' || tcp2 == '<')
3745                     tcp2 = *maskp++;
3746
3747                 /* skip over characters that don't match tcp2 */
3748                 while (req8dot3 && tcn1 != '.' && tcn1 != 0 && 
3749                         ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
3750                           (!casefold && tcn1 != tcp2)))
3751                     tcn1 = *++namep;
3752
3753                 /* No match */
3754                 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
3755                     return 0;
3756
3757                 /* Remember where we are */
3758                 sawStar = 1;
3759                 starMaskp = maskp;
3760                 starNamep = namep;
3761
3762                 namep++;
3763                 continue;
3764             }
3765         }
3766         else {
3767             /* tcp1 is not a wildcard */
3768             if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
3769                  (!casefold && tcn1 == tcp1)) {
3770                 /* they match */
3771                 namep++;
3772                 continue;
3773             }
3774             /* if trying to match a star pattern, go back */
3775             if (sawStar) {
3776                 maskp = starMaskp - 2;
3777                 namep = starNamep + 1;
3778                 sawStar = 0;
3779                 continue;
3780             }
3781             /* that's all */
3782             return 0;
3783         }
3784     }
3785 }
3786 #endif /* USE_OLD_MATCHING */
3787
3788 long smb_ReceiveTran2SearchDir(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3789 {
3790     int attribute;
3791     long nextCookie;
3792     char *tp;
3793     long code = 0, code2 = 0;
3794     char *pathp;
3795     cm_dirEntry_t *dep;
3796     int maxCount;
3797     smb_dirListPatch_t *dirListPatchesp;
3798     smb_dirListPatch_t *curPatchp;
3799     cm_buf_t *bufferp;
3800     long temp;
3801     long orbytes;                       /* # of bytes in this output record */
3802     long ohbytes;                       /* # of bytes, except file name */
3803     long onbytes;                       /* # of bytes in name, incl. term. null */
3804     osi_hyper_t dirLength;
3805     osi_hyper_t bufferOffset;
3806     osi_hyper_t curOffset;
3807     osi_hyper_t thyper;
3808     smb_dirSearch_t *dsp;
3809     cm_scache_t *scp;
3810     long entryInDir;
3811     long entryInBuffer;
3812     cm_pageHeader_t *pageHeaderp;
3813     cm_user_t *userp = NULL;
3814     int slotInPage;
3815     int returnedNames;
3816     long nextEntryCookie;
3817     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
3818     char *op;                   /* output data ptr */
3819     char *origOp;                       /* original value of op */
3820     cm_space_t *spacep;         /* for pathname buffer */
3821     long maxReturnData;         /* max # of return data */
3822     long maxReturnParms;                /* max # of return parms */
3823     long bytesInBuffer;         /* # data bytes in the output buffer */
3824     int starPattern;
3825     char *maskp;                        /* mask part of path */
3826     int infoLevel;
3827     int searchFlags;
3828     int eos;
3829     smb_tran2Packet_t *outp;    /* response packet */
3830     char *tidPathp;
3831     int align;
3832     char shortName[13];         /* 8.3 name if needed */
3833     int NeedShortName;
3834     int foundInexact;
3835     char *shortNameEnd;
3836     int fileType;
3837     cm_fid_t fid;
3838     cm_req_t req;
3839
3840     cm_InitReq(&req);
3841
3842     eos = 0;
3843     if (p->opcode == 1) {
3844         /* find first; obtain basic parameters from request */
3845         attribute = p->parmsp[0];
3846         maxCount = p->parmsp[1];
3847         infoLevel = p->parmsp[3];
3848         searchFlags = p->parmsp[2];
3849         dsp = smb_NewDirSearch(1);
3850         dsp->attribute = attribute;
3851         pathp = ((char *) p->parmsp) + 12;      /* points to path */
3852         if (smb_StoreAnsiFilenames)
3853             OemToChar(pathp,pathp);
3854         nextCookie = 0;
3855         maskp = strrchr(pathp, '\\');
3856         if (maskp == NULL) 
3857             maskp = pathp;
3858         else 
3859             maskp++;    /* skip over backslash */
3860         strcpy(dsp->mask, maskp);       /* and save mask */
3861         /* track if this is likely to match a lot of entries */
3862         starPattern = smb_V3IsStarMask(maskp);
3863     }
3864     else {
3865         osi_assert(p->opcode == 2);
3866         /* find next; obtain basic parameters from request or open dir file */
3867         dsp = smb_FindDirSearch(p->parmsp[0]);
3868         maxCount = p->parmsp[1];
3869         infoLevel = p->parmsp[2];
3870         nextCookie = p->parmsp[3] | (p->parmsp[4] << 16);
3871         searchFlags = p->parmsp[5];
3872         if (!dsp) {
3873             osi_Log2(smb_logp, "T2 search dir bad search ID: id %d nextCookie 0x%x",
3874                      p->parmsp[0], nextCookie);
3875             return CM_ERROR_BADFD;
3876         }
3877         attribute = dsp->attribute;
3878         pathp = NULL;
3879         maskp = dsp->mask;
3880         starPattern = 1;        /* assume, since required a Find Next */
3881     }
3882
3883     osi_Log4(smb_logp,
3884               "T2 search dir attr 0x%x, info level %d, max count %d, flags 0x%x",
3885               attribute, infoLevel, maxCount, searchFlags);
3886
3887     osi_Log3(smb_logp, "...T2 search op %d, id %d, nextCookie 0x%x",
3888               p->opcode, dsp->cookie, nextCookie);
3889
3890     if (infoLevel >= 0x101)
3891         searchFlags &= ~4;      /* no resume keys */
3892
3893     dirListPatchesp = NULL;
3894
3895     maxReturnData = p->maxReturnData;
3896     if (p->opcode == 1) /* find first */
3897         maxReturnParms = 10;    /* bytes */
3898     else    
3899         maxReturnParms = 8;     /* bytes */
3900
3901 #ifndef CM_CONFIG_MULTITRAN2RESPONSES
3902     if (maxReturnData > 6000) 
3903         maxReturnData = 6000;
3904 #endif /* CM_CONFIG_MULTITRAN2RESPONSES */
3905
3906     outp = smb_GetTran2ResponsePacket(vcp, p, opx, maxReturnParms,
3907                                       maxReturnData);
3908
3909     osi_Log2(smb_logp, "T2 receive search dir count %d [%s]",
3910              maxCount, osi_LogSaveString(smb_logp, pathp));
3911         
3912     /* bail out if request looks bad */
3913     if (p->opcode == 1 && !pathp) {
3914         smb_ReleaseDirSearch(dsp);
3915         smb_FreeTran2Packet(outp);
3916         return CM_ERROR_BADSMB;
3917     }
3918         
3919     osi_Log3(smb_logp, "T2 search dir id %d, nextCookie 0x%x, attr 0x%x",
3920              dsp->cookie, nextCookie, attribute);
3921
3922     userp = smb_GetTran2User(vcp, p);
3923     if (!userp) {
3924         osi_Log1(smb_logp, "T2 search dir unable to resolve user [%d]", p->uid);
3925         smb_ReleaseDirSearch(dsp);
3926         smb_FreeTran2Packet(outp);
3927         return CM_ERROR_BADSMB;
3928     }
3929
3930     /* try to get the vnode for the path name next */
3931     lock_ObtainMutex(&dsp->mx);
3932     if (dsp->scp) {
3933         scp = dsp->scp;
3934         cm_HoldSCache(scp);
3935         code = 0;
3936     } else {
3937         spacep = cm_GetSpace();
3938         smb_StripLastComponent(spacep->data, NULL, pathp);
3939         code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3940         if (code) {
3941             cm_ReleaseUser(userp);
3942             smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOFILES);
3943             smb_FreeTran2Packet(outp);
3944             lock_ReleaseMutex(&dsp->mx);
3945             smb_DeleteDirSearch(dsp);
3946             smb_ReleaseDirSearch(dsp);
3947             return 0;
3948         }
3949         code = cm_NameI(cm_data.rootSCachep, spacep->data,
3950                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
3951                         userp, tidPathp, &req, &scp);
3952         cm_FreeSpace(spacep);
3953
3954         if (code == 0) {
3955 #ifdef DFS_SUPPORT_BUT_NOT_FIND_FIRST
3956             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3957                 cm_ReleaseSCache(scp);
3958                 cm_ReleaseUser(userp);
3959                 if ( WANTS_DFS_PATHNAMES(p) )
3960                     code = CM_ERROR_PATH_NOT_COVERED;
3961                 else
3962                     code = CM_ERROR_BADSHARENAME;
3963                 smb_SendTran2Error(vcp, p, opx, code);
3964                 smb_FreeTran2Packet(outp);
3965                 lock_ReleaseMutex(&dsp->mx);
3966                 smb_DeleteDirSearch(dsp);
3967                 smb_ReleaseDirSearch(dsp);
3968                 return 0;
3969             }
3970 #endif /* DFS_SUPPORT */
3971             dsp->scp = scp;
3972             /* we need one hold for the entry we just stored into,
3973              * and one for our own processing.  When we're done
3974              * with this function, we'll drop the one for our own
3975              * processing.  We held it once from the namei call,
3976              * and so we do another hold now.
3977              */
3978             cm_HoldSCache(scp);
3979             lock_ObtainMutex(&scp->mx);
3980             if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0 &&
3981                  LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3982                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3983                 dsp->flags |= SMB_DIRSEARCH_BULKST;
3984             }
3985             lock_ReleaseMutex(&scp->mx);
3986         } 
3987     }
3988     lock_ReleaseMutex(&dsp->mx);
3989     if (code) {
3990         cm_ReleaseUser(userp);
3991         smb_FreeTran2Packet(outp);
3992         smb_DeleteDirSearch(dsp);
3993         smb_ReleaseDirSearch(dsp);
3994         return code;
3995     }
3996
3997     /* get the directory size */
3998     lock_ObtainMutex(&scp->mx);
3999     code = cm_SyncOp(scp, NULL, userp, &req, 0,
4000                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4001     if (code) {
4002         lock_ReleaseMutex(&scp->mx);
4003         cm_ReleaseSCache(scp);
4004         cm_ReleaseUser(userp);
4005         smb_FreeTran2Packet(outp);
4006         smb_DeleteDirSearch(dsp);
4007         smb_ReleaseDirSearch(dsp);
4008         return code;
4009     }
4010
4011   startsearch:
4012     dirLength = scp->length;
4013     bufferp = NULL;
4014     bufferOffset.LowPart = bufferOffset.HighPart = 0;
4015     curOffset.HighPart = 0;
4016     curOffset.LowPart = nextCookie;
4017     origOp = outp->datap;
4018
4019     foundInexact = 0;
4020     code = 0;
4021     returnedNames = 0;
4022     bytesInBuffer = 0;
4023     while (1) {
4024         op = origOp;
4025         if (searchFlags & 4)
4026             /* skip over resume key */
4027             op += 4;
4028
4029         /* make sure that curOffset.LowPart doesn't point to the first
4030          * 32 bytes in the 2nd through last dir page, and that it doesn't
4031          * point at the first 13 32-byte chunks in the first dir page,
4032          * since those are dir and page headers, and don't contain useful
4033          * information.
4034          */
4035         temp = curOffset.LowPart & (2048-1);
4036         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4037             /* we're in the first page */
4038             if (temp < 13*32) temp = 13*32;
4039         }
4040         else {
4041             /* we're in a later dir page */
4042             if (temp < 32) temp = 32;
4043         }
4044                 
4045         /* make sure the low order 5 bits are zero */
4046         temp &= ~(32-1);
4047                 
4048         /* now put temp bits back ito curOffset.LowPart */
4049         curOffset.LowPart &= ~(2048-1);
4050         curOffset.LowPart |= temp;
4051
4052         /* check if we've passed the dir's EOF */
4053         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) {
4054             osi_Log0(smb_logp, "T2 search dir passed eof");
4055             eos = 1;
4056             break;
4057         }
4058
4059         /* check if we've returned all the names that will fit in the
4060          * response packet; we check return count as well as the number
4061          * of bytes requested.  We check the # of bytes after we find
4062          * the dir entry, since we'll need to check its size.
4063          */
4064         if (returnedNames >= maxCount) {
4065             osi_Log2(smb_logp, "T2 search dir returnedNames %d >= maxCount %d",
4066                       returnedNames, maxCount);
4067             break;
4068         }
4069
4070         /* see if we can use the bufferp we have now; compute in which
4071          * page the current offset would be, and check whether that's
4072          * the offset of the buffer we have.  If not, get the buffer.
4073          */
4074         thyper.HighPart = curOffset.HighPart;
4075         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4076         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4077             /* wrong buffer */
4078             if (bufferp) {
4079                 buf_Release(bufferp);
4080                 bufferp = NULL;
4081             }       
4082             lock_ReleaseMutex(&scp->mx);
4083             lock_ObtainRead(&scp->bufCreateLock);
4084             code = buf_Get(scp, &thyper, &bufferp);
4085             lock_ReleaseRead(&scp->bufCreateLock);
4086             lock_ObtainMutex(&dsp->mx);
4087
4088             /* now, if we're doing a star match, do bulk fetching
4089              * of all of the status info for files in the dir.
4090              */
4091             if (starPattern) {
4092                 smb_ApplyV3DirListPatches(scp, &dirListPatchesp,
4093                                            infoLevel, userp,
4094                                            &req);
4095                 lock_ObtainMutex(&scp->mx);
4096                 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4097                     LargeIntegerGreaterThanOrEqualTo(thyper, scp->bulkStatProgress)) {
4098                     /* Don't bulk stat if risking timeout */
4099                     int now = GetCurrentTime();
4100                     if (now - req.startTime > 5000) {
4101                         scp->bulkStatProgress = thyper;
4102                         scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4103                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4104                     } else
4105                         cm_TryBulkStat(scp, &thyper, userp, &req);
4106                 }
4107             } else {
4108                 lock_ObtainMutex(&scp->mx);
4109             }
4110             lock_ReleaseMutex(&dsp->mx);
4111             if (code) {
4112                 osi_Log2(smb_logp, "T2 search dir buf_Get scp %x failed %d", scp, code);
4113                 break;
4114             }
4115
4116             bufferOffset = thyper;
4117
4118             /* now get the data in the cache */
4119             while (1) {
4120                 code = cm_SyncOp(scp, bufferp, userp, &req,
4121                                  PRSFS_LOOKUP,
4122                                  CM_SCACHESYNC_NEEDCALLBACK
4123                                  | CM_SCACHESYNC_READ);
4124                 if (code) {
4125                     osi_Log2(smb_logp, "T2 search dir cm_SyncOp scp %x failed %d", scp, code);
4126                     break;
4127                 }
4128                                 
4129                 if (cm_HaveBuffer(scp, bufferp, 0)) {
4130                     osi_Log2(smb_logp, "T2 search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4131                     break;
4132                 }
4133
4134                 /* otherwise, load the buffer and try again */
4135                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4136                                     &req);
4137                 if (code) {
4138                     osi_Log3(smb_logp, "T2 search dir cm_GetBuffer failed scp %x bufferp %x code %d", 
4139                               scp, bufferp, code);
4140                     break;
4141                 }
4142             }
4143             if (code) {
4144                 buf_Release(bufferp);
4145                 bufferp = NULL;
4146                 break;
4147             }
4148         }       /* if (wrong buffer) ... */
4149                 
4150         /* now we have the buffer containing the entry we're interested
4151          * in; copy it out if it represents a non-deleted entry.
4152          */
4153         entryInDir = curOffset.LowPart & (2048-1);
4154         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4155
4156         /* page header will help tell us which entries are free.  Page
4157          * header can change more often than once per buffer, since
4158          * AFS 3 dir page size may be less than (but not more than)
4159          * a buffer package buffer.
4160          */
4161         /* only look intra-buffer */
4162         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4163         temp &= ~(2048 - 1);    /* turn off intra-page bits */
4164         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4165
4166         /* now determine which entry we're looking at in the page.
4167          * If it is free (there's a free bitmap at the start of the
4168          * dir), we should skip these 32 bytes.
4169          */
4170         slotInPage = (entryInDir & 0x7e0) >> 5;
4171         if (!(pageHeaderp->freeBitmap[slotInPage>>3] &
4172             (1 << (slotInPage & 0x7)))) {
4173             /* this entry is free */
4174             numDirChunks = 1;   /* only skip this guy */
4175             goto nextEntry;
4176         }
4177
4178         tp = bufferp->datap + entryInBuffer;
4179         dep = (cm_dirEntry_t *) tp;     /* now points to AFS3 dir entry */
4180
4181         /* while we're here, compute the next entry's location, too,
4182          * since we'll need it when writing out the cookie into the dir
4183          * listing stream.
4184          *
4185          * XXXX Probably should do more sanity checking.
4186          */
4187         numDirChunks = cm_NameEntries(dep->name, &onbytes);
4188                 
4189         /* compute offset of cookie representing next entry */
4190         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4191
4192         /* Need 8.3 name? */
4193         NeedShortName = 0;
4194         if (infoLevel == SMB_QUERY_FILE_NAME_INFO
4195              && dep->fid.vnode != 0
4196              && !cm_Is8Dot3(dep->name)) {
4197             cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4198             NeedShortName = 1;
4199         }
4200
4201         osi_Log3(smb_logp, "T2 search dir vn %u name %s (%s)",
4202                   dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4203                   NeedShortName ? osi_LogSaveString(smb_logp, shortName) : "");
4204
4205         /* When matching, we are using doing a case fold if we have a wildcard mask.
4206          * If we get a non-wildcard match, it's a lookup for a specific file. 
4207          */
4208         if (dep->fid.vnode != 0 && 
4209             (smb_V3MatchMask(dep->name, maskp, (starPattern? CM_FLAG_CASEFOLD : 0)) ||
4210              (NeedShortName &&
4211               smb_V3MatchMask(shortName, maskp, CM_FLAG_CASEFOLD)))) {
4212
4213             /* Eliminate entries that don't match requested attributes */
4214             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && 
4215                  smb_IsDotFile(dep->name)) {
4216                 osi_Log0(smb_logp, "T2 search dir skipping hidden");
4217                 goto nextEntry; /* no hidden files */
4218             }
4219             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
4220             {
4221                 /* We have already done the cm_TryBulkStat above */
4222                 fid.cell = scp->fid.cell;
4223                 fid.volume = scp->fid.volume;
4224                 fid.vnode = ntohl(dep->fid.vnode);
4225                 fid.unique = ntohl(dep->fid.unique);
4226                 fileType = cm_FindFileType(&fid);
4227                 /*osi_Log2(smb_logp, "smb_ReceiveTran2SearchDir: file %s "
4228                  "has filetype %d", dep->name,
4229                  fileType);*/
4230                 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4231                     fileType == CM_SCACHETYPE_DFSLINK ||
4232                     fileType == CM_SCACHETYPE_INVALID)
4233                     osi_Log0(smb_logp, "T2 search dir skipping directory or bad link");
4234                     goto nextEntry;
4235             }
4236
4237             /* finally check if this name will fit */
4238
4239             /* standard dir entry stuff */
4240             if (infoLevel < 0x101)
4241                 ohbytes = 23;   /* pre-NT */
4242             else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4243                 ohbytes = 12;   /* NT names only */
4244             else
4245                 ohbytes = 64;   /* NT */
4246
4247             if (infoLevel == SMB_QUERY_FILE_NAME_INFO)
4248                 ohbytes += 26;  /* Short name & length */
4249
4250             if (searchFlags & 4) {
4251                 ohbytes += 4;   /* if resume key required */
4252             }   
4253
4254             if (infoLevel != 1
4255                  && infoLevel != 0x101
4256                  && infoLevel != 0x103)
4257                 ohbytes += 4;   /* EASIZE */
4258
4259             /* add header to name & term. null */
4260             orbytes = onbytes + ohbytes + 1;
4261
4262             /* now, we round up the record to a 4 byte alignment,
4263              * and we make sure that we have enough room here for
4264              * even the aligned version (so we don't have to worry
4265              * about an * overflow when we pad things out below).
4266              * That's the reason for the alignment arithmetic below.
4267              */
4268             if (infoLevel >= 0x101)
4269                 align = (4 - (orbytes & 3)) & 3;
4270             else
4271                 align = 0;
4272             if (orbytes + bytesInBuffer + align > maxReturnData) {
4273                 osi_Log1(smb_logp, "T2 dir search exceed max return data %d",
4274                           maxReturnData);
4275                 break;
4276             }
4277
4278             /* this is one of the entries to use: it is not deleted
4279              * and it matches the star pattern we're looking for.
4280              * Put out the name, preceded by its length.
4281              */
4282             /* First zero everything else */
4283             memset(origOp, 0, ohbytes);
4284
4285             if (infoLevel <= 0x101)
4286                 *(origOp + ohbytes - 1) = (unsigned char) onbytes;
4287             else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
4288                 *((u_long *)(op + 8)) = onbytes;
4289             else
4290                 *((u_long *)(op + 60)) = onbytes;
4291             strcpy(origOp+ohbytes, dep->name);
4292             if (smb_StoreAnsiFilenames)
4293                 CharToOem(origOp+ohbytes, origOp+ohbytes);
4294
4295             /* Short name if requested and needed */
4296             if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
4297                 if (NeedShortName) {
4298                     strcpy(op + 70, shortName);
4299                     if (smb_StoreAnsiFilenames)
4300                         CharToOem(op + 70, op + 70);
4301                     *(op + 68) = shortNameEnd - shortName;
4302                 }
4303             }
4304
4305             /* now, adjust the # of entries copied */
4306             returnedNames++;
4307
4308             /* NextEntryOffset and FileIndex */
4309             if (infoLevel >= 101) {
4310                 int entryOffset = orbytes + align;
4311                 *((u_long *)op) = entryOffset;
4312                 *((u_long *)(op+4)) = nextEntryCookie;
4313             }
4314
4315             /* now we emit the attribute.  This is tricky, since
4316              * we need to really stat the file to find out what
4317              * type of entry we've got.  Right now, we're copying
4318              * out data from a buffer, while holding the scp
4319              * locked, so it isn't really convenient to stat
4320              * something now.  We'll put in a place holder
4321              * now, and make a second pass before returning this
4322              * to get the real attributes.  So, we just skip the
4323              * data for now, and adjust it later.  We allocate a
4324              * patch record to make it easy to find this point
4325              * later.  The replay will happen at a time when it is
4326              * safe to unlock the directory.
4327              */
4328             if (infoLevel != 0x103) {
4329                 curPatchp = malloc(sizeof(*curPatchp));
4330                 osi_QAdd((osi_queue_t **) &dirListPatchesp,
4331                           &curPatchp->q);
4332                 curPatchp->dptr = op;
4333                 if (infoLevel >= 0x101)
4334                     curPatchp->dptr += 8;
4335
4336                 if (smb_hideDotFiles && smb_IsDotFile(dep->name)) {
4337                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4338                 }       
4339                 else    
4340                     curPatchp->flags = 0;
4341
4342                 curPatchp->fid.cell = scp->fid.cell;
4343                 curPatchp->fid.volume = scp->fid.volume;
4344                 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4345                 curPatchp->fid.unique = ntohl(dep->fid.unique);
4346
4347                 /* temp */
4348                 curPatchp->dep = dep;
4349             }   
4350
4351             if (searchFlags & 4)
4352                 /* put out resume key */
4353                 *((u_long *)origOp) = nextEntryCookie;
4354
4355             /* Adjust byte ptr and count */
4356             origOp += orbytes;  /* skip entire record */
4357             bytesInBuffer += orbytes;
4358
4359             /* and pad the record out */
4360             while (--align >= 0) {
4361                 *origOp++ = 0;
4362                 bytesInBuffer++;
4363             }
4364         }       /* if we're including this name */
4365         else if (!starPattern &&
4366                  !foundInexact &&
4367                  dep->fid.vnode != 0 &&
4368                  smb_V3MatchMask(dep->name, maskp, CM_FLAG_CASEFOLD)) {
4369             /* We were looking for exact matches, but here's an inexact one*/
4370             foundInexact = 1;
4371         }
4372                 
4373       nextEntry:
4374         /* and adjust curOffset to be where the new cookie is */
4375         thyper.HighPart = 0;
4376         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4377         curOffset = LargeIntegerAdd(thyper, curOffset);
4378     } /* while copying data for dir listing */
4379
4380     /* If we didn't get a star pattern, we did an exact match during the first pass. 
4381      * If there were no exact matches found, we fail over to inexact matches by
4382      * marking the query as a star pattern (matches all case permutations), and
4383      * re-running the query. 
4384      */
4385     if (returnedNames == 0 && !starPattern && foundInexact) {
4386         osi_Log0(afsd_logp,"T2 Search: No exact matches. Re-running for inexact matches");
4387         starPattern = 1;
4388         goto startsearch;
4389     }
4390
4391     /* release the mutex */
4392     lock_ReleaseMutex(&scp->mx);
4393     if (bufferp) 
4394         buf_Release(bufferp);
4395
4396     /* apply and free last set of patches; if not doing a star match, this
4397      * will be empty, but better safe (and freeing everything) than sorry.
4398      */
4399     code2 = smb_ApplyV3DirListPatches(scp, &dirListPatchesp, infoLevel, userp,
4400                               &req);
4401         
4402     /* now put out the final parameters */
4403     if (returnedNames == 0) 
4404         eos = 1;
4405     if (p->opcode == 1) {
4406         /* find first */
4407         outp->parmsp[0] = (unsigned short) dsp->cookie;
4408         outp->parmsp[1] = returnedNames;
4409         outp->parmsp[2] = eos;
4410         outp->parmsp[3] = 0;            /* nothing wrong with EAS */
4411         outp->parmsp[4] = 0;    
4412         /* don't need last name to continue
4413          * search, cookie is enough.  Normally,
4414          * this is the offset of the file name
4415          * of the last entry returned.
4416          */
4417         outp->totalParms = 10;  /* in bytes */
4418     }
4419     else {
4420         /* find next */
4421         outp->parmsp[0] = returnedNames;
4422         outp->parmsp[1] = eos;
4423         outp->parmsp[2] = 0;    /* EAS error */
4424         outp->parmsp[3] = 0;    /* last name, as above */
4425         outp->totalParms = 8;   /* in bytes */
4426     }   
4427
4428     /* return # of bytes in the buffer */
4429     outp->totalData = bytesInBuffer;
4430
4431     /* Return error code if unsuccessful on first request */
4432     if (code == 0 && p->opcode == 1 && returnedNames == 0)
4433         code = CM_ERROR_NOSUCHFILE;
4434
4435     osi_Log4(smb_logp, "T2 search dir done, opcode %d, id %d, %d names, code %d",
4436              p->opcode, dsp->cookie, returnedNames, code);
4437
4438     /* if we're supposed to close the search after this request, or if
4439      * we're supposed to close the search if we're done, and we're done,
4440      * or if something went wrong, close the search.
4441      */
4442     /* ((searchFlags & 1) || ((searchFlags & 2) && eos) */
4443     if ((searchFlags & 1) || (returnedNames == 0) || 
4444          ((searchFlags & 2) && eos) || code != 0)
4445         smb_DeleteDirSearch(dsp);
4446     if (code)
4447         smb_SendTran2Error(vcp, p, opx, code);
4448     else
4449         smb_SendTran2Packet(vcp, outp, opx);
4450
4451     smb_FreeTran2Packet(outp);
4452     smb_ReleaseDirSearch(dsp);
4453     cm_ReleaseSCache(scp);
4454     cm_ReleaseUser(userp);
4455     return 0;
4456 }
4457
4458 long smb_ReceiveV3FindClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4459 {
4460     int dirHandle;
4461     smb_dirSearch_t *dsp;
4462
4463     dirHandle = smb_GetSMBParm(inp, 0);
4464         
4465     osi_Log1(smb_logp, "SMB3 find close handle %d", dirHandle);
4466
4467     dsp = smb_FindDirSearch(dirHandle);
4468         
4469     if (!dsp)
4470         return CM_ERROR_BADFD;
4471         
4472     /* otherwise, we have an FD to destroy */
4473     smb_DeleteDirSearch(dsp);
4474     smb_ReleaseDirSearch(dsp);
4475         
4476     /* and return results */
4477     smb_SetSMBDataLength(outp, 0);
4478
4479     return 0;
4480 }
4481
4482 long smb_ReceiveV3FindNotifyClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4483 {
4484     smb_SetSMBDataLength(outp, 0);
4485     return 0;
4486 }
4487
4488 long smb_ReceiveV3OpenX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4489 {
4490     char *pathp;
4491     long code = 0;
4492     cm_space_t *spacep;
4493     int excl;
4494     cm_user_t *userp;
4495     cm_scache_t *dscp;          /* dir we're dealing with */
4496     cm_scache_t *scp;           /* file we're creating */
4497     cm_attr_t setAttr;
4498     int initialModeBits;
4499     smb_fid_t *fidp;
4500     int attributes;
4501     char *lastNamep;
4502     time_t dosTime;
4503     int openFun;
4504     int trunc;
4505     int openMode;
4506     int extraInfo;
4507     int openAction;
4508     int parmSlot;                       /* which parm we're dealing with */
4509     char *tidPathp;
4510     cm_req_t req;
4511
4512     cm_InitReq(&req);
4513
4514     scp = NULL;
4515         
4516     extraInfo = (smb_GetSMBParm(inp, 2) & 1);   /* return extra info */
4517     openFun = smb_GetSMBParm(inp, 8);   /* open function */
4518     excl = ((openFun & 3) == 0);
4519     trunc = ((openFun & 3) == 2);               /* truncate it */
4520     openMode = (smb_GetSMBParm(inp, 3) & 0x7);
4521     openAction = 0;                     /* tracks what we did */
4522
4523     attributes = smb_GetSMBParm(inp, 5);
4524     dosTime = smb_GetSMBParm(inp, 6) | (smb_GetSMBParm(inp, 7) << 16);
4525
4526         /* compute initial mode bits based on read-only flag in attributes */
4527     initialModeBits = 0666;
4528     if (attributes & 1) initialModeBits &= ~0222;
4529         
4530     pathp = smb_GetSMBData(inp, NULL);
4531     if (smb_StoreAnsiFilenames)
4532         OemToChar(pathp,pathp);
4533
4534     spacep = inp->spacep;
4535     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4536
4537     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4538         /* special case magic file name for receiving IOCTL requests
4539          * (since IOCTL calls themselves aren't getting through).
4540          */
4541 #ifdef NOTSERVICE
4542         osi_Log0(smb_logp, "IOCTL Open");
4543 #endif
4544
4545         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4546         smb_SetupIoctlFid(fidp, spacep);
4547
4548         /* set inp->fid so that later read calls in same msg can find fid */
4549         inp->fid = fidp->fid;
4550         
4551         /* copy out remainder of the parms */
4552         parmSlot = 2;
4553         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4554         if (extraInfo) {
4555             smb_SetSMBParm(outp, parmSlot, /* attrs */ 0); parmSlot++;
4556             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* mod time */
4557             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4558             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* len */
4559             smb_SetSMBParm(outp, parmSlot, 0x7fff); parmSlot++;
4560             smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4561             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4562             smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4563         }   
4564         /* and the final "always present" stuff */
4565         smb_SetSMBParm(outp, parmSlot, /* openAction found existing file */ 1); parmSlot++;
4566         /* next write out the "unique" ID */
4567         smb_SetSMBParm(outp, parmSlot, 0x1234); parmSlot++;
4568         smb_SetSMBParm(outp, parmSlot, 0x5678); parmSlot++;
4569         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4570         smb_SetSMBDataLength(outp, 0);
4571
4572         /* and clean up fid reference */
4573         smb_ReleaseFID(fidp);
4574         return 0;
4575     }
4576
4577 #ifdef DEBUG_VERBOSE
4578     {
4579         char *hexp, *asciip;
4580         asciip = (lastNamep ? lastNamep : pathp );
4581         hexp = osi_HexifyString(asciip);
4582         DEBUG_EVENT2("AFS", "V3Open H[%s] A[%s]", hexp, asciip );
4583         free(hexp);
4584     }
4585 #endif
4586     userp = smb_GetUser(vcp, inp);
4587
4588     dscp = NULL;
4589     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4590     if (code) {
4591         cm_ReleaseUser(userp);
4592         return CM_ERROR_NOSUCHPATH;
4593     }
4594     code = cm_NameI(cm_data.rootSCachep, pathp,
4595                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4596                     userp, tidPathp, &req, &scp);
4597
4598 #ifdef DFS_SUPPORT
4599     if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
4600         cm_ReleaseSCache(scp);
4601         cm_ReleaseUser(userp);
4602         if ( WANTS_DFS_PATHNAMES(inp) )
4603             return CM_ERROR_PATH_NOT_COVERED;
4604         else
4605             return CM_ERROR_BADSHARENAME;
4606     }
4607 #endif /* DFS_SUPPORT */
4608
4609     if (code != 0) {
4610         code = cm_NameI(cm_data.rootSCachep, spacep->data,
4611                         CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4612                         userp, tidPathp, &req, &dscp);
4613         if (code) {
4614             cm_ReleaseUser(userp);
4615             return code;
4616         }
4617
4618 #ifdef DFS_SUPPORT
4619         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4620             cm_ReleaseSCache(dscp);
4621             cm_ReleaseUser(userp);
4622             if ( WANTS_DFS_PATHNAMES(inp) )
4623                 return CM_ERROR_PATH_NOT_COVERED;
4624             else
4625                 return CM_ERROR_BADSHARENAME;
4626         }
4627 #endif /* DFS_SUPPORT */
4628
4629         /* otherwise, scp points to the parent directory.  Do a lookup,
4630          * and truncate the file if we find it, otherwise we create the
4631          * file.
4632          */
4633         if (!lastNamep) 
4634             lastNamep = pathp;
4635         else 
4636             lastNamep++;
4637         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
4638                           &req, &scp);
4639         if (code && code != CM_ERROR_NOSUCHFILE) {
4640             cm_ReleaseSCache(dscp);
4641             cm_ReleaseUser(userp);
4642             return code;
4643         }
4644     }
4645         
4646     /* if we get here, if code is 0, the file exists and is represented by
4647      * scp.  Otherwise, we have to create it.  The dir may be represented
4648      * by dscp, or we may have found the file directly.  If code is non-zero,
4649      * scp is NULL.
4650      */
4651     if (code == 0) {
4652         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
4653         if (code) {
4654             if (dscp) cm_ReleaseSCache(dscp);
4655             cm_ReleaseSCache(scp);
4656             cm_ReleaseUser(userp);
4657             return code;
4658         }
4659
4660         if (excl) {
4661             /* oops, file shouldn't be there */
4662             if (dscp) 
4663                 cm_ReleaseSCache(dscp);
4664             cm_ReleaseSCache(scp);
4665             cm_ReleaseUser(userp);
4666             return CM_ERROR_EXISTS;
4667         }
4668
4669         if (trunc) {
4670             setAttr.mask = CM_ATTRMASK_LENGTH;
4671             setAttr.length.LowPart = 0;
4672             setAttr.length.HighPart = 0;
4673             code = cm_SetAttr(scp, &setAttr, userp, &req);
4674             openAction = 3;     /* truncated existing file */
4675         }
4676         else openAction = 1;    /* found existing file */
4677     }
4678     else if (!(openFun & SMB_ATTR_DIRECTORY)) {
4679         /* don't create if not found */
4680         if (dscp) cm_ReleaseSCache(dscp);
4681         cm_ReleaseUser(userp);
4682         return CM_ERROR_NOSUCHFILE;
4683     }
4684     else {
4685         osi_assert(dscp != NULL);
4686         osi_Log1(smb_logp, "smb_ReceiveV3OpenX creating file %s",
4687                  osi_LogSaveString(smb_logp, lastNamep));
4688         openAction = 2; /* created file */
4689         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
4690         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
4691         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
4692                          &req);
4693         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4694             smb_NotifyChange(FILE_ACTION_ADDED,
4695                              FILE_NOTIFY_CHANGE_FILE_NAME,
4696                              dscp, lastNamep, NULL, TRUE);
4697         if (!excl && code == CM_ERROR_EXISTS) {
4698             /* not an exclusive create, and someone else tried
4699              * creating it already, then we open it anyway.  We
4700              * don't bother retrying after this, since if this next
4701              * fails, that means that the file was deleted after we
4702              * started this call.
4703              */
4704             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
4705                              userp, &req, &scp);
4706             if (code == 0) {
4707                 if (trunc) {
4708                     setAttr.mask = CM_ATTRMASK_LENGTH;
4709                     setAttr.length.LowPart = 0;
4710                     setAttr.length.HighPart = 0;
4711                     code = cm_SetAttr(scp, &setAttr, userp, &req);
4712                 }   
4713             }   /* lookup succeeded */
4714         }
4715     }
4716         
4717     /* we don't need this any longer */
4718     if (dscp) 
4719         cm_ReleaseSCache(dscp);
4720
4721     if (code) {
4722         /* something went wrong creating or truncating the file */
4723         if (scp) 
4724             cm_ReleaseSCache(scp);
4725         cm_ReleaseUser(userp);
4726         return code;
4727     }
4728         
4729     /* make sure we're about to open a file */
4730     if (scp->fileType != CM_SCACHETYPE_FILE) {
4731         cm_ReleaseSCache(scp);
4732         cm_ReleaseUser(userp);
4733         return CM_ERROR_ISDIR;
4734     }
4735
4736     /* now all we have to do is open the file itself */
4737     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4738     osi_assert(fidp);
4739         
4740     /* save a pointer to the vnode */
4741     fidp->scp = scp;
4742         
4743     /* compute open mode */
4744     if (openMode != 1) 
4745         fidp->flags |= SMB_FID_OPENREAD;
4746     if (openMode == 1 || openMode == 2)
4747         fidp->flags |= SMB_FID_OPENWRITE;
4748
4749     smb_ReleaseFID(fidp);
4750         
4751     cm_Open(scp, 0, userp);
4752
4753     /* set inp->fid so that later read calls in same msg can find fid */
4754     inp->fid = fidp->fid;
4755         
4756     /* copy out remainder of the parms */
4757     parmSlot = 2;
4758     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
4759     lock_ObtainMutex(&scp->mx);
4760     if (extraInfo) {
4761         smb_SetSMBParm(outp, parmSlot, smb_Attributes(scp)); parmSlot++;
4762         smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4763         smb_SetSMBParm(outp, parmSlot, dosTime & 0xffff); parmSlot++;
4764         smb_SetSMBParm(outp, parmSlot, (dosTime>>16) & 0xffff); parmSlot++;
4765         smb_SetSMBParm(outp, parmSlot, scp->length.LowPart & 0xffff); parmSlot++;
4766         smb_SetSMBParm(outp, parmSlot, (scp->length.LowPart >> 16) & 0xffff); parmSlot++;
4767         smb_SetSMBParm(outp, parmSlot, openMode); parmSlot++;
4768         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* file type 0 ==> normal file or dir */
4769         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++; /* IPC junk */
4770     }
4771     /* and the final "always present" stuff */
4772     smb_SetSMBParm(outp, parmSlot, openAction); parmSlot++;
4773     /* next write out the "unique" ID */
4774     smb_SetSMBParm(outp, parmSlot, scp->fid.vnode & 0xffff); parmSlot++;
4775     smb_SetSMBParm(outp, parmSlot, scp->fid.volume & 0xffff); parmSlot++;
4776     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;
4777     lock_ReleaseMutex(&scp->mx);
4778     smb_SetSMBDataLength(outp, 0);
4779
4780     osi_Log1(smb_logp, "SMB OpenX opening fid %d", fidp->fid);
4781
4782     cm_ReleaseUser(userp);
4783     /* leave scp held since we put it in fidp->scp */
4784     return 0;
4785 }       
4786
4787 long smb_ReceiveV3LockingX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4788 {
4789     cm_req_t req;
4790     cm_user_t *userp;
4791     unsigned short fid;
4792     smb_fid_t *fidp;
4793     cm_scache_t *scp;
4794     unsigned char LockType;
4795     unsigned short NumberOfUnlocks, NumberOfLocks;
4796     unsigned long Timeout;
4797     char *op;
4798     LARGE_INTEGER LOffset, LLength;
4799     smb_waitingLock_t *waitingLock;
4800     void *lockp;
4801     long code = 0;
4802     int i;
4803
4804     cm_InitReq(&req);
4805
4806     fid = smb_GetSMBParm(inp, 2);
4807     fid = smb_ChainFID(fid, inp);
4808
4809     fidp = smb_FindFID(vcp, fid, 0);
4810     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4811         return CM_ERROR_BADFD;
4812     }
4813     /* set inp->fid so that later read calls in same msg can find fid */
4814     inp->fid = fid;
4815
4816     userp = smb_GetUser(vcp, inp);
4817
4818     scp = fidp->scp;
4819
4820     lock_ObtainMutex(&scp->mx);
4821     code = cm_SyncOp(scp, NULL, userp, &req, 0,
4822                       CM_SCACHESYNC_NEEDCALLBACK
4823                          | CM_SCACHESYNC_GETSTATUS
4824                          | CM_SCACHESYNC_LOCK);
4825     if (code) 
4826         goto doneSync;
4827
4828     LockType = smb_GetSMBParm(inp, 3) & 0xff;
4829     Timeout = (smb_GetSMBParm(inp, 5) << 16) + smb_GetSMBParm(inp, 4);
4830     NumberOfUnlocks = smb_GetSMBParm(inp, 6);
4831     NumberOfLocks = smb_GetSMBParm(inp, 7);
4832
4833     op = smb_GetSMBData(inp, NULL);
4834
4835     for (i=0; i<NumberOfUnlocks; i++) {
4836         if (LockType & 0x10) {
4837             /* Large Files */
4838             LOffset.HighPart = *((LONG *)(op + 4));
4839             LOffset.LowPart = *((DWORD *)(op + 8));
4840             LLength.HighPart = *((LONG *)(op + 12));
4841             LLength.LowPart = *((DWORD *)(op + 16));
4842             op += 20;
4843         }
4844         else {
4845             /* Not Large Files */
4846             LOffset.HighPart = 0;
4847             LOffset.LowPart = *((DWORD *)(op + 2));
4848             LLength.HighPart = 0;
4849             LLength.LowPart = *((DWORD *)(op + 6));
4850             op += 10;
4851         }
4852         if (LargeIntegerNotEqualToZero(LOffset))
4853             continue;
4854         /* Do not check length -- length check done in cm_Unlock */
4855
4856         code = cm_Unlock(scp, LockType, LOffset, LLength, userp, &req);
4857         if (code) goto done;
4858     }       
4859
4860     for (i=0; i<NumberOfLocks; i++) {
4861         if (LockType & 0x10) {
4862             /* Large Files */
4863             LOffset.HighPart = *((LONG *)(op + 4));
4864             LOffset.LowPart = *((DWORD *)(op + 8));
4865             LLength.HighPart = *((LONG *)(op + 12));
4866             LLength.LowPart = *((DWORD *)(op + 16));
4867             op += 20;
4868         }
4869         else {
4870             /* Not Large Files */
4871             LOffset.HighPart = 0;
4872             LOffset.LowPart = *((DWORD *)(op + 2));
4873             LLength.HighPart = 0;
4874             LLength.LowPart = *((DWORD *)(op + 6));
4875             op += 10;
4876         }
4877         if (LargeIntegerNotEqualToZero(LOffset))
4878             continue;
4879         if (LargeIntegerLessThan(LOffset, scp->length))
4880             continue;
4881
4882         code = cm_Lock(scp, LockType, LOffset, LLength, Timeout,
4883                         userp, &req, &lockp);
4884         if (code == CM_ERROR_WOULDBLOCK && Timeout != 0) {
4885             /* Put on waiting list */
4886             waitingLock = malloc(sizeof(smb_waitingLock_t));
4887             waitingLock->vcp = vcp;
4888             smb_HoldVC(vcp);
4889             waitingLock->inp = smb_CopyPacket(inp);
4890             waitingLock->outp = smb_CopyPacket(outp);
4891             waitingLock->timeRemaining = Timeout;
4892             waitingLock->lockp = lockp;
4893             lock_ObtainWrite(&smb_globalLock);
4894             osi_QAdd((osi_queue_t **)&smb_allWaitingLocks,
4895                       &waitingLock->q);
4896             osi_Wakeup((long) &smb_allWaitingLocks);
4897             lock_ReleaseWrite(&smb_globalLock);
4898             /* don't send reply immediately */
4899             outp->flags |= SMB_PACKETFLAG_NOSEND;
4900         }
4901         if (code) 
4902             break;
4903     }           
4904
4905     if (code) {
4906         /* release any locks acquired before the failure */
4907     }
4908     else
4909         smb_SetSMBDataLength(outp, 0);
4910   done:   
4911     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
4912   doneSync:
4913     lock_ReleaseMutex(&scp->mx);
4914     cm_ReleaseUser(userp);
4915     smb_ReleaseFID(fidp);
4916
4917     return code;
4918 }
4919
4920 long smb_ReceiveV3GetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4921 {
4922     unsigned short fid;
4923     smb_fid_t *fidp;
4924     cm_scache_t *scp;
4925     long code = 0;
4926     time_t searchTime;
4927     cm_user_t *userp;
4928     cm_req_t req;
4929
4930     cm_InitReq(&req);
4931
4932     fid = smb_GetSMBParm(inp, 0);
4933     fid = smb_ChainFID(fid, inp);
4934         
4935     fidp = smb_FindFID(vcp, fid, 0);
4936     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4937         return CM_ERROR_BADFD;
4938     }
4939         
4940     userp = smb_GetUser(vcp, inp);
4941         
4942     scp = fidp->scp;
4943         
4944     /* otherwise, stat the file */
4945     lock_ObtainMutex(&scp->mx);
4946     code = cm_SyncOp(scp, NULL, userp, &req, 0,
4947                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4948     if (code) goto done;
4949
4950     /* decode times.  We need a search time, but the response to this
4951      * call provides the date first, not the time, as returned in the
4952      * searchTime variable.  So we take the high-order bits first.
4953      */
4954     smb_SearchTimeFromUnixTime(&searchTime, scp->clientModTime);
4955     smb_SetSMBParm(outp, 0, (searchTime >> 16) & 0xffff);       /* ctime */
4956     smb_SetSMBParm(outp, 1, searchTime & 0xffff);
4957     smb_SetSMBParm(outp, 2, (searchTime >> 16) & 0xffff);       /* atime */
4958     smb_SetSMBParm(outp, 3, searchTime & 0xffff);
4959     smb_SetSMBParm(outp, 4, (searchTime >> 16) & 0xffff);       /* mtime */
4960     smb_SetSMBParm(outp, 5, searchTime & 0xffff);
4961
4962     /* now handle file size and allocation size */
4963     smb_SetSMBParm(outp, 6, scp->length.LowPart & 0xffff);              /* file size */
4964     smb_SetSMBParm(outp, 7, (scp->length.LowPart >> 16) & 0xffff);
4965     smb_SetSMBParm(outp, 8, scp->length.LowPart & 0xffff);              /* alloc size */
4966     smb_SetSMBParm(outp, 9, (scp->length.LowPart >> 16) & 0xffff);
4967
4968     /* file attribute */
4969     smb_SetSMBParm(outp, 10, smb_Attributes(scp));
4970         
4971     /* and finalize stuff */
4972     smb_SetSMBDataLength(outp, 0);
4973     code = 0;
4974
4975   done:
4976     lock_ReleaseMutex(&scp->mx);
4977     cm_ReleaseUser(userp);
4978     smb_ReleaseFID(fidp);
4979     return code;
4980 }       
4981
4982 long smb_ReceiveV3SetAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4983 {
4984     unsigned short fid;
4985     smb_fid_t *fidp;
4986     cm_scache_t *scp;
4987     long code = 0;
4988     time_t searchTime;
4989     time_t unixTime;
4990     cm_user_t *userp;
4991     cm_attr_t attrs;
4992     cm_req_t req;
4993
4994     cm_InitReq(&req);
4995
4996     fid = smb_GetSMBParm(inp, 0);
4997     fid = smb_ChainFID(fid, inp);
4998         
4999     fidp = smb_FindFID(vcp, fid, 0);
5000     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5001         return CM_ERROR_BADFD;
5002     }
5003         
5004     userp = smb_GetUser(vcp, inp);
5005         
5006     scp = fidp->scp;
5007         
5008     /* now prepare to call cm_setattr.  This message only sets various times,
5009      * and AFS only implements mtime, and we'll set the mtime if that's
5010      * requested.  The others we'll ignore.
5011      */
5012     searchTime = smb_GetSMBParm(inp, 5) | (smb_GetSMBParm(inp, 6) << 16);
5013         
5014     if (searchTime != 0) {
5015         smb_UnixTimeFromSearchTime(&unixTime, searchTime);
5016
5017         if ( unixTime != -1 ) {
5018             attrs.mask = CM_ATTRMASK_CLIENTMODTIME;
5019             attrs.clientModTime = unixTime;
5020             code = cm_SetAttr(scp, &attrs, userp, &req);
5021
5022             osi_Log1(smb_logp, "SMB receive V3SetAttributes [fid=%ld]", fid);
5023         } else {
5024             osi_Log1(smb_logp, "**smb_UnixTimeFromSearchTime failed searchTime=%ld", searchTime);
5025         }
5026     }
5027     else code = 0;
5028
5029     cm_ReleaseUser(userp);
5030     smb_ReleaseFID(fidp);
5031     return code;
5032 }
5033
5034
5035 long smb_ReceiveV3ReadX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5036 {
5037     osi_hyper_t offset;
5038     long count, finalCount;
5039     unsigned short fd;
5040     smb_fid_t *fidp;
5041     long code = 0;
5042     cm_user_t *userp;
5043     char *op;
5044         
5045     fd = smb_GetSMBParm(inp, 2);
5046     count = smb_GetSMBParm(inp, 5);
5047     offset.HighPart = 0;        /* too bad */
5048     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5049
5050     osi_Log3(smb_logp, "smb_ReceiveV3Read fd %d, off 0x%x, size 0x%x",
5051              fd, offset.LowPart, count);
5052         
5053     fd = smb_ChainFID(fd, inp);
5054     fidp = smb_FindFID(vcp, fd, 0);
5055     if (!fidp) {
5056         return CM_ERROR_BADFD;
5057     }
5058     /* set inp->fid so that later read calls in same msg can find fid */
5059     inp->fid = fd;
5060
5061     if (fidp->flags & SMB_FID_IOCTL) {
5062         return smb_IoctlV3Read(fidp, vcp, inp, outp);
5063     }
5064         
5065     userp = smb_GetUser(vcp, inp);
5066
5067     /* 0 and 1 are reserved for request chaining, were setup by our caller,
5068      * and will be further filled in after we return.
5069      */
5070     smb_SetSMBParm(outp, 2, 0); /* remaining bytes, for pipes */
5071     smb_SetSMBParm(outp, 3, 0); /* resvd */
5072     smb_SetSMBParm(outp, 4, 0); /* resvd */
5073     smb_SetSMBParm(outp, 5, count);     /* # of bytes we're going to read */
5074     /* fill in #6 when we have all the parameters' space reserved */
5075     smb_SetSMBParm(outp, 7, 0); /* resv'd */
5076     smb_SetSMBParm(outp, 8, 0); /* resv'd */
5077     smb_SetSMBParm(outp, 9, 0); /* resv'd */
5078     smb_SetSMBParm(outp, 10, 0);        /* resv'd */
5079     smb_SetSMBParm(outp, 11, 0);        /* reserved */
5080
5081     /* get op ptr after putting in the parms, since otherwise we don't
5082      * know where the data really is.
5083      */
5084     op = smb_GetSMBData(outp, NULL);
5085         
5086     /* now fill in offset from start of SMB header to first data byte (to op) */
5087     smb_SetSMBParm(outp, 6, ((int) (op - outp->data)));
5088
5089     /* set the packet data length the count of the # of bytes */
5090     smb_SetSMBDataLength(outp, count);
5091
5092 #ifndef DJGPP
5093     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5094 #else /* DJGPP */
5095     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5096 #endif /* !DJGPP */
5097
5098     /* fix some things up */
5099     smb_SetSMBParm(outp, 5, finalCount);
5100     smb_SetSMBDataLength(outp, finalCount);
5101
5102     smb_ReleaseFID(fidp);
5103
5104     cm_ReleaseUser(userp);
5105     return code;
5106 }   
5107         
5108 /*
5109  * Values for createDisp, copied from NTDDK.H
5110  */
5111 #define  FILE_SUPERSEDE 0       // (???)
5112 #define  FILE_OPEN      1       // (open)
5113 #define  FILE_CREATE    2       // (exclusive)
5114 #define  FILE_OPEN_IF   3       // (non-exclusive)
5115 #define  FILE_OVERWRITE 4       // (open & truncate, but do not create)
5116 #define  FILE_OVERWRITE_IF 5    // (open & truncate, or create)
5117
5118 long smb_ReceiveNTCreateX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5119 {
5120     char *pathp, *realPathp;
5121     long code = 0;
5122     cm_space_t *spacep;
5123     cm_user_t *userp;
5124     cm_scache_t *dscp;          /* parent dir */
5125     cm_scache_t *scp;           /* file to create or open */
5126     cm_scache_t *targetScp;     /* if scp is a symlink */
5127     cm_attr_t setAttr;
5128     char *lastNamep;
5129     char *treeStartp;
5130     unsigned short nameLength;
5131     unsigned int flags;
5132     unsigned int requestOpLock;
5133     unsigned int requestBatchOpLock;
5134     unsigned int mustBeDir;
5135     unsigned int treeCreate;
5136     int realDirFlag;
5137     unsigned int desiredAccess;
5138     unsigned int extAttributes;
5139     unsigned int createDisp;
5140     unsigned int createOptions;
5141     int initialModeBits;
5142     unsigned short baseFid;
5143     smb_fid_t *baseFidp;
5144     smb_fid_t *fidp;
5145     cm_scache_t *baseDirp;
5146     unsigned short openAction;
5147     int parmSlot;
5148     long fidflags;
5149     FILETIME ft;
5150     LARGE_INTEGER sz;
5151     char *tidPathp;
5152     BOOL foundscp;
5153     cm_req_t req;
5154
5155     cm_InitReq(&req);
5156
5157     /* This code is very long and has a lot of if-then-else clauses
5158      * scp and dscp get reused frequently and we need to ensure that 
5159      * we don't lose a reference.  Start by ensuring that they are NULL.
5160      */
5161     scp = NULL;
5162     dscp = NULL;
5163     treeCreate = FALSE;
5164     foundscp = FALSE;
5165
5166     nameLength = smb_GetSMBOffsetParm(inp, 2, 1);
5167     flags = smb_GetSMBOffsetParm(inp, 3, 1)
5168         | (smb_GetSMBOffsetParm(inp, 4, 1) << 16);
5169     requestOpLock = flags & 0x02;
5170     requestBatchOpLock = flags & 0x04;
5171     mustBeDir = flags & 0x08;
5172
5173     /*
5174      * Why all of a sudden 32-bit FID?
5175      * We will reject all bits higher than 16.
5176      */
5177     if (smb_GetSMBOffsetParm(inp, 6, 1) != 0)
5178         return CM_ERROR_INVAL;
5179     baseFid = smb_GetSMBOffsetParm(inp, 5, 1);
5180     desiredAccess = smb_GetSMBOffsetParm(inp, 7, 1)
5181         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
5182     extAttributes = smb_GetSMBOffsetParm(inp, 13, 1)
5183         | (smb_GetSMBOffsetParm(inp, 14, 1) << 16);
5184     createDisp = smb_GetSMBOffsetParm(inp, 17, 1)
5185         | (smb_GetSMBOffsetParm(inp, 18, 1) << 16);
5186     createOptions = smb_GetSMBOffsetParm(inp, 19, 1)
5187         | (smb_GetSMBOffsetParm(inp, 20, 1) << 16);
5188
5189     /* mustBeDir is never set; createOptions directory bit seems to be
5190      * more important
5191      */
5192     if (createOptions & 1)
5193         realDirFlag = 1;
5194     else if (createOptions & 0x40)
5195         realDirFlag = 0;
5196     else
5197         realDirFlag = -1;
5198
5199     /*
5200      * compute initial mode bits based on read-only flag in
5201      * extended attributes
5202      */
5203     initialModeBits = 0666;
5204     if (extAttributes & 1) 
5205         initialModeBits &= ~0222;
5206
5207     pathp = smb_GetSMBData(inp, NULL);
5208     /* Sometimes path is not null-terminated, so we make a copy. */
5209     realPathp = malloc(nameLength+1);
5210     memcpy(realPathp, pathp, nameLength);
5211     realPathp[nameLength] = 0;
5212     if (smb_StoreAnsiFilenames)
5213         OemToChar(realPathp,realPathp);
5214
5215     spacep = inp->spacep;
5216     smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5217
5218     osi_Log1(smb_logp,"NTCreateX for [%s]",osi_LogSaveString(smb_logp,realPathp));
5219     osi_Log4(smb_logp,"... da=[%x] ea=[%x] cd=[%x] co=[%x]", desiredAccess, extAttributes, createDisp, createOptions);
5220     osi_Log2(smb_logp,"... flags=[%x] lastNamep=[%s]", flags, osi_LogSaveString(smb_logp,(lastNamep?lastNamep:"null")));
5221
5222     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5223         /* special case magic file name for receiving IOCTL requests
5224          * (since IOCTL calls themselves aren't getting through).
5225          */
5226         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5227         smb_SetupIoctlFid(fidp, spacep);
5228         osi_Log1(smb_logp,"NTCreateX Setting up IOCTL on fid[%d]",fidp->fid);
5229
5230         /* set inp->fid so that later read calls in same msg can find fid */
5231         inp->fid = fidp->fid;
5232
5233         /* out parms */
5234         parmSlot = 2;
5235         smb_SetSMBParmByte(outp, parmSlot, 0);  /* oplock */
5236         smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5237         smb_SetSMBParmLong(outp, parmSlot, 1); parmSlot += 2; /* Action */
5238         /* times */
5239         memset(&ft, 0, sizeof(ft));
5240         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5241         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5242         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5243         smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5244         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2; /* attr */
5245         sz.HighPart = 0x7fff; sz.LowPart = 0;
5246         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* alen */
5247         smb_SetSMBParmDouble(outp, parmSlot, (char *)&sz); parmSlot += 4; /* len */
5248         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* filetype */
5249         smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;  /* dev state */
5250         smb_SetSMBParmByte(outp, parmSlot, 0);  /* is a dir? */
5251         smb_SetSMBDataLength(outp, 0);
5252
5253         /* clean up fid reference */
5254         smb_ReleaseFID(fidp);
5255         free(realPathp);
5256         return 0;
5257     }
5258
5259 #ifdef DEBUG_VERBOSE
5260     {
5261         char *hexp, *asciip;
5262         asciip = (lastNamep? lastNamep : realPathp);
5263         hexp = osi_HexifyString( asciip );
5264         DEBUG_EVENT2("AFS", "NTCreateX H[%s] A[%s]", hexp, asciip);
5265         free(hexp);
5266     }
5267 #endif
5268     userp = smb_GetUser(vcp, inp);
5269     if (!userp) {
5270         osi_Log1(smb_logp, "NTCreateX Invalid user [%d]", ((smb_t *) inp)->uid);
5271         free(realPathp);
5272         return CM_ERROR_INVAL;
5273     }
5274
5275     if (baseFid == 0) {
5276         baseDirp = cm_data.rootSCachep;
5277         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5278         if (code == CM_ERROR_TIDIPC) {
5279             /* Attempt to use a TID allocated for IPC.  The client
5280              * is probably looking for DCE RPC end points which we
5281              * don't support OR it could be looking to make a DFS
5282              * referral request. 
5283              */
5284             osi_Log0(smb_logp, "NTCreateX received IPC TID");
5285 #ifndef DFS_SUPPORT
5286             free(realPathp);
5287             cm_ReleaseUser(userp);
5288             return CM_ERROR_NOSUCHFILE;
5289 #endif /* DFS_SUPPORT */
5290         }
5291     } else {
5292         baseFidp = smb_FindFID(vcp, baseFid, 0);
5293         if (!baseFidp) {
5294             osi_Log1(smb_logp, "NTCreateX Invalid base fid [%d]", baseFid);
5295             free(realPathp);
5296             cm_ReleaseUser(userp);
5297             return CM_ERROR_INVAL;
5298         }       
5299         baseDirp = baseFidp->scp;
5300         tidPathp = NULL;
5301     }
5302
5303     osi_Log1(smb_logp, "NTCreateX tidPathp=[%s]", (tidPathp==NULL)?"null": osi_LogSaveString(smb_logp,tidPathp));
5304
5305     /* compute open mode */
5306     fidflags = 0;
5307     if (desiredAccess & DELETE)
5308         fidflags |= SMB_FID_OPENDELETE;
5309     if (desiredAccess & AFS_ACCESS_READ)
5310         fidflags |= SMB_FID_OPENREAD;
5311     if (desiredAccess & AFS_ACCESS_WRITE)
5312         fidflags |= SMB_FID_OPENWRITE;
5313
5314     code = 0;
5315
5316     /* For an exclusive create, we want to do a case sensitive match for the last component. */
5317     if ( createDisp == FILE_CREATE || 
5318          createDisp == FILE_OVERWRITE ||
5319          createDisp == FILE_OVERWRITE_IF) {
5320         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5321                         userp, tidPathp, &req, &dscp);
5322         if (code == 0) {
5323 #ifdef DFS_SUPPORT
5324             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5325                 cm_ReleaseSCache(dscp);
5326                 cm_ReleaseUser(userp);
5327                 free(realPathp);
5328                 if ( WANTS_DFS_PATHNAMES(inp) )
5329                     return CM_ERROR_PATH_NOT_COVERED;
5330                 else
5331                     return CM_ERROR_BADSHARENAME;
5332             }
5333 #endif /* DFS_SUPPORT */
5334             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5335                              userp, &req, &scp);
5336             if (code == CM_ERROR_NOSUCHFILE) {
5337                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
5338                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5339                 if (code == 0 && realDirFlag == 1) {
5340                     cm_ReleaseSCache(scp);
5341                     cm_ReleaseSCache(dscp);
5342                     cm_ReleaseUser(userp);
5343                     free(realPathp);
5344                     return CM_ERROR_EXISTS;
5345                 }
5346             }
5347         }
5348         /* we have both scp and dscp */
5349     } else {
5350         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5351                         userp, tidPathp, &req, &scp);
5352 #ifdef DFS_SUPPORT
5353         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
5354             cm_ReleaseSCache(scp);
5355             cm_ReleaseUser(userp);
5356             free(realPathp);
5357             if ( WANTS_DFS_PATHNAMES(inp) )
5358                 return CM_ERROR_PATH_NOT_COVERED;
5359             else
5360                 return CM_ERROR_BADSHARENAME;
5361         }
5362 #endif /* DFS_SUPPORT */
5363         /* we might have scp but not dscp */
5364     }
5365
5366     if (scp)
5367         foundscp = TRUE;
5368     
5369     if (!foundscp || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
5370         /* look up parent directory */
5371         /* If we are trying to create a path (i.e. multiple nested directories), then we don't *need*
5372          * the immediate parent.  We have to work our way up realPathp until we hit something that we
5373          * recognize.
5374          */
5375
5376         /* we might or might not have scp */
5377
5378         if (dscp == NULL) {
5379             do {
5380                 char *tp;
5381
5382                 code = cm_NameI(baseDirp, spacep->data,
5383                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5384                              userp, tidPathp, &req, &dscp);
5385
5386 #ifdef DFS_SUPPORT
5387                 if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5388                     if (scp)
5389                         cm_ReleaseSCache(scp);
5390                     cm_ReleaseSCache(dscp);
5391                     cm_ReleaseUser(userp);
5392                     free(realPathp);
5393                     if ( WANTS_DFS_PATHNAMES(inp) )
5394                         return CM_ERROR_PATH_NOT_COVERED;
5395                     else
5396                         return CM_ERROR_BADSHARENAME;
5397                 }
5398 #endif /* DFS_SUPPORT */
5399
5400                 if (code && 
5401                      (tp = strrchr(spacep->data,'\\')) &&
5402                      (createDisp == FILE_CREATE) &&
5403                      (realDirFlag == 1)) {
5404                     *tp++ = 0;
5405                     treeCreate = TRUE;
5406                     treeStartp = realPathp + (tp - spacep->data);
5407
5408                     if (*tp && !smb_IsLegalFilename(tp)) {
5409                         if (baseFid != 0) 
5410                             smb_ReleaseFID(baseFidp);
5411                         cm_ReleaseUser(userp);
5412                         free(realPathp);
5413                         if (scp)
5414                             cm_ReleaseSCache(scp);
5415                         return CM_ERROR_BADNTFILENAME;
5416                     }
5417                     code = 0;
5418                 }
5419             } while (dscp == NULL && code == 0);
5420         } else
5421                         code = 0;
5422
5423         /* we might have scp and we might have dscp */
5424
5425         if (baseFid != 0) 
5426             smb_ReleaseFID(baseFidp);
5427
5428         if (code) {
5429             osi_Log0(smb_logp,"NTCreateX parent not found");
5430             if (scp)
5431                 cm_ReleaseSCache(scp);
5432             if (dscp)
5433                 cm_ReleaseSCache(dscp);
5434             cm_ReleaseUser(userp);
5435             free(realPathp);
5436             return code;
5437         }
5438
5439         if (treeCreate && dscp->fileType == CM_SCACHETYPE_FILE) {
5440             /* A file exists where we want a directory. */
5441             if (scp)
5442                 cm_ReleaseSCache(scp);
5443             cm_ReleaseSCache(dscp);
5444             cm_ReleaseUser(userp);
5445             free(realPathp);
5446             return CM_ERROR_EXISTS;
5447         }
5448
5449         if (!lastNamep) 
5450             lastNamep = realPathp;
5451         else 
5452             lastNamep++;
5453
5454         if (!smb_IsLegalFilename(lastNamep)) {
5455             if (scp)
5456                 cm_ReleaseSCache(scp);
5457                         if (dscp)
5458             cm_ReleaseSCache(dscp);
5459             cm_ReleaseUser(userp);
5460             free(realPathp);
5461             return CM_ERROR_BADNTFILENAME;
5462         }
5463
5464         if (!foundscp && !treeCreate) {
5465             if ( createDisp == FILE_CREATE || 
5466                  createDisp == FILE_OVERWRITE ||
5467                  createDisp == FILE_OVERWRITE_IF) 
5468             {
5469                 code = cm_Lookup(dscp, lastNamep,
5470                                   CM_FLAG_FOLLOW, userp, &req, &scp);
5471             } else {
5472                 code = cm_Lookup(dscp, lastNamep,
5473                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5474                                  userp, &req, &scp);
5475             }
5476             if (code && code != CM_ERROR_NOSUCHFILE) {
5477                 cm_ReleaseSCache(dscp);
5478                 cm_ReleaseUser(userp);
5479                 free(realPathp);
5480                 return code;
5481             }
5482         }
5483         /* we have scp and dscp */
5484     } else {
5485         /* we have scp but not dscp */
5486         if (baseFid != 0) 
5487             smb_ReleaseFID(baseFidp);
5488     }       
5489
5490     /* if we get here, if code is 0, the file exists and is represented by
5491      * scp.  Otherwise, we have to create it.  The dir may be represented
5492      * by dscp, or we may have found the file directly.  If code is non-zero,
5493      * scp is NULL.
5494      */
5495     if (code == 0 && !treeCreate) {
5496         if (createDisp == FILE_CREATE) {
5497             /* oops, file shouldn't be there */
5498             if (dscp)
5499                 cm_ReleaseSCache(dscp);
5500             cm_ReleaseSCache(scp);
5501             cm_ReleaseUser(userp);
5502             free(realPathp);
5503             return CM_ERROR_EXISTS;
5504         }
5505
5506         if ( createDisp == FILE_OVERWRITE || 
5507              createDisp == FILE_OVERWRITE_IF) {
5508             setAttr.mask = CM_ATTRMASK_LENGTH;
5509             setAttr.length.LowPart = 0;
5510             setAttr.length.HighPart = 0;
5511             /* now watch for a symlink */
5512             code = 0;
5513             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5514                 targetScp = 0;
5515                 osi_assert(dscp != NULL);
5516                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5517                 if (code == 0) {
5518                     /* we have a more accurate file to use (the
5519                      * target of the symbolic link).  Otherwise,
5520                      * we'll just use the symlink anyway.
5521                      */
5522                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
5523                               scp, targetScp);
5524                     cm_ReleaseSCache(scp);
5525                     scp = targetScp;
5526                 }
5527             }
5528             code = cm_SetAttr(scp, &setAttr, userp, &req);
5529             openAction = 3;     /* truncated existing file */
5530         }
5531         else 
5532             openAction = 1;     /* found existing file */
5533
5534         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp, &req);
5535         if (code) {
5536             if (dscp)
5537                 cm_ReleaseSCache(dscp);
5538             cm_ReleaseSCache(scp);
5539             cm_ReleaseUser(userp);
5540             free(realPathp);
5541             return code;
5542         }
5543     } else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
5544         /* don't create if not found */
5545         if (dscp)
5546             cm_ReleaseSCache(dscp);
5547                 if (scp)
5548                         cm_ReleaseSCache(scp);
5549         cm_ReleaseUser(userp);
5550         free(realPathp);
5551         return CM_ERROR_NOSUCHFILE;
5552     } else if (realDirFlag == 0 || realDirFlag == -1) {
5553         osi_assert(dscp != NULL);
5554         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating file %s",
5555                   osi_LogSaveString(smb_logp, lastNamep));
5556         openAction = 2;         /* created file */
5557         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5558         setAttr.clientModTime = time(NULL);
5559         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp, &req);
5560         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5561             smb_NotifyChange(FILE_ACTION_ADDED,
5562                               FILE_NOTIFY_CHANGE_FILE_NAME,
5563                               dscp, lastNamep, NULL, TRUE);
5564         if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
5565             /* Not an exclusive create, and someone else tried
5566              * creating it already, then we open it anyway.  We
5567              * don't bother retrying after this, since if this next
5568              * fails, that means that the file was deleted after we
5569              * started this call.
5570              */
5571             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
5572                               userp, &req, &scp);
5573             if (code == 0) {
5574                 if (createDisp == FILE_OVERWRITE_IF) {
5575                     setAttr.mask = CM_ATTRMASK_LENGTH;
5576                     setAttr.length.LowPart = 0;
5577                     setAttr.length.HighPart = 0;
5578
5579                     /* now watch for a symlink */
5580                     code = 0;
5581                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5582                         targetScp = 0;
5583                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5584                         if (code == 0) {
5585                             /* we have a more accurate file to use (the
5586                              * target of the symbolic link).  Otherwise,
5587                              * we'll just use the symlink anyway.
5588                              */
5589                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
5590                                       scp, targetScp);
5591                             cm_ReleaseSCache(scp);
5592                             scp = targetScp;
5593                         }
5594                     }
5595                     code = cm_SetAttr(scp, &setAttr, userp, &req);
5596                 }
5597             }   /* lookup succeeded */
5598         }
5599     } else {
5600         char *tp, *pp;
5601         char *cp; /* This component */
5602         int clen = 0; /* length of component */
5603         cm_scache_t *tscp1, *tscp2;
5604         int isLast = 0;
5605
5606         /* create directory */
5607         if ( !treeCreate ) 
5608             treeStartp = lastNamep;
5609         osi_assert(dscp != NULL);
5610         osi_Log1(smb_logp, "smb_ReceiveNTCreateX creating directory [%s]",
5611                   osi_LogSaveString(smb_logp, treeStartp));
5612         openAction = 2;         /* created directory */
5613
5614         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5615         setAttr.clientModTime = time(NULL);
5616
5617         pp = treeStartp;
5618         cp = spacep->data;
5619         tscp1 = dscp;
5620         cm_HoldSCache(tscp1);
5621         tscp2 = NULL;
5622
5623         while (pp && *pp) {
5624             tp = strchr(pp, '\\');
5625             if (!tp) {
5626                 strcpy(cp,pp);
5627                 clen = strlen(cp);
5628                 isLast = 1; /* indicate last component.  the supplied path never ends in a slash */
5629             } else {
5630                 clen = tp - pp;
5631                 strncpy(cp,pp,clen);
5632                 *(cp + clen) = 0;
5633                 tp++;
5634             }
5635             pp = tp;
5636
5637             if (clen == 0) 
5638                 continue; /* the supplied path can't have consecutive slashes either , but */
5639
5640             /* cp is the next component to be created. */
5641             code = cm_MakeDir(tscp1, cp, 0, &setAttr, userp, &req);
5642             if (code == 0 && (tscp1->flags & CM_SCACHEFLAG_ANYWATCH))
5643                 smb_NotifyChange(FILE_ACTION_ADDED,
5644                                   FILE_NOTIFY_CHANGE_DIR_NAME,
5645                                   tscp1, cp, NULL, TRUE);
5646             if (code == 0 || 
5647                  (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
5648                 /* Not an exclusive create, and someone else tried
5649                  * creating it already, then we open it anyway.  We
5650                  * don't bother retrying after this, since if this next
5651                  * fails, that means that the file was deleted after we
5652                  * started this call.
5653                  */
5654                 code = cm_Lookup(tscp1, cp, CM_FLAG_CASEFOLD,
5655                                   userp, &req, &tscp2);
5656             }       
5657             if (code) 
5658                 break;
5659
5660             if (!isLast) { /* for anything other than dscp, release it unless it's the last one */
5661                 cm_ReleaseSCache(tscp1);
5662                 tscp1 = tscp2; /* Newly created directory will be next parent */
5663                 /* the hold is transfered to tscp1 from tscp2 */
5664             }
5665         }
5666
5667         if (dscp)
5668             cm_ReleaseSCache(dscp);
5669         dscp = tscp1;
5670         if (scp)
5671             cm_ReleaseSCache(scp);
5672         scp = tscp2;
5673         /* 
5674          * if we get here and code == 0, then scp is the last directory created, and dscp is the
5675          * parent of scp.
5676          */
5677     }
5678
5679     if (code) {
5680         /* something went wrong creating or truncating the file */
5681         if (scp) 
5682             cm_ReleaseSCache(scp);
5683         if (dscp) 
5684             cm_ReleaseSCache(dscp);
5685         cm_ReleaseUser(userp);
5686         free(realPathp);
5687         return code;
5688     }
5689
5690     /* make sure we have file vs. dir right (only applies for single component case) */
5691     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
5692         /* now watch for a symlink */
5693         code = 0;
5694         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
5695             cm_scache_t * targetScp = 0;
5696             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
5697             if (code == 0) {
5698                 /* we have a more accurate file to use (the
5699                 * target of the symbolic link).  Otherwise,
5700                 * we'll just use the symlink anyway.
5701                 */
5702                 osi_Log2(smb_logp, "symlink vp %x to vp %x", scp, targetScp);
5703                 cm_ReleaseSCache(scp);
5704                 scp = targetScp;
5705             }
5706         }
5707
5708         if (scp->fileType != CM_SCACHETYPE_FILE) {
5709             if (dscp)
5710                 cm_ReleaseSCache(dscp);
5711             cm_ReleaseSCache(scp);
5712             cm_ReleaseUser(userp);
5713             free(realPathp);
5714             return CM_ERROR_ISDIR;
5715         }
5716     }
5717
5718     /* (only applies to single component case) */
5719     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
5720         cm_ReleaseSCache(scp);
5721         cm_ReleaseSCache(dscp);
5722         cm_ReleaseUser(userp);
5723         free(realPathp);
5724         return CM_ERROR_NOTDIR;
5725     }
5726
5727     /* open the file itself */
5728     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5729     osi_assert(fidp);
5730     /* save a pointer to the vnode */
5731     fidp->scp = scp;    /* Hold transfered to fidp->scp and no longer needed */
5732
5733     fidp->flags = fidflags;
5734
5735     /* save parent dir and pathname for delete or change notification */
5736     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
5737         fidp->flags |= SMB_FID_NTOPEN;
5738         fidp->NTopen_dscp = dscp;
5739         cm_HoldSCache(dscp);
5740         fidp->NTopen_pathp = strdup(lastNamep);
5741     }
5742     fidp->NTopen_wholepathp = realPathp;
5743
5744     /* we don't need this any longer */
5745     if (dscp) {
5746         cm_ReleaseSCache(dscp);
5747         dscp = NULL;
5748     }
5749     cm_Open(scp, 0, userp);
5750
5751     /* set inp->fid so that later read calls in same msg can find fid */
5752     inp->fid = fidp->fid;
5753
5754     /* out parms */
5755     parmSlot = 2;
5756     lock_ObtainMutex(&scp->mx);
5757     smb_SetSMBParmByte(outp, parmSlot, 0);      /* oplock */
5758     smb_SetSMBParm(outp, parmSlot, fidp->fid); parmSlot++;
5759     smb_SetSMBParmLong(outp, parmSlot, openAction); parmSlot += 2;
5760     smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
5761     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5762     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5763     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5764     smb_SetSMBParmDouble(outp, parmSlot, (char *)&ft); parmSlot += 4;
5765     smb_SetSMBParmLong(outp, parmSlot, smb_ExtAttributes(scp));
5766     parmSlot += 2;
5767     smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5768     smb_SetSMBParmDouble(outp, parmSlot, (char *)&scp->length); parmSlot += 4;
5769     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* filetype */
5770     smb_SetSMBParm(outp, parmSlot, 0); parmSlot++;      /* dev state */
5771     smb_SetSMBParmByte(outp, parmSlot,
5772                         scp->fileType == CM_SCACHETYPE_DIRECTORY); /* is a dir? */
5773     lock_ReleaseMutex(&scp->mx);
5774     smb_SetSMBDataLength(outp, 0);
5775
5776     osi_Log2(smb_logp, "SMB NT CreateX opening fid %d path %s", fidp->fid,
5777               osi_LogSaveString(smb_logp, realPathp));
5778
5779     smb_ReleaseFID(fidp);
5780
5781     cm_ReleaseUser(userp);
5782
5783     /* Can't free realPathp if we get here since fidp->NTopen_wholepathp is pointing there */
5784
5785     /* leave scp held since we put it in fidp->scp */
5786     return 0;
5787 }       
5788
5789 /*
5790  * A lot of stuff copied verbatim from NT Create&X to NT Tran Create.
5791  * Instead, ultimately, would like to use a subroutine for common code.
5792  */
5793 long smb_ReceiveNTTranCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5794 {
5795     char *pathp, *realPathp;
5796     long code = 0;
5797     cm_space_t *spacep;
5798     cm_user_t *userp;
5799     cm_scache_t *dscp;          /* parent dir */
5800     cm_scache_t *scp;           /* file to create or open */
5801     cm_scache_t *targetScp;     /* if scp is a symlink */
5802     cm_attr_t setAttr;
5803     char *lastNamep;
5804     unsigned long nameLength;
5805     unsigned int flags;
5806     unsigned int requestOpLock;
5807     unsigned int requestBatchOpLock;
5808     unsigned int mustBeDir;
5809     unsigned int extendedRespRequired;
5810     int realDirFlag;
5811     unsigned int desiredAccess;
5812 #ifdef DEBUG_VERBOSE    
5813     unsigned int allocSize;
5814     unsigned int shareAccess;
5815 #endif
5816     unsigned int extAttributes;
5817     unsigned int createDisp;
5818 #ifdef DEBUG_VERBOSE
5819     unsigned int sdLen;
5820 #endif
5821     unsigned int createOptions;
5822     int initialModeBits;
5823     unsigned short baseFid;
5824     smb_fid_t *baseFidp;
5825     smb_fid_t *fidp;
5826     cm_scache_t *baseDirp;
5827     unsigned short openAction;
5828     int parmSlot;
5829     long fidflags;
5830     FILETIME ft;
5831     char *tidPathp;
5832     BOOL foundscp;
5833     int parmOffset, dataOffset;
5834     char *parmp;
5835     ULONG *lparmp;
5836     char *outData;
5837     cm_req_t req;
5838
5839     cm_InitReq(&req);
5840
5841     foundscp = FALSE;
5842     scp = NULL;
5843
5844     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
5845         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
5846     parmp = inp->data + parmOffset;
5847     lparmp = (ULONG *) parmp;
5848
5849     flags = lparmp[0];
5850     requestOpLock = flags & 0x02;
5851     requestBatchOpLock = flags & 0x04;
5852     mustBeDir = flags & 0x08;
5853     extendedRespRequired = flags & 0x10;
5854
5855     /*
5856      * Why all of a sudden 32-bit FID?
5857      * We will reject all bits higher than 16.
5858      */
5859     if (lparmp[1] & 0xFFFF0000)
5860         return CM_ERROR_INVAL;
5861     baseFid = (unsigned short)lparmp[1];
5862     desiredAccess = lparmp[2];
5863 #ifdef DEBUG_VERBOSE
5864     allocSize = lparmp[3];
5865 #endif /* DEBUG_VERSOSE */
5866     extAttributes = lparmp[5];
5867 #ifdef DEBUG_VEROSE
5868     shareAccess = lparmp[6];
5869 #endif
5870     createDisp = lparmp[7];
5871     createOptions = lparmp[8];
5872 #ifdef DEBUG_VERBOSE
5873     sdLen = lparmp[9];
5874 #endif
5875     nameLength = lparmp[11];
5876
5877 #ifdef DEBUG_VERBOSE
5878     osi_Log4(smb_logp,"NTTranCreate with da[%x],ea[%x],sa[%x],cd[%x]",desiredAccess,extAttributes,shareAccess,createDisp);
5879     osi_Log3(smb_logp,"... co[%x],sdl[%x],as[%x]",createOptions,sdLen,allocSize);
5880     osi_Log1(smb_logp,"... flags[%x]",flags);
5881 #endif
5882
5883     /* mustBeDir is never set; createOptions directory bit seems to be
5884      * more important
5885      */
5886     if (createOptions & 1)
5887         realDirFlag = 1;
5888     else if (createOptions & 0x40)
5889         realDirFlag = 0;
5890     else
5891         realDirFlag = -1;
5892
5893     /*
5894      * compute initial mode bits based on read-only flag in
5895      * extended attributes
5896      */
5897     initialModeBits = 0666;
5898     if (extAttributes & 1) 
5899         initialModeBits &= ~0222;
5900
5901     pathp = parmp + (13 * sizeof(ULONG)) + sizeof(UCHAR);
5902     /* Sometimes path is not null-terminated, so we make a copy. */
5903     realPathp = malloc(nameLength+1);
5904     memcpy(realPathp, pathp, nameLength);
5905     realPathp[nameLength] = 0;
5906     if (smb_StoreAnsiFilenames)
5907         OemToChar(realPathp,realPathp);
5908
5909     spacep = cm_GetSpace();
5910     smb_StripLastComponent(spacep->data, &lastNamep, realPathp);
5911
5912     /*
5913      * Nothing here to handle SMB_IOCTL_FILENAME.
5914      * Will add it if necessary.
5915      */
5916
5917 #ifdef DEBUG_VERBOSE
5918     {
5919         char *hexp, *asciip;
5920         asciip = (lastNamep? lastNamep : realPathp);
5921         hexp = osi_HexifyString( asciip );
5922         DEBUG_EVENT2("AFS", "NTTranCreate H[%s] A[%s]", hexp, asciip);
5923         free(hexp);
5924     }
5925 #endif
5926
5927     userp = smb_GetUser(vcp, inp);
5928     if (!userp) {
5929         osi_Log1(smb_logp, "NTTranCreate invalid user [%d]", ((smb_t *) inp)->uid);
5930         free(realPathp);
5931         return CM_ERROR_INVAL;
5932     }
5933
5934     if (baseFid == 0) {
5935         baseDirp = cm_data.rootSCachep;
5936         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5937         if (code == CM_ERROR_TIDIPC) {
5938             /* Attempt to use a TID allocated for IPC.  The client
5939              * is probably looking for DCE RPC end points which we
5940              * don't support OR it could be looking to make a DFS
5941              * referral request. 
5942              */
5943             osi_Log0(smb_logp, "NTTranCreate received IPC TID");
5944 #ifndef DFS_SUPPORT
5945             free(realPathp);
5946             cm_ReleaseUser(userp);
5947             return CM_ERROR_NOSUCHPATH;
5948 #endif 
5949         }
5950     } else {
5951         baseFidp = smb_FindFID(vcp, baseFid, 0);
5952         if (!baseFidp) {
5953                 osi_Log1(smb_logp, "NTTranCreate Invalid fid [%d]", baseFid);
5954             free(realPathp);
5955             cm_ReleaseUser(userp);
5956             return CM_ERROR_INVAL;
5957         }       
5958         baseDirp = baseFidp->scp;
5959         tidPathp = NULL;
5960     }
5961
5962     /* compute open mode */
5963     fidflags = 0;
5964     if (desiredAccess & DELETE)
5965         fidflags |= SMB_FID_OPENDELETE;
5966     if (desiredAccess & AFS_ACCESS_READ)
5967         fidflags |= SMB_FID_OPENREAD;
5968     if (desiredAccess & AFS_ACCESS_WRITE)
5969         fidflags |= SMB_FID_OPENWRITE;
5970
5971     dscp = NULL;
5972     code = 0;
5973     if ( createDisp == FILE_OPEN || 
5974          createDisp == FILE_OVERWRITE ||
5975          createDisp == FILE_OVERWRITE_IF) {
5976         code = cm_NameI(baseDirp, spacep->data, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
5977                         userp, tidPathp, &req, &dscp);
5978         if (code == 0) {
5979 #ifdef DFS_SUPPORT
5980             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5981                 cm_ReleaseSCache(dscp);
5982                 cm_ReleaseUser(userp);
5983                 free(realPathp);
5984                 if ( WANTS_DFS_PATHNAMES(inp) )
5985                     return CM_ERROR_PATH_NOT_COVERED;
5986                 else
5987                     return CM_ERROR_BADSHARENAME;
5988             }
5989 #endif /* DFS_SUPPORT */
5990             code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, CM_FLAG_FOLLOW,
5991                              userp, &req, &scp);
5992             if (code == CM_ERROR_NOSUCHFILE) {
5993                 code = cm_Lookup(dscp, (lastNamep)?(lastNamep+1):realPathp, 
5994                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, &req, &scp);
5995                 if (code == 0 && realDirFlag == 1) {
5996                     cm_ReleaseSCache(scp);
5997                     cm_ReleaseSCache(dscp);
5998                     cm_ReleaseUser(userp);
5999                     free(realPathp);
6000                     return CM_ERROR_EXISTS;
6001                 }
6002             }
6003         } else 
6004             dscp = NULL;
6005     } else {
6006         code = cm_NameI(baseDirp, realPathp, CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6007                         userp, tidPathp, &req, &scp);
6008 #ifdef DFS_SUPPORT
6009         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK) {
6010             cm_ReleaseSCache(scp);
6011             cm_ReleaseUser(userp);
6012             free(realPathp);
6013             if ( WANTS_DFS_PATHNAMES(inp) )
6014                 return CM_ERROR_PATH_NOT_COVERED;
6015             else
6016                 return CM_ERROR_BADSHARENAME;
6017         }
6018 #endif /* DFS_SUPPORT */
6019     }
6020
6021     if (code == 0) 
6022         foundscp = TRUE;
6023
6024     if (code != 0 || (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE))) {
6025         /* look up parent directory */
6026         if ( !dscp ) {
6027             code = cm_NameI(baseDirp, spacep->data,
6028                              CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6029                              userp, tidPathp, &req, &dscp);
6030 #ifdef DFS_SUPPORT
6031             if (code == 0 && dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6032                 cm_ReleaseSCache(dscp);
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         } else
6042             code = 0;
6043         
6044         cm_FreeSpace(spacep);
6045
6046         if (baseFid != 0) {
6047             smb_ReleaseFID(baseFidp);
6048             baseFidp = 0;
6049         }
6050
6051         if (code) {
6052             cm_ReleaseUser(userp);
6053             free(realPathp);
6054             return code;
6055         }
6056
6057         if (!lastNamep) lastNamep = realPathp;
6058         else lastNamep++;
6059
6060         if (!smb_IsLegalFilename(lastNamep))
6061             return CM_ERROR_BADNTFILENAME;
6062
6063         if (!foundscp) {
6064             if (createDisp == FILE_CREATE || createDisp == FILE_OVERWRITE_IF) {
6065                 code = cm_Lookup(dscp, lastNamep,
6066                                   CM_FLAG_FOLLOW, userp, &req, &scp);
6067             } else {
6068                 code = cm_Lookup(dscp, lastNamep,
6069                                  CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
6070                                  userp, &req, &scp);
6071             }
6072             if (code && code != CM_ERROR_NOSUCHFILE) {
6073                 cm_ReleaseSCache(dscp);
6074                 cm_ReleaseUser(userp);
6075                 free(realPathp);
6076                 return code;
6077             }
6078         }
6079     } else {
6080         if (baseFid != 0) {
6081             smb_ReleaseFID(baseFidp);
6082             baseFidp = 0;
6083         }
6084         cm_FreeSpace(spacep);
6085     }
6086
6087     /* if we get here, if code is 0, the file exists and is represented by
6088      * scp.  Otherwise, we have to create it.  The dir may be represented
6089      * by dscp, or we may have found the file directly.  If code is non-zero,
6090      * scp is NULL.
6091      */
6092     if (code == 0) {
6093         code = cm_CheckNTOpen(scp, desiredAccess, createDisp, userp,
6094                                &req);
6095         if (code) {     
6096             if (dscp) cm_ReleaseSCache(dscp);
6097             cm_ReleaseSCache(scp);
6098             cm_ReleaseUser(userp);
6099             free(realPathp);
6100             return code;
6101         }
6102
6103         if (createDisp == FILE_CREATE) {
6104             /* oops, file shouldn't be there */
6105             if (dscp) cm_ReleaseSCache(dscp);
6106             cm_ReleaseSCache(scp);
6107             cm_ReleaseUser(userp);
6108             free(realPathp);
6109             return CM_ERROR_EXISTS;
6110         }
6111
6112         if (createDisp == FILE_OVERWRITE ||
6113             createDisp == FILE_OVERWRITE_IF) {
6114             setAttr.mask = CM_ATTRMASK_LENGTH;
6115             setAttr.length.LowPart = 0;
6116             setAttr.length.HighPart = 0;
6117
6118             /* now watch for a symlink */
6119             code = 0;
6120             while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6121                 targetScp = 0;
6122                 code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6123                 if (code == 0) {
6124                     /* we have a more accurate file to use (the
6125                     * target of the symbolic link).  Otherwise,
6126                     * we'll just use the symlink anyway.
6127                     */
6128                     osi_Log2(smb_logp, "symlink vp %x to vp %x",
6129                               scp, targetScp);
6130                     cm_ReleaseSCache(scp);
6131                     scp = targetScp;
6132                 }
6133             }
6134             code = cm_SetAttr(scp, &setAttr, userp, &req);
6135             openAction = 3;     /* truncated existing file */
6136         }
6137         else openAction = 1;    /* found existing file */
6138     }
6139     else if (createDisp == FILE_OPEN || createDisp == FILE_OVERWRITE) {
6140         /* don't create if not found */
6141         if (dscp) cm_ReleaseSCache(dscp);
6142         cm_ReleaseUser(userp);
6143         free(realPathp);
6144         return CM_ERROR_NOSUCHFILE;
6145     }
6146     else if (realDirFlag == 0 || realDirFlag == -1) {
6147         osi_assert(dscp != NULL);
6148         osi_Log1(smb_logp, "smb_ReceiveNTTranCreate creating file %s",
6149                   osi_LogSaveString(smb_logp, lastNamep));
6150         openAction = 2;         /* created file */
6151         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6152         setAttr.clientModTime = time(NULL);
6153         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
6154                           &req);
6155         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6156             smb_NotifyChange(FILE_ACTION_ADDED,
6157                               FILE_NOTIFY_CHANGE_FILE_NAME,
6158                               dscp, lastNamep, NULL, TRUE);
6159         if (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE) {
6160             /* Not an exclusive create, and someone else tried
6161              * creating it already, then we open it anyway.  We
6162              * don't bother retrying after this, since if this next
6163              * fails, that means that the file was deleted after we
6164              * started this call.
6165              */
6166             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6167                               userp, &req, &scp);
6168             if (code == 0) {
6169                 if (createDisp == FILE_OVERWRITE_IF) {
6170                     setAttr.mask = CM_ATTRMASK_LENGTH;
6171                     setAttr.length.LowPart = 0;
6172                     setAttr.length.HighPart = 0;
6173
6174                     /* now watch for a symlink */
6175                     code = 0;
6176                     while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6177                         targetScp = 0;
6178                         code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6179                         if (code == 0) {
6180                             /* we have a more accurate file to use (the
6181                             * target of the symbolic link).  Otherwise,
6182                             * we'll just use the symlink anyway.
6183                             */
6184                             osi_Log2(smb_logp, "symlink vp %x to vp %x",
6185                                       scp, targetScp);
6186                             cm_ReleaseSCache(scp);
6187                             scp = targetScp;
6188                         }
6189                     }
6190                     code = cm_SetAttr(scp, &setAttr, userp, &req);
6191                 }       
6192             }   /* lookup succeeded */
6193         }
6194     } else {
6195         /* create directory */
6196         osi_assert(dscp != NULL);
6197         osi_Log1(smb_logp,
6198                   "smb_ReceiveNTTranCreate creating directory %s",
6199                   osi_LogSaveString(smb_logp, lastNamep));
6200         openAction = 2;         /* created directory */
6201         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6202         setAttr.clientModTime = time(NULL);
6203         code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6204         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6205             smb_NotifyChange(FILE_ACTION_ADDED,
6206                               FILE_NOTIFY_CHANGE_DIR_NAME,
6207                               dscp, lastNamep, NULL, TRUE);
6208         if (code == 0 ||
6209             (code == CM_ERROR_EXISTS && createDisp != FILE_CREATE)) {
6210             /* Not an exclusive create, and someone else tried
6211              * creating it already, then we open it anyway.  We
6212              * don't bother retrying after this, since if this next
6213              * fails, that means that the file was deleted after we
6214              * started this call.
6215              */
6216             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
6217                               userp, &req, &scp);
6218         }       
6219     }
6220
6221     if (code) {
6222         /* something went wrong creating or truncating the file */
6223         if (scp) cm_ReleaseSCache(scp);
6224         cm_ReleaseUser(userp);
6225         free(realPathp);
6226         return code;
6227     }
6228
6229     /* make sure we have file vs. dir right */
6230     if (realDirFlag == 0 && scp->fileType != CM_SCACHETYPE_FILE) {
6231         /* now watch for a symlink */
6232         code = 0;
6233         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
6234             targetScp = 0;
6235             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
6236             if (code == 0) {
6237                 /* we have a more accurate file to use (the
6238                 * target of the symbolic link).  Otherwise,
6239                 * we'll just use the symlink anyway.
6240                 */
6241                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
6242                           scp, targetScp);
6243                 cm_ReleaseSCache(scp);
6244                 scp = targetScp;
6245             }
6246         }
6247
6248         if (scp->fileType != CM_SCACHETYPE_FILE) {
6249             cm_ReleaseSCache(scp);
6250             cm_ReleaseUser(userp);
6251             free(realPathp);
6252             return CM_ERROR_ISDIR;
6253         }
6254     }
6255
6256     if (realDirFlag == 1 && scp->fileType == CM_SCACHETYPE_FILE) {
6257         cm_ReleaseSCache(scp);
6258         cm_ReleaseUser(userp);
6259         free(realPathp);
6260         return CM_ERROR_NOTDIR;
6261     }
6262
6263     /* open the file itself */
6264     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
6265     osi_assert(fidp);
6266
6267     /* save a pointer to the vnode */
6268     fidp->scp = scp;
6269
6270     fidp->flags = fidflags;
6271
6272     /* save parent dir and pathname for deletion or change notification */
6273     if (fidflags & (SMB_FID_OPENDELETE | SMB_FID_OPENWRITE)) {
6274         fidp->flags |= SMB_FID_NTOPEN;
6275         fidp->NTopen_dscp = dscp;
6276         cm_HoldSCache(dscp);
6277         fidp->NTopen_pathp = strdup(lastNamep);
6278     }
6279     fidp->NTopen_wholepathp = realPathp;
6280
6281     /* we don't need this any longer */
6282     if (dscp) cm_ReleaseSCache(dscp);
6283
6284     cm_Open(scp, 0, userp);
6285
6286     /* set inp->fid so that later read calls in same msg can find fid */
6287     inp->fid = fidp->fid;
6288
6289     /* check whether we are required to send an extended response */
6290     if (!extendedRespRequired) {
6291         /* out parms */
6292         parmOffset = 8*4 + 39;
6293         parmOffset += 1;        /* pad to 4 */
6294         dataOffset = parmOffset + 70;
6295
6296         parmSlot = 1;
6297         outp->oddByte = 1;
6298         /* Total Parameter Count */
6299         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6300         /* Total Data Count */
6301         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6302         /* Parameter Count */
6303         smb_SetSMBParmLong(outp, parmSlot, 70); parmSlot += 2;
6304         /* Parameter Offset */
6305         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6306         /* Parameter Displacement */
6307         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6308         /* Data Count */
6309         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6310         /* Data Offset */
6311         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6312         /* Data Displacement */
6313         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6314         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
6315         smb_SetSMBDataLength(outp, 70);
6316
6317         lock_ObtainMutex(&scp->mx);
6318         outData = smb_GetSMBData(outp, NULL);
6319         outData++;                      /* round to get to parmOffset */
6320         *outData = 0; outData++;        /* oplock */
6321         *outData = 0; outData++;        /* reserved */
6322         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6323         *((ULONG *)outData) = openAction; outData += 4;
6324         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
6325         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6326         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
6327         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
6328         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
6329         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
6330         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6331         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6332         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6333         *((USHORT *)outData) = 0; outData += 2; /* filetype */
6334         *((USHORT *)outData) = 0; outData += 2; /* dev state */
6335         *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6336         outData += 2;   /* is a dir? */
6337         lock_ReleaseMutex(&scp->mx);
6338     } else {
6339         /* out parms */
6340         parmOffset = 8*4 + 39;
6341         parmOffset += 1;        /* pad to 4 */
6342         dataOffset = parmOffset + 104;
6343         
6344         parmSlot = 1;
6345         outp->oddByte = 1;
6346         /* Total Parameter Count */
6347         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6348         /* Total Data Count */
6349         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6350         /* Parameter Count */
6351         smb_SetSMBParmLong(outp, parmSlot, 101); parmSlot += 2;
6352         /* Parameter Offset */
6353         smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6354         /* Parameter Displacement */
6355         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6356         /* Data Count */
6357         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6358         /* Data Offset */
6359         smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6360         /* Data Displacement */
6361         smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6362         smb_SetSMBParmByte(outp, parmSlot, 0);  /* Setup Count */
6363         smb_SetSMBDataLength(outp, 105);
6364         
6365         lock_ObtainMutex(&scp->mx);
6366         outData = smb_GetSMBData(outp, NULL);
6367         outData++;                      /* round to get to parmOffset */
6368         *outData = 0; outData++;        /* oplock */
6369         *outData = 1; outData++;        /* response type */
6370         *((USHORT *)outData) = fidp->fid; outData += 2; /* fid */
6371         *((ULONG *)outData) = openAction; outData += 4;
6372         *((ULONG *)outData) = 0; outData += 4;  /* EA error offset */
6373         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
6374         *((FILETIME *)outData) = ft; outData += 8;      /* creation time */
6375         *((FILETIME *)outData) = ft; outData += 8;      /* last access time */
6376         *((FILETIME *)outData) = ft; outData += 8;      /* last write time */
6377         *((FILETIME *)outData) = ft; outData += 8;      /* change time */
6378         *((ULONG *)outData) = smb_ExtAttributes(scp); outData += 4;
6379         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* alloc sz */
6380         *((LARGE_INTEGER *)outData) = scp->length; outData += 8; /* EOF */
6381         *((USHORT *)outData) = 0; outData += 2; /* filetype */
6382         *((USHORT *)outData) = 0; outData += 2; /* dev state */
6383         *((USHORT *)outData) = (scp->fileType == CM_SCACHETYPE_DIRECTORY);
6384         outData += 1;   /* is a dir? */
6385         memset(outData,0,24); outData += 24; /* Volume ID and file ID */
6386         *((ULONG *)outData) = 0x001f01ffL; outData += 4; /* Maxmimal access rights */
6387         *((ULONG *)outData) = 0; outData += 4; /* Guest Access rights */
6388         lock_ReleaseMutex(&scp->mx);
6389     }
6390
6391     osi_Log1(smb_logp, "SMB NTTranCreate opening fid %d", fidp->fid);
6392
6393     smb_ReleaseFID(fidp);
6394
6395     cm_ReleaseUser(userp);
6396
6397     /* free(realPathp); Can't free realPathp here because fidp->NTopen_wholepathp points there */
6398     /* leave scp held since we put it in fidp->scp */
6399     return 0;
6400 }
6401
6402 long smb_ReceiveNTTranNotifyChange(smb_vc_t *vcp, smb_packet_t *inp,
6403         smb_packet_t *outp)
6404 {
6405     smb_packet_t *savedPacketp;
6406     ULONG filter; USHORT fid, watchtree;
6407     smb_fid_t *fidp;
6408     cm_scache_t *scp;
6409         
6410     filter = smb_GetSMBParm(inp, 19) |
6411              (smb_GetSMBParm(inp, 20) << 16);
6412     fid = smb_GetSMBParm(inp, 21);
6413     watchtree = smb_GetSMBParm(inp, 22) && 0xffff;  /* TODO: should this be 0xff ? */
6414
6415     fidp = smb_FindFID(vcp, fid, 0);
6416     if (!fidp) {
6417         osi_Log1(smb_logp, "ERROR: NotifyChange given invalid fid [%d]", fid);
6418         return CM_ERROR_BADFD;
6419     }
6420
6421     savedPacketp = smb_CopyPacket(inp);
6422     smb_HoldVC(vcp);
6423     savedPacketp->vcp = vcp;
6424     lock_ObtainMutex(&smb_Dir_Watch_Lock);
6425     savedPacketp->nextp = smb_Directory_Watches;
6426     smb_Directory_Watches = savedPacketp;
6427     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6428
6429     osi_Log4(smb_logp, "Request for NotifyChange filter 0x%x fid %d wtree %d file %s",
6430              filter, fid, watchtree, osi_LogSaveString(smb_logp, fidp->NTopen_wholepathp));
6431
6432     scp = fidp->scp;
6433     lock_ObtainMutex(&scp->mx);
6434     if (watchtree)
6435         scp->flags |= CM_SCACHEFLAG_WATCHEDSUBTREE;
6436     else
6437         scp->flags |= CM_SCACHEFLAG_WATCHED;
6438     lock_ReleaseMutex(&scp->mx);
6439     smb_ReleaseFID(fidp);
6440
6441     outp->flags |= SMB_PACKETFLAG_NOSEND;
6442     return 0;
6443 }
6444
6445 unsigned char nullSecurityDesc[36] = {
6446     0x01,                               /* security descriptor revision */
6447     0x00,                               /* reserved, should be zero */
6448     0x00, 0x80,                         /* security descriptor control;
6449                                          * 0x8000 : self-relative format */
6450     0x14, 0x00, 0x00, 0x00,             /* offset of owner SID */
6451     0x1c, 0x00, 0x00, 0x00,             /* offset of group SID */
6452     0x00, 0x00, 0x00, 0x00,             /* offset of DACL would go here */
6453     0x00, 0x00, 0x00, 0x00,             /* offset of SACL would go here */
6454     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6455                                         /* "null SID" owner SID */
6456     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
6457                                         /* "null SID" group SID */
6458 };      
6459
6460 long smb_ReceiveNTTranQuerySecurityDesc(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6461 {
6462     int parmOffset, parmCount, dataOffset, dataCount;
6463     int parmSlot;
6464     int maxData;
6465     char *outData;
6466     char *parmp;
6467     USHORT *sparmp;
6468     ULONG *lparmp;
6469     USHORT fid;
6470     ULONG securityInformation;
6471
6472     parmOffset = smb_GetSMBOffsetParm(inp, 11, 1)
6473         | (smb_GetSMBOffsetParm(inp, 12, 1) << 16);
6474     parmp = inp->data + parmOffset;
6475     sparmp = (USHORT *) parmp;
6476     lparmp = (ULONG *) parmp;
6477
6478     fid = sparmp[0];
6479     securityInformation = lparmp[1];
6480
6481     maxData = smb_GetSMBOffsetParm(inp, 7, 1)
6482         | (smb_GetSMBOffsetParm(inp, 8, 1) << 16);
6483
6484     if (maxData < 36)
6485         dataCount = 0;
6486     else
6487         dataCount = 36;
6488
6489     /* out parms */
6490     parmOffset = 8*4 + 39;
6491     parmOffset += 1;    /* pad to 4 */
6492     parmCount = 4;
6493     dataOffset = parmOffset + parmCount;
6494
6495     parmSlot = 1;
6496     outp->oddByte = 1;
6497     /* Total Parameter Count */
6498     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6499     /* Total Data Count */
6500     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6501     /* Parameter Count */
6502     smb_SetSMBParmLong(outp, parmSlot, parmCount); parmSlot += 2;
6503     /* Parameter Offset */
6504     smb_SetSMBParmLong(outp, parmSlot, parmOffset); parmSlot += 2;
6505     /* Parameter Displacement */
6506     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6507     /* Data Count */
6508     smb_SetSMBParmLong(outp, parmSlot, dataCount); parmSlot += 2;
6509     /* Data Offset */
6510     smb_SetSMBParmLong(outp, parmSlot, dataOffset); parmSlot += 2;
6511     /* Data Displacement */
6512     smb_SetSMBParmLong(outp, parmSlot, 0); parmSlot += 2;
6513     smb_SetSMBParmByte(outp, parmSlot, 0);      /* Setup Count */
6514     smb_SetSMBDataLength(outp, 1 + parmCount + dataCount);
6515
6516     outData = smb_GetSMBData(outp, NULL);
6517     outData++;                  /* round to get to parmOffset */
6518     *((ULONG *)outData) = 36; outData += 4;     /* length */
6519
6520     if (maxData >= 36) {
6521         memcpy(outData, nullSecurityDesc, 36);
6522         outData += 36;
6523         return 0;
6524     } else
6525         return CM_ERROR_BUFFERTOOSMALL;
6526 }
6527
6528 long smb_ReceiveNTTransact(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6529 {
6530     unsigned short function;
6531
6532     function = smb_GetSMBParm(inp, 18);
6533
6534     osi_Log1(smb_logp, "SMB NT Transact function %d", function);
6535
6536     /* We can handle long names */
6537     if (vcp->flags & SMB_VCFLAG_USENT)
6538         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
6539         
6540     switch (function) {
6541     case 6: 
6542         return smb_ReceiveNTTranQuerySecurityDesc(vcp, inp, outp);
6543     case 4: 
6544         return smb_ReceiveNTTranNotifyChange(vcp, inp, outp);
6545     case 1: 
6546         return smb_ReceiveNTTranCreate(vcp, inp, outp);
6547     default: 
6548         return CM_ERROR_INVAL;
6549     }
6550 }
6551
6552 /*
6553  * smb_NotifyChange -- find relevant change notification messages and
6554  *                     reply to them
6555  *
6556  * If we don't know the file name (i.e. a callback break), filename is
6557  * NULL, and we return a zero-length list.
6558  */
6559 void smb_NotifyChange(DWORD action, DWORD notifyFilter,
6560         cm_scache_t *dscp, char *filename, char *otherFilename,
6561         BOOL isDirectParent)
6562 {
6563     smb_packet_t *watch, *lastWatch, *nextWatch;
6564     ULONG parmSlot, parmCount, parmOffset, dataOffset, nameLen;
6565     char *outData, *oldOutData;
6566     ULONG filter;
6567     USHORT fid, wtree;
6568     ULONG maxLen;
6569     BOOL twoEntries = FALSE;
6570     ULONG otherNameLen, oldParmCount = 0;
6571     DWORD otherAction;
6572     smb_vc_t *vcp;
6573     smb_fid_t *fidp;
6574
6575     /* Get ready for rename within directory */
6576     if (action == FILE_ACTION_RENAMED_OLD_NAME && otherFilename != NULL) {
6577         twoEntries = TRUE;
6578         otherAction = FILE_ACTION_RENAMED_NEW_NAME;
6579     }
6580
6581     osi_Log2(smb_logp,"in smb_NotifyChange for file [%s] dscp [%x]",
6582              osi_LogSaveString(smb_logp,filename),dscp);
6583
6584     lock_ObtainMutex(&smb_Dir_Watch_Lock);
6585     watch = smb_Directory_Watches;
6586     while (watch) {
6587         filter = smb_GetSMBParm(watch, 19)
6588             | (smb_GetSMBParm(watch, 20) << 16);
6589         fid = smb_GetSMBParm(watch, 21);
6590         wtree = smb_GetSMBParm(watch, 22) & 0xffff;  /* TODO: should this be 0xff ? */
6591         maxLen = smb_GetSMBOffsetParm(watch, 5, 1)
6592             | (smb_GetSMBOffsetParm(watch, 6, 1) << 16);
6593         vcp = watch->vcp;
6594
6595         /*
6596          * Strange hack - bug in NT Client and NT Server that we
6597          * must emulate?
6598          */
6599         if (filter == 3 && wtree)
6600             filter = 0x17;
6601
6602         fidp = smb_FindFID(vcp, fid, 0);
6603         if (!fidp) {
6604             osi_Log1(smb_logp," no fidp for fid[%d]",fid);
6605             lastWatch = watch;
6606             watch = watch->nextp;
6607             continue;
6608         }       
6609         if (fidp->scp != dscp
6610              || (filter & notifyFilter) == 0
6611              || (!isDirectParent && !wtree)) {
6612             osi_Log1(smb_logp," passing fidp->scp[%x]", fidp->scp);
6613             smb_ReleaseFID(fidp);
6614             lastWatch = watch;
6615             watch = watch->nextp;
6616             continue;
6617         }
6618         smb_ReleaseFID(fidp);
6619
6620         osi_Log4(smb_logp,
6621                   "Sending Change Notification for fid %d filter 0x%x wtree %d file %s",
6622                   fid, filter, wtree, osi_LogSaveString(smb_logp, filename));
6623
6624         nextWatch = watch->nextp;
6625         if (watch == smb_Directory_Watches)
6626             smb_Directory_Watches = nextWatch;
6627         else
6628             lastWatch->nextp = nextWatch;
6629
6630         /* Turn off WATCHED flag in dscp */
6631         lock_ObtainMutex(&dscp->mx);
6632         if (wtree)
6633             dscp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6634         else
6635             dscp->flags &= ~CM_SCACHEFLAG_WATCHED;
6636         lock_ReleaseMutex(&dscp->mx);
6637
6638         /* Convert to response packet */
6639         ((smb_t *) watch)->reb = SMB_FLAGS_SERVER_TO_CLIENT | SMB_FLAGS_CANONICAL_PATHNAMES;
6640         ((smb_t *) watch)->wct = 0;
6641
6642         /* out parms */
6643         if (filename == NULL)
6644             parmCount = 0;
6645         else {
6646             nameLen = strlen(filename);
6647             parmCount = 3*4 + nameLen*2;
6648             parmCount = (parmCount + 3) & ~3;   /* pad to 4 */
6649             if (twoEntries) {
6650                 otherNameLen = strlen(otherFilename);
6651                 oldParmCount = parmCount;
6652                 parmCount += 3*4 + otherNameLen*2;
6653                 parmCount = (parmCount + 3) & ~3; /* pad to 4 */
6654             }
6655             if (maxLen < parmCount)
6656                 parmCount = 0;  /* not enough room */
6657         }
6658         parmOffset = 8*4 + 39;
6659         parmOffset += 1;                        /* pad to 4 */
6660         dataOffset = parmOffset + parmCount;
6661
6662         parmSlot = 1;
6663         watch->oddByte = 1;
6664         /* Total Parameter Count */
6665         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6666         /* Total Data Count */
6667         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6668         /* Parameter Count */
6669         smb_SetSMBParmLong(watch, parmSlot, parmCount); parmSlot += 2;
6670         /* Parameter Offset */
6671         smb_SetSMBParmLong(watch, parmSlot, parmOffset); parmSlot += 2;
6672         /* Parameter Displacement */
6673         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6674         /* Data Count */
6675         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6676         /* Data Offset */
6677         smb_SetSMBParmLong(watch, parmSlot, dataOffset); parmSlot += 2;
6678         /* Data Displacement */
6679         smb_SetSMBParmLong(watch, parmSlot, 0); parmSlot += 2;
6680         smb_SetSMBParmByte(watch, parmSlot, 0); /* Setup Count */
6681         smb_SetSMBDataLength(watch, parmCount + 1);
6682
6683         if (parmCount != 0) {
6684             char * p;
6685             outData = smb_GetSMBData(watch, NULL);
6686             outData++;  /* round to get to parmOffset */
6687             oldOutData = outData;
6688             *((DWORD *)outData) = oldParmCount; outData += 4;
6689             /* Next Entry Offset */
6690             *((DWORD *)outData) = action; outData += 4;
6691             /* Action */
6692             *((DWORD *)outData) = nameLen*2; outData += 4;
6693             /* File Name Length */
6694             p = strdup(filename);
6695             if (smb_StoreAnsiFilenames)
6696                 CharToOem(p,p);
6697             mbstowcs((WCHAR *)outData, p, nameLen);
6698             free(p);
6699             /* File Name */
6700             if (twoEntries) {
6701                 outData = oldOutData + oldParmCount;
6702                 *((DWORD *)outData) = 0; outData += 4;
6703                 /* Next Entry Offset */
6704                 *((DWORD *)outData) = otherAction; outData += 4;
6705                 /* Action */
6706                 *((DWORD *)outData) = otherNameLen*2;
6707                 outData += 4;   /* File Name Length */
6708                 p = strdup(otherFilename);
6709                 if (smb_StoreAnsiFilenames)
6710                     CharToOem(p,p);
6711                 mbstowcs((WCHAR *)outData, p, otherNameLen);    /* File Name */
6712                 free(p);
6713             }       
6714         }       
6715
6716         /*
6717          * If filename is null, we don't know the cause of the
6718          * change notification.  We return zero data (see above),
6719          * and set error code to NT_STATUS_NOTIFY_ENUM_DIR
6720          * (= 0x010C).  We set the error code here by hand, without
6721          * modifying wct and bcc.
6722          */
6723         if (filename == NULL) {
6724             ((smb_t *) watch)->rcls = 0x0C;
6725             ((smb_t *) watch)->reh = 0x01;
6726             ((smb_t *) watch)->errLow = 0;
6727             ((smb_t *) watch)->errHigh = 0;
6728             /* Set NT Status codes flag */
6729             ((smb_t *) watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6730         }
6731
6732         smb_SendPacket(vcp, watch);
6733         smb_FreePacket(watch);
6734         watch = nextWatch;
6735     }
6736     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6737 }       
6738
6739 long smb_ReceiveNTCancel(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6740 {
6741     unsigned char *replyWctp;
6742     smb_packet_t *watch, *lastWatch;
6743     USHORT fid, watchtree;
6744     smb_fid_t *fidp;
6745     cm_scache_t *scp;
6746
6747     osi_Log0(smb_logp, "SMB3 receive NT cancel");
6748
6749     lock_ObtainMutex(&smb_Dir_Watch_Lock);
6750     watch = smb_Directory_Watches;
6751     while (watch) {
6752         if (((smb_t *)watch)->uid == ((smb_t *)inp)->uid
6753              && ((smb_t *)watch)->pid == ((smb_t *)inp)->pid
6754              && ((smb_t *)watch)->mid == ((smb_t *)inp)->mid
6755              && ((smb_t *)watch)->tid == ((smb_t *)inp)->tid) {
6756             if (watch == smb_Directory_Watches)
6757                 smb_Directory_Watches = watch->nextp;
6758             else
6759                 lastWatch->nextp = watch->nextp;
6760             lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6761
6762             /* Turn off WATCHED flag in scp */
6763             fid = smb_GetSMBParm(watch, 21);
6764             watchtree = smb_GetSMBParm(watch, 22) & 0xffff;
6765
6766             if (vcp != watch->vcp)
6767                 osi_Log2(smb_logp, "smb_ReceiveNTCancel: vcp %x not equal to watch vcp %x", 
6768                           vcp, watch->vcp);
6769
6770             fidp = smb_FindFID(vcp, fid, 0);
6771             if (fidp) {
6772                 osi_Log3(smb_logp, "Cancelling change notification for fid %d wtree %d file %s", 
6773                           fid, watchtree,
6774                           osi_LogSaveString(smb_logp, (fidp)?fidp->NTopen_wholepathp:""));
6775
6776                 scp = fidp->scp;
6777                 lock_ObtainMutex(&scp->mx);
6778                 if (watchtree)
6779                     scp->flags &= ~CM_SCACHEFLAG_WATCHEDSUBTREE;
6780                 else
6781                     scp->flags &= ~CM_SCACHEFLAG_WATCHED;
6782                 lock_ReleaseMutex(&scp->mx);
6783                 smb_ReleaseFID(fidp);
6784             } else {
6785                 osi_Log2(smb_logp,"NTCancel unable to resolve fid [%d] in vcp[%x]", fid,vcp);
6786             }
6787
6788             /* assume STATUS32; return 0xC0000120 (CANCELED) */
6789             replyWctp = watch->wctp;
6790             *replyWctp++ = 0;
6791             *replyWctp++ = 0;
6792             *replyWctp++ = 0;
6793             ((smb_t *)watch)->rcls = 0x20;
6794             ((smb_t *)watch)->reh = 0x1;
6795             ((smb_t *)watch)->errLow = 0;
6796             ((smb_t *)watch)->errHigh = 0xC0;
6797             ((smb_t *)watch)->flg2 |= SMB_FLAGS2_32BIT_STATUS;
6798             smb_SendPacket(vcp, watch);
6799             smb_FreePacket(watch);
6800             return 0;
6801         }
6802         lastWatch = watch;
6803         watch = watch->nextp;
6804     }
6805     lock_ReleaseMutex(&smb_Dir_Watch_Lock);
6806
6807     return 0;
6808 }
6809
6810 /*
6811  * NT rename also does hard links.
6812  */
6813
6814 #define RENAME_FLAG_MOVE_CLUSTER_INFORMATION 0x102
6815 #define RENAME_FLAG_HARD_LINK                0x103
6816 #define RENAME_FLAG_RENAME                   0x104
6817 #define RENAME_FLAG_COPY                     0x105
6818
6819 long smb_ReceiveNTRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6820 {
6821     char *oldPathp, *newPathp;
6822     long code = 0;
6823     char * tp;
6824     int attrs;
6825     int rename_type;
6826
6827     attrs = smb_GetSMBParm(inp, 0);
6828     rename_type = smb_GetSMBParm(inp, 1);
6829
6830     if (rename_type != RENAME_FLAG_RENAME && rename_type != RENAME_FLAG_HARD_LINK) {
6831         osi_Log1(smb_logp, "NTRename invalid infolevel [%x]", rename_type);
6832         return CM_ERROR_NOACCESS;
6833     }
6834
6835     tp = smb_GetSMBData(inp, NULL);
6836     oldPathp = smb_ParseASCIIBlock(tp, &tp);
6837     if (smb_StoreAnsiFilenames)
6838         OemToChar(oldPathp,oldPathp);
6839     newPathp = smb_ParseASCIIBlock(tp, &tp);
6840     if (smb_StoreAnsiFilenames)
6841         OemToChar(newPathp,newPathp);
6842
6843     osi_Log3(smb_logp, "NTRename for [%s]->[%s] type [%s]",
6844              osi_LogSaveString(smb_logp, oldPathp),
6845              osi_LogSaveString(smb_logp, newPathp),
6846              ((rename_type==RENAME_FLAG_RENAME)?"rename":"hardlink"));
6847
6848     if (rename_type == RENAME_FLAG_RENAME) {
6849         code = smb_Rename(vcp,inp,oldPathp,newPathp,attrs);
6850     } else { /* RENAME_FLAG_HARD_LINK */
6851         code = smb_Link(vcp,inp,oldPathp,newPathp);
6852     }
6853     return code;
6854 }
6855
6856 void smb3_Init()
6857 {
6858     lock_InitializeMutex(&smb_Dir_Watch_Lock, "Directory Watch List Lock");
6859 }
6860
6861 cm_user_t *smb_FindCMUserByName(/*smb_vc_t *vcp,*/ char *usern, char *machine)
6862 {
6863     /*int newUid;*/
6864     smb_username_t *unp;
6865
6866     unp = smb_FindUserByName(usern, machine, SMB_FLAG_CREATE);
6867     if (!unp->userp) {
6868         lock_ObtainMutex(&unp->mx);
6869         unp->userp = cm_NewUser();
6870         lock_ReleaseMutex(&unp->mx);
6871         osi_Log2(smb_logp,"smb_FindCMUserByName New user name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6872         osi_LogEvent("AFS smb_FindCMUserByName : New User",NULL,"name[%s] machine[%s]",usern,machine);
6873     }  else     {
6874         osi_Log2(smb_logp,"smb_FindCMUserByName Not found name[%s] machine[%s]",osi_LogSaveString(smb_logp,usern),osi_LogSaveString(smb_logp,machine));
6875         osi_LogEvent("AFS smb_FindCMUserByName : Found",NULL,"name[%s] machine[%s]",usern,machine);
6876         }
6877     return unp->userp;
6878 }
6879