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