ade4503d0000ab6ad44af31d560463e67d7f0785
[openafs.git] / src / WINNT / afsd / smb3.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #include <windows.h>
14 #pragma warning(push)
15 #pragma warning(disable: 4005)
16 #include <ntstatus.h>
17 #define SECURITY_WIN32
18 #include <security.h>
19 #include <lmaccess.h>
20 #pragma warning(pop)
21 #include <stdlib.h>
22 #include <malloc.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <time.h>
26 #include <osi.h>
27
28 #include "afsd.h"
29 #include <WINNT\afsreg.h>
30
31 #include "smb.h"
32 #include <strsafe.h>
33
34 extern osi_hyper_t hzero;
35
36 smb_packet_t *smb_Directory_Watches = NULL;
37 osi_mutex_t smb_Dir_Watch_Lock;
38
39 smb_tran2Dispatch_t smb_tran2DispatchTable[SMB_TRAN2_NOPCODES];
40
41 smb_tran2Dispatch_t smb_rapDispatchTable[SMB_RAP_NOPCODES];
42
43 /* protected by the smb_globalLock */
44 smb_tran2Packet_t *smb_tran2AssemblyQueuep;
45
46 const clientchar_t **smb_ExecutableExtensions = NULL;
47
48 /* retrieve a held reference to a user structure corresponding to an incoming
49  * request */
50 cm_user_t *smb_GetTran2User(smb_vc_t *vcp, smb_tran2Packet_t *inp)
51 {
52     smb_user_t *uidp;
53     cm_user_t *up = NULL;
54         
55     uidp = smb_FindUID(vcp, inp->uid, 0);
56     if (!uidp) 
57         return NULL;
58         
59     up = smb_GetUserFromUID(uidp);
60
61     smb_ReleaseUID(uidp);
62
63     return up;
64 }
65
66 /* 
67  * Return boolean specifying if the path name is thought to be an 
68  * executable file.  For now .exe or .dll.
69  */
70 afs_uint32 smb_IsExecutableFileName(const clientchar_t *name)
71 {
72     int i, j, len;
73         
74     if ( smb_ExecutableExtensions == NULL || name == NULL)
75         return 0;
76
77     len = (int)cm_ClientStrLen(name);
78
79     for ( i=0; smb_ExecutableExtensions[i]; i++) {
80         j = len - (int)cm_ClientStrLen(smb_ExecutableExtensions[i]);
81         if (cm_ClientStrCmpI(smb_ExecutableExtensions[i], &name[j]) == 0)
82             return 1;
83     }
84
85     return 0;
86 }
87
88 /*
89  * Return extended attributes.
90  * Right now, we aren't using any of the "new" bits, so this looks exactly
91  * like smb_Attributes() (see smb.c).
92  */
93 unsigned long smb_ExtAttributes(cm_scache_t *scp)
94 {
95     unsigned long attrs;
96
97     if (scp->fileType == CM_SCACHETYPE_DIRECTORY ||
98         scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
99         scp->fileType == CM_SCACHETYPE_INVALID)
100     {
101         attrs = SMB_ATTR_DIRECTORY;
102 #ifdef SPECIAL_FOLDERS
103         attrs |= SMB_ATTR_SYSTEM;               /* FILE_ATTRIBUTE_SYSTEM */
104 #endif /* SPECIAL_FOLDERS */
105     } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
106         attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
107     } else if (scp->fid.vnode & 0x1)
108         attrs = SMB_ATTR_DIRECTORY;
109     else 
110         attrs = 0;
111
112     /*
113      * We used to mark a file RO if it was in an RO volume, but that
114      * turns out to be impolitic in NT.  See defect 10007.
115      */
116 #ifdef notdef
117     if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
118         attrs |= SMB_ATTR_READONLY;             /* Read-only */
119 #else
120     if ((scp->unixModeBits & 0222) == 0)
121         attrs |= SMB_ATTR_READONLY;             /* Read-only */
122 #endif
123
124     if (attrs == 0)
125         attrs = SMB_ATTR_NORMAL;                /* FILE_ATTRIBUTE_NORMAL */
126
127     return attrs;
128 }
129
130 int smb_V3IsStarMask(clientchar_t *maskp)
131 {
132     clientchar_t tc;
133
134     while (tc = *maskp++)
135         if (tc == '?' || tc == '*' || tc == '<' || tc == '>') 
136             return 1;
137     return 0;
138 }
139
140 void OutputDebugF(clientchar_t * format, ...) {
141     va_list args;
142     clientchar_t vbuffer[1024];
143
144     va_start( args, format );
145     cm_ClientStrPrintfV(vbuffer, lengthof(vbuffer), format, args);
146     osi_Log1(smb_logp, "%S", osi_LogSaveClientString(smb_logp, vbuffer));
147 }
148
149 void OutputDebugHexDump(unsigned char * buffer, int len) {
150     int i,j,k;
151     char buf[256];
152     static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
153
154     OutputDebugF(_C("Hexdump length [%d]"),len);
155
156     for (i=0;i<len;i++) {
157         if(!(i%16)) {
158             if(i) {
159                 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
160             }
161             StringCchPrintfA(buf, lengthof(buf), "%5x", i);
162             memset(buf+5,' ',80);
163             buf[85] = 0;
164         }
165
166         j = (i%16);
167         j = j*3 + 7 + ((j>7)?1:0);
168         k = buffer[i];
169
170         buf[j] = tr[k / 16]; buf[j+1] = tr[k % 16];
171
172         j = (i%16);
173         j = j + 56 + ((j>7)?1:0);
174
175         buf[j] = (k>32 && k<127)?k:'.';
176     }    
177     if(i) {
178         osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
179     }   
180 }
181
182 #define SMB_EXT_SEC_PACKAGE_NAME "Negotiate"
183
184 void smb_NegotiateExtendedSecurity(void ** secBlob, int * secBlobLength) {
185     SECURITY_STATUS status, istatus;
186     CredHandle creds = {0,0};
187     TimeStamp expiry;
188     SecBufferDesc secOut;
189     SecBuffer secTok;
190     CtxtHandle ctx;
191     ULONG flags;
192
193     *secBlob = NULL;
194     *secBlobLength = 0;
195
196     OutputDebugF(_C("Negotiating Extended Security"));
197
198     status = AcquireCredentialsHandle( NULL,
199                                        SMB_EXT_SEC_PACKAGE_NAME,
200                                        SECPKG_CRED_INBOUND,
201                                        NULL,
202                                        NULL,
203                                        NULL,
204                                        NULL,
205                                        &creds,
206                                        &expiry);
207
208     if (status != SEC_E_OK) {
209         /* Really bad. We return an empty security blob */
210         OutputDebugF(_C("AcquireCredentialsHandle failed with %lX"), status);
211         goto nes_0;
212     }
213
214     secOut.cBuffers = 1;
215     secOut.pBuffers = &secTok;
216     secOut.ulVersion = SECBUFFER_VERSION;
217
218     secTok.BufferType = SECBUFFER_TOKEN;
219     secTok.cbBuffer = 0;
220     secTok.pvBuffer = NULL;
221
222     ctx.dwLower = ctx.dwUpper = 0;
223
224     status = AcceptSecurityContext( &creds,
225                                     NULL,
226                                     NULL,
227                                     ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
228                                     SECURITY_NETWORK_DREP,
229                                     &ctx,
230                                     &secOut,
231                                     &flags,
232                                     &expiry
233                                     );
234
235     if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
236         OutputDebugF(_C("Completing token..."));
237         istatus = CompleteAuthToken(&ctx, &secOut);
238         if ( istatus != SEC_E_OK )
239             OutputDebugF(_C("Token completion failed: %x"), istatus);
240     }
241
242     if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
243         if (secTok.pvBuffer) {
244             *secBlobLength = secTok.cbBuffer;
245             *secBlob = malloc( secTok.cbBuffer );
246             memcpy(*secBlob, secTok.pvBuffer, secTok.cbBuffer );
247         }
248     } else {
249         if ( status != SEC_E_OK )
250             OutputDebugF(_C("AcceptSecurityContext status != CONTINUE  %lX"), status);
251     }
252
253     /* Discard partial security context */
254     DeleteSecurityContext(&ctx);
255
256     if (secTok.pvBuffer) FreeContextBuffer( secTok.pvBuffer );
257
258     /* Discard credentials handle.  We'll reacquire one when we get the session setup X */
259     FreeCredentialsHandle(&creds);
260
261   nes_0:
262     return;
263 }
264
265 struct smb_ext_context {
266     CredHandle creds;
267     CtxtHandle ctx;
268     int partialTokenLen;
269     void * partialToken;
270 };      
271
272 long smb_AuthenticateUserExt(smb_vc_t * vcp, clientchar_t * usern,
273                              char * secBlobIn, int secBlobInLength,
274                              char ** secBlobOut, int * secBlobOutLength) {
275     SECURITY_STATUS status, istatus;
276     CredHandle creds;
277     TimeStamp expiry;
278     long code = 0;
279     SecBufferDesc secBufIn;
280     SecBuffer secTokIn;
281     SecBufferDesc secBufOut;
282     SecBuffer secTokOut;
283     CtxtHandle ctx;
284     struct smb_ext_context * secCtx = NULL;
285     struct smb_ext_context * newSecCtx = NULL;
286     void * assembledBlob = NULL;
287     int assembledBlobLength = 0;
288     ULONG flags;
289
290     OutputDebugF(_C("In smb_AuthenticateUserExt"));
291
292     *secBlobOut = NULL;
293     *secBlobOutLength = 0;
294
295     if (vcp->flags & SMB_VCFLAG_AUTH_IN_PROGRESS) {
296         secCtx = vcp->secCtx;
297         lock_ObtainMutex(&vcp->mx);
298         vcp->flags &= ~SMB_VCFLAG_AUTH_IN_PROGRESS;
299         vcp->secCtx = NULL;
300         lock_ReleaseMutex(&vcp->mx);
301     }
302
303     if (secBlobIn) {
304         OutputDebugF(_C("Received incoming token:"));
305         OutputDebugHexDump(secBlobIn,secBlobInLength);
306     }
307     
308     if (secCtx) {
309         OutputDebugF(_C("Continuing with existing context."));          
310         creds = secCtx->creds;
311         ctx = secCtx->ctx;
312
313         if (secCtx->partialToken) {
314             assembledBlobLength = secCtx->partialTokenLen + secBlobInLength;
315             assembledBlob = malloc(assembledBlobLength);
316             memcpy(assembledBlob,secCtx->partialToken, secCtx->partialTokenLen);
317             memcpy(((BYTE *)assembledBlob) + secCtx->partialTokenLen, secBlobIn, secBlobInLength);
318         }
319     } else {
320         status = AcquireCredentialsHandle( NULL,
321                                            SMB_EXT_SEC_PACKAGE_NAME,
322                                            SECPKG_CRED_INBOUND,
323                                            NULL,
324                                            NULL,
325                                            NULL,
326                                            NULL,
327                                            &creds,
328                                            &expiry);
329
330         if (status != SEC_E_OK) {
331             OutputDebugF(_C("Can't acquire Credentials handle [%lX]"), status);
332             code = CM_ERROR_BADPASSWORD; /* means "try again when I'm sober" */
333             goto aue_0;
334         }
335
336         ctx.dwLower = 0;
337         ctx.dwUpper = 0;
338     }
339
340     secBufIn.cBuffers = 1;
341     secBufIn.pBuffers = &secTokIn;
342     secBufIn.ulVersion = SECBUFFER_VERSION;
343
344     secTokIn.BufferType = SECBUFFER_TOKEN;
345     if (assembledBlob) {
346         secTokIn.cbBuffer = assembledBlobLength;
347         secTokIn.pvBuffer = assembledBlob;
348     } else {
349         secTokIn.cbBuffer = secBlobInLength;
350         secTokIn.pvBuffer = secBlobIn;
351     }
352
353     secBufOut.cBuffers = 1;
354     secBufOut.pBuffers = &secTokOut;
355     secBufOut.ulVersion = SECBUFFER_VERSION;
356
357     secTokOut.BufferType = SECBUFFER_TOKEN;
358     secTokOut.cbBuffer = 0;
359     secTokOut.pvBuffer = NULL;
360
361     status = AcceptSecurityContext( &creds,
362                                     ((secCtx)?&ctx:NULL),
363                                     &secBufIn,
364                                     ASC_REQ_CONNECTION | ASC_REQ_EXTENDED_ERROR | ASC_REQ_ALLOCATE_MEMORY,
365                                     SECURITY_NETWORK_DREP,
366                                     &ctx,
367                                     &secBufOut,
368                                     &flags,
369                                     &expiry
370                                     );
371
372     if (status == SEC_I_COMPLETE_NEEDED || status == SEC_I_COMPLETE_AND_CONTINUE) {
373         OutputDebugF(_C("Completing token..."));
374         istatus = CompleteAuthToken(&ctx, &secBufOut);
375         if ( istatus != SEC_E_OK )
376             OutputDebugF(_C("Token completion failed: %lX"), istatus);
377     }
378
379     if (status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) {
380         OutputDebugF(_C("Continue needed"));
381
382         newSecCtx = malloc(sizeof(*newSecCtx));
383
384         newSecCtx->creds = creds;
385         newSecCtx->ctx = ctx;
386         newSecCtx->partialToken = NULL;
387         newSecCtx->partialTokenLen = 0;
388
389         lock_ObtainMutex( &vcp->mx );
390         vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
391         vcp->secCtx = newSecCtx;
392         lock_ReleaseMutex( &vcp->mx );
393
394         code = CM_ERROR_GSSCONTINUE;
395     }
396
397     if ((status == SEC_I_COMPLETE_NEEDED || status == SEC_E_OK || 
398           status == SEC_I_COMPLETE_AND_CONTINUE || status == SEC_I_CONTINUE_NEEDED) && 
399          secTokOut.pvBuffer) {
400         OutputDebugF(_C("Need to send token back to client"));
401
402         *secBlobOutLength = secTokOut.cbBuffer;
403         *secBlobOut = malloc(secTokOut.cbBuffer);
404         memcpy(*secBlobOut, secTokOut.pvBuffer, secTokOut.cbBuffer);
405
406         OutputDebugF(_C("Outgoing token:"));
407         OutputDebugHexDump(*secBlobOut,*secBlobOutLength);
408     } else if (status == SEC_E_INCOMPLETE_MESSAGE) {
409         OutputDebugF(_C("Incomplete message"));
410
411         newSecCtx = malloc(sizeof(*newSecCtx));
412
413         newSecCtx->creds = creds;
414         newSecCtx->ctx = ctx;
415         newSecCtx->partialToken = malloc(secTokOut.cbBuffer);
416         memcpy(newSecCtx->partialToken, secTokOut.pvBuffer, secTokOut.cbBuffer);
417         newSecCtx->partialTokenLen = secTokOut.cbBuffer;
418
419         lock_ObtainMutex( &vcp->mx );
420         vcp->flags |= SMB_VCFLAG_AUTH_IN_PROGRESS;
421         vcp->secCtx = newSecCtx;
422         lock_ReleaseMutex( &vcp->mx );
423
424         code = CM_ERROR_GSSCONTINUE;
425     }
426
427     if (status == SEC_E_OK || status == SEC_I_COMPLETE_NEEDED) {
428         /* woo hoo! */
429         SecPkgContext_NamesW names;
430
431         OutputDebugF(_C("Authentication completed"));
432         OutputDebugF(_C("Returned flags : [%lX]"), flags);
433
434         if (!QueryContextAttributesW(&ctx, SECPKG_ATTR_NAMES, &names)) {
435             OutputDebugF(_C("Received name [%s]"), names.sUserName);
436             cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, names.sUserName);
437             cm_ClientStrLwr(usern); /* in tandem with smb_GetNormalizedUsername */
438             FreeContextBuffer(names.sUserName);
439         } else {
440             /* Force the user to retry if the context is invalid */
441             OutputDebugF(_C("QueryContextAttributes Names failed [%x]"), GetLastError());
442             code = CM_ERROR_BADPASSWORD; 
443         }
444     } else if (!code) {
445         switch ( status ) {
446         case SEC_E_INVALID_TOKEN:
447             OutputDebugF(_C("Returning bad password :: INVALID_TOKEN"));
448             break;
449         case SEC_E_INVALID_HANDLE:
450             OutputDebugF(_C("Returning bad password :: INVALID_HANDLE"));
451             break;
452         case SEC_E_LOGON_DENIED:
453             OutputDebugF(_C("Returning bad password :: LOGON_DENIED"));
454             break;
455         case SEC_E_UNKNOWN_CREDENTIALS:
456             OutputDebugF(_C("Returning bad password :: UNKNOWN_CREDENTIALS"));
457             break;
458         case SEC_E_NO_CREDENTIALS:
459             OutputDebugF(_C("Returning bad password :: NO_CREDENTIALS"));
460             break;
461         case SEC_E_CONTEXT_EXPIRED:
462             OutputDebugF(_C("Returning bad password :: CONTEXT_EXPIRED"));
463             break;
464         case SEC_E_INCOMPLETE_CREDENTIALS:
465             OutputDebugF(_C("Returning bad password :: INCOMPLETE_CREDENTIALS"));
466             break;
467         case SEC_E_WRONG_PRINCIPAL:
468             OutputDebugF(_C("Returning bad password :: WRONG_PRINCIPAL"));
469             break;
470         case SEC_E_TIME_SKEW:
471             OutputDebugF(_C("Returning bad password :: TIME_SKEW"));
472             break;
473         default:
474             OutputDebugF(_C("Returning bad password :: Status == %lX"), status);
475         }
476         code = CM_ERROR_BADPASSWORD;
477     }
478
479     if (secCtx) {
480         if (secCtx->partialToken) free(secCtx->partialToken);
481         free(secCtx);
482     }
483
484     if (assembledBlob) {
485         free(assembledBlob);
486     }
487
488     if (secTokOut.pvBuffer)
489         FreeContextBuffer(secTokOut.pvBuffer);
490
491     if (code != CM_ERROR_GSSCONTINUE) {
492         DeleteSecurityContext(&ctx);
493         FreeCredentialsHandle(&creds);
494     }
495
496   aue_0:
497     return code;
498 }
499
500 #define P_LEN 256
501 #define P_RESP_LEN 128
502
503 /* LsaLogonUser expects input parameters to be in a contiguous block of memory. 
504    So put stuff in a struct. */
505 struct Lm20AuthBlob {
506     MSV1_0_LM20_LOGON lmlogon;
507     BYTE ciResponse[P_RESP_LEN];    /* Unicode representation */
508     BYTE csResponse[P_RESP_LEN];    /* ANSI representation */
509     WCHAR accountNameW[P_LEN];
510     WCHAR primaryDomainW[P_LEN];
511     WCHAR workstationW[MAX_COMPUTERNAME_LENGTH + 1];
512     TOKEN_GROUPS tgroups;
513     TOKEN_SOURCE tsource;
514 };
515
516 long smb_AuthenticateUserLM(smb_vc_t *vcp, clientchar_t * accountName, clientchar_t * primaryDomain, char * ciPwd, unsigned ciPwdLength, char * csPwd, unsigned csPwdLength) 
517 {
518     NTSTATUS nts, ntsEx;
519     struct Lm20AuthBlob lmAuth;
520     PMSV1_0_LM20_LOGON_PROFILE lmprofilep;
521     QUOTA_LIMITS quotaLimits;
522     DWORD size;
523     ULONG lmprofilepSize;
524     LUID lmSession;
525     HANDLE lmToken;
526
527     OutputDebugF(_C("In smb_AuthenticateUser for user [%s] domain [%s]"), accountName, primaryDomain);
528     OutputDebugF(_C("ciPwdLength is %d and csPwdLength is %d"), ciPwdLength, csPwdLength);
529
530     if (ciPwdLength > P_RESP_LEN || csPwdLength > P_RESP_LEN) {
531         OutputDebugF(_C("ciPwdLength or csPwdLength is too long"));
532         return CM_ERROR_BADPASSWORD;
533     }
534
535     memset(&lmAuth,0,sizeof(lmAuth));
536
537     lmAuth.lmlogon.MessageType = MsV1_0NetworkLogon;
538         
539     lmAuth.lmlogon.LogonDomainName.Buffer = lmAuth.primaryDomainW;
540     cm_ClientStringToUtf16(primaryDomain, -1, lmAuth.primaryDomainW, P_LEN);
541     lmAuth.lmlogon.LogonDomainName.Length = (USHORT)(wcslen(lmAuth.primaryDomainW) * sizeof(WCHAR));
542     lmAuth.lmlogon.LogonDomainName.MaximumLength = P_LEN * sizeof(WCHAR);
543
544     lmAuth.lmlogon.UserName.Buffer = lmAuth.accountNameW;
545     cm_ClientStringToUtf16(accountName, -1, lmAuth.accountNameW, P_LEN);
546     lmAuth.lmlogon.UserName.Length = (USHORT)(wcslen(lmAuth.accountNameW) * sizeof(WCHAR));
547     lmAuth.lmlogon.UserName.MaximumLength = P_LEN * sizeof(WCHAR);
548
549     lmAuth.lmlogon.Workstation.Buffer = lmAuth.workstationW;
550     lmAuth.lmlogon.Workstation.MaximumLength = (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR);
551     size = MAX_COMPUTERNAME_LENGTH + 1;
552     GetComputerNameW(lmAuth.workstationW, &size);
553     lmAuth.lmlogon.Workstation.Length = (USHORT)(wcslen(lmAuth.workstationW) * sizeof(WCHAR));
554
555     memcpy(lmAuth.lmlogon.ChallengeToClient, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
556
557     lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Buffer = lmAuth.ciResponse;
558     lmAuth.lmlogon.CaseInsensitiveChallengeResponse.Length = ciPwdLength;
559     lmAuth.lmlogon.CaseInsensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
560     memcpy(lmAuth.ciResponse, ciPwd, ciPwdLength);
561
562     lmAuth.lmlogon.CaseSensitiveChallengeResponse.Buffer = lmAuth.csResponse;
563     lmAuth.lmlogon.CaseSensitiveChallengeResponse.Length = csPwdLength;
564     lmAuth.lmlogon.CaseSensitiveChallengeResponse.MaximumLength = P_RESP_LEN;
565     memcpy(lmAuth.csResponse, csPwd, csPwdLength);
566
567     lmAuth.lmlogon.ParameterControl = 0;
568
569     lmAuth.tgroups.GroupCount = 0;
570     lmAuth.tgroups.Groups[0].Sid = NULL;
571     lmAuth.tgroups.Groups[0].Attributes = 0;
572
573 #ifdef _WIN64
574     lmAuth.tsource.SourceIdentifier.HighPart = (DWORD)((LONG_PTR)vcp << 32);
575 #else
576     lmAuth.tsource.SourceIdentifier.HighPart = 0;
577 #endif
578     lmAuth.tsource.SourceIdentifier.LowPart = (DWORD)((LONG_PTR)vcp & _UI32_MAX);
579     StringCchCopyA(lmAuth.tsource.SourceName, lengthof(lmAuth.tsource.SourceName),
580                    "OpenAFS"); /* 8 char limit */
581
582     nts = LsaLogonUser( smb_lsaHandle,
583                         &smb_lsaLogonOrigin,
584                         Network, /*3*/
585                         smb_lsaSecPackage,
586                         &lmAuth,
587                         sizeof(lmAuth),
588                         &lmAuth.tgroups,
589                         &lmAuth.tsource,
590                         &lmprofilep,
591                         &lmprofilepSize,
592                         &lmSession,
593                         &lmToken,
594                         &quotaLimits,
595                         &ntsEx);
596
597     if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS)
598         osi_Log2(smb_logp,"LsaLogonUser failure: nts %u ntsEx %u",
599                   nts, ntsEx);
600
601     OutputDebugF(_C("Return from LsaLogonUser is 0x%lX"), nts);
602     OutputDebugF(_C("Extended status is 0x%lX"), ntsEx);
603
604     if (nts == ERROR_SUCCESS) {
605         /* free the token */
606         LsaFreeReturnBuffer(lmprofilep);
607         CloseHandle(lmToken);
608         return 0;
609     } else {
610         /* No AFS for you */
611         if (nts == 0xC000015BL)
612             return CM_ERROR_BADLOGONTYPE;
613         else /* our catchall is a bad password though we could be more specific */
614             return CM_ERROR_BADPASSWORD;
615     }       
616 }
617
618 /* The buffer pointed to by usern is assumed to be at least SMB_MAX_USERNAME_LENGTH bytes */
619 long smb_GetNormalizedUsername(clientchar_t * usern, const clientchar_t * accountName, const clientchar_t * domainName) 
620 {
621     clientchar_t * atsign;
622     const clientchar_t * domain;
623
624     /* check if we have sane input */
625     if ((cm_ClientStrLen(accountName) + cm_ClientStrLen(domainName) + 1) > SMB_MAX_USERNAME_LENGTH)
626         return 1;
627
628     /* we could get : [accountName][domainName]
629        [user][domain]
630        [user@domain][]
631        [user][]/[user][?]
632        [][]/[][?] */
633
634     atsign = cm_ClientStrChr(accountName, '@');
635
636     if (atsign) /* [user@domain][] -> [user@domain][domain] */
637         domain = atsign + 1;
638     else
639         domain = domainName;
640
641     /* if for some reason the client doesn't know what domain to use,
642        it will either return an empty string or a '?' */
643     if (!domain[0] || domain[0] == '?')
644         /* Empty domains and empty usernames are usually sent from tokenless contexts.
645            This way such logins will get an empty username (easy to check).  I don't know 
646            when a non-empty username would be supplied with an anonymous domain, but *shrug* */
647         cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, accountName);
648     else {
649         /* TODO: what about WIN.MIT.EDU\user vs. WIN\user? */
650         cm_ClientStrCpy(usern, SMB_MAX_USERNAME_LENGTH, domain);
651         cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, _C("\\"));
652         if (atsign)
653             cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
654         else
655             cm_ClientStrCat(usern, SMB_MAX_USERNAME_LENGTH, accountName);
656     }
657
658     cm_ClientStrLwr(usern);
659
660     return 0;
661 }
662
663 /* When using SMB auth, all SMB sessions have to pass through here
664  * first to authenticate the user.  
665  *
666  * Caveat: If not using SMB auth, the protocol does not require
667  * sending a session setup packet, which means that we can't rely on a
668  * UID in subsequent packets.  Though in practice we get one anyway.
669  */
670 /* SMB_COM_SESSION_SETUP_ANDX */
671 long smb_ReceiveV3SessionSetupX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
672 {
673     char *tp;
674     smb_user_t *uidp;
675     unsigned short newUid;
676     unsigned long caps = 0;
677     smb_username_t *unp;
678     clientchar_t *s1 = _C(" ");
679     long code = 0; 
680     clientchar_t usern[SMB_MAX_USERNAME_LENGTH];
681     char *secBlobOut = NULL;
682     int  secBlobOutLength = 0;
683     int  maxBufferSize = 0;
684     int  maxMpxCount = 0;
685     int  vcNumber = 0;
686
687     /* Check for bad conns */
688     if (vcp->flags & SMB_VCFLAG_REMOTECONN)
689         return CM_ERROR_REMOTECONN;
690
691     /* maxBufferSize */
692     maxBufferSize = smb_GetSMBParm(inp, 2);
693     maxMpxCount = smb_GetSMBParm(inp, 3);
694     vcNumber = smb_GetSMBParm(inp, 4);
695
696     osi_Log3(smb_logp, "SESSION_SETUP_ANDX with MaxBufferSize=%d, MaxMpxCount=%d, VCNumber=%d",
697              maxBufferSize, maxMpxCount, vcNumber);
698
699     if (maxMpxCount > smb_maxMpxRequests) {
700         LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_MPX_COUNT, maxMpxCount, smb_maxMpxRequests);
701         osi_Log2(smb_logp, "MaxMpxCount for client is too large (Client=%d, Server=%d)",
702                  maxMpxCount, smb_maxMpxRequests);
703     }
704
705     if (maxBufferSize < SMB_PACKETSIZE) {
706         LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_MAX_BUFFER_SIZE, maxBufferSize, SMB_PACKETSIZE);
707         osi_Log2(smb_logp, "MaxBufferSize for client is too small (Client=%d, Server=%d)",
708                  maxBufferSize, SMB_PACKETSIZE);
709     }
710
711     if (vcNumber == 0) {
712         osi_Log0(smb_logp, "Resetting all VCs");
713         smb_MarkAllVCsDead(vcp);
714     }
715
716     if (vcp->flags & SMB_VCFLAG_USENT) {
717         if (smb_authType == SMB_AUTH_EXTENDED) {
718             /* extended authentication */
719             char *secBlobIn;
720             int secBlobInLength;
721
722             OutputDebugF(_C("NT Session Setup: Extended"));
723         
724             if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
725                 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
726             }
727
728             secBlobInLength = smb_GetSMBParm(inp, 7);
729             secBlobIn = smb_GetSMBData(inp, NULL);
730
731             code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
732
733             if (code == CM_ERROR_GSSCONTINUE) {
734                 size_t cb_data = 0;
735
736                 smb_SetSMBParm(outp, 2, 0);
737                 smb_SetSMBParm(outp, 3, secBlobOutLength);
738
739                 tp = smb_GetSMBData(outp, NULL);
740                 if (secBlobOutLength) {
741                     memcpy(tp, secBlobOut, secBlobOutLength);
742                     free(secBlobOut);
743                     tp += secBlobOutLength;
744                     cb_data += secBlobOutLength;
745                 }       
746                 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
747                 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
748                 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
749
750                 smb_SetSMBDataLength(outp, cb_data);
751             }
752
753             /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
754         } else {
755             unsigned ciPwdLength, csPwdLength;
756             char *ciPwd, *csPwd;
757             clientchar_t *accountName;
758             clientchar_t *primaryDomain;
759             int  datalen;
760
761             if (smb_authType == SMB_AUTH_NTLM)
762                 OutputDebugF(_C("NT Session Setup: NTLM"));
763             else
764                 OutputDebugF(_C("NT Session Setup: None"));
765
766             /* TODO: parse for extended auth as well */
767             ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
768             csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
769
770             tp = smb_GetSMBData(inp, &datalen);
771
772             OutputDebugF(_C("Session packet data size [%d]"),datalen);
773
774             ciPwd = tp;
775             tp += ciPwdLength;
776             csPwd = tp;
777             tp += csPwdLength;
778
779             accountName = smb_ParseString(inp, tp, &tp, 0);
780             primaryDomain = smb_ParseString(inp, tp, NULL, 0);
781
782             OutputDebugF(_C("Account Name: %s"),accountName);
783             OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
784             OutputDebugF(_C("Case Sensitive Password: %s"),
785                          csPwd && csPwd[0] ? _C("yes") : _C("no"));
786             OutputDebugF(_C("Case Insensitive Password: %s"),
787                          ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
788
789             if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
790                 /* shouldn't happen */
791                 code = CM_ERROR_BADSMB;
792                 goto after_read_packet;
793             }
794
795             /* capabilities are only valid for first session packet */
796             if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
797                 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
798             }
799
800             if (smb_authType == SMB_AUTH_NTLM) {
801                 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
802                 if ( code )
803                     OutputDebugF(_C("LM authentication failed [%d]"), code);
804                 else
805                     OutputDebugF(_C("LM authentication succeeded"));
806             }
807         }
808     }  else { /* V3 */
809         unsigned ciPwdLength;
810         char *ciPwd;
811         clientchar_t *accountName;
812         clientchar_t *primaryDomain;
813
814         switch ( smb_authType ) {
815         case SMB_AUTH_EXTENDED:
816             OutputDebugF(_C("V3 Session Setup: Extended"));
817             break;
818         case SMB_AUTH_NTLM:
819             OutputDebugF(_C("V3 Session Setup: NTLM"));
820             break;
821         default:
822             OutputDebugF(_C("V3 Session Setup: None"));
823         }
824         ciPwdLength = smb_GetSMBParm(inp, 7);
825         tp = smb_GetSMBData(inp, NULL);
826         ciPwd = tp;
827         tp += ciPwdLength;
828
829         accountName = smb_ParseString(inp, tp, &tp, 0);
830         primaryDomain = smb_ParseString(inp, tp, NULL, 0);
831
832         OutputDebugF(_C("Account Name: %s"),accountName);
833         OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
834         OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
835
836         if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
837             /* shouldn't happen */
838             code = CM_ERROR_BADSMB;
839             goto after_read_packet;
840         }
841
842         /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
843          * to NTLM.
844          */
845         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
846             code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
847             if ( code )
848                 OutputDebugF(_C("LM authentication failed [%d]"), code);
849             else
850                 OutputDebugF(_C("LM authentication succeeded"));
851         }
852     }
853
854   after_read_packet:
855     /* note down that we received a session setup X and set the capabilities flag */
856     if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
857         lock_ObtainMutex(&vcp->mx);
858         vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
859         /* for the moment we can only deal with NTSTATUS */
860         if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
861             vcp->flags |= SMB_VCFLAG_STATUS32;
862         }       
863
864 #ifdef SMB_UNICODE
865         if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
866             vcp->flags |= SMB_VCFLAG_USEUNICODE;
867         }
868 #endif
869         lock_ReleaseMutex(&vcp->mx);
870     }
871
872     /* code would be non-zero if there was an authentication failure.
873        Ideally we would like to invalidate the uid for this session or break
874        early to avoid accidently stealing someone else's tokens. */
875
876     if (code) {
877         return code;
878     }
879
880     OutputDebugF(_C("Received username=[%s]"), usern);
881
882     /* On Windows 2000, this function appears to be called more often than
883        it is expected to be called. This resulted in multiple smb_user_t
884        records existing all for the same user session which results in all
885        of the users tokens disappearing.
886
887        To avoid this problem, we look for an existing smb_user_t record
888        based on the users name, and use that one if we find it.
889     */
890
891     uidp = smb_FindUserByNameThisSession(vcp, usern);
892     if (uidp) {   /* already there, so don't create a new one */
893         unp = uidp->unp;
894         newUid = uidp->userID;
895         osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
896                  vcp->lana,vcp->lsn,newUid);
897         smb_ReleaseUID(uidp);
898     }
899     else {
900         cm_user_t *userp;
901
902         /* do a global search for the username/machine name pair */
903         unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
904         lock_ObtainMutex(&unp->mx);
905         if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
906             /* clear the afslogon flag so that the tickets can now 
907              * be freed when the refCount returns to zero.
908              */
909             unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
910         }
911         lock_ReleaseMutex(&unp->mx);
912
913         /* Create a new UID and cm_user_t structure */
914         userp = unp->userp;
915         if (!userp)
916             userp = cm_NewUser();
917         cm_HoldUserVCRef(userp);
918         lock_ObtainMutex(&vcp->mx);
919         if (!vcp->uidCounter)
920             vcp->uidCounter++; /* handle unlikely wraparounds */
921         newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
922         lock_ReleaseMutex(&vcp->mx);
923
924         /* Create a new smb_user_t structure and connect them up */
925         lock_ObtainMutex(&unp->mx);
926         unp->userp = userp;
927         lock_ReleaseMutex(&unp->mx);
928
929         uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
930         if (uidp) {
931             lock_ObtainMutex(&uidp->mx);
932             uidp->unp = unp;
933             osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
934             lock_ReleaseMutex(&uidp->mx);
935             smb_ReleaseUID(uidp);
936         }
937     }
938
939     /* Return UID to the client */
940     ((smb_t *)outp)->uid = newUid;
941     /* Also to the next chained message */
942     ((smb_t *)inp)->uid = newUid;
943
944     osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
945              osi_LogSaveClientString(smb_logp, usern), newUid,
946              osi_LogSaveClientString(smb_logp, s1));
947
948     smb_SetSMBParm(outp, 2, 0);
949
950     if (vcp->flags & SMB_VCFLAG_USENT) {
951         if (smb_authType == SMB_AUTH_EXTENDED) {
952             size_t cb_data = 0;
953
954             smb_SetSMBParm(outp, 3, secBlobOutLength);
955
956             tp = smb_GetSMBData(outp, NULL);
957             if (secBlobOutLength) {
958                 memcpy(tp, secBlobOut, secBlobOutLength);
959                 free(secBlobOut);
960                 tp += secBlobOutLength;
961                 cb_data +=  secBlobOutLength;
962             }   
963
964             tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
965             tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
966             tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
967
968             smb_SetSMBDataLength(outp, cb_data);
969         } else {
970             smb_SetSMBDataLength(outp, 0);
971         }
972     } else {
973         if (smb_authType == SMB_AUTH_EXTENDED) {
974             size_t cb_data = 0;
975
976             tp = smb_GetSMBData(outp, NULL);
977
978             tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
979             tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
980             tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
981
982             smb_SetSMBDataLength(outp, cb_data);
983         } else {
984             smb_SetSMBDataLength(outp, 0);
985         }
986     }
987
988     return 0;
989 }
990
991 /* SMB_COM_LOGOFF_ANDX */
992 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
993 {
994     smb_user_t *uidp;
995
996     /* find the tree and free it */
997     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
998     if (uidp) {
999         smb_username_t * unp;
1000
1001         osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1002                  osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1003
1004         lock_ObtainMutex(&uidp->mx);
1005         uidp->flags |= SMB_USERFLAG_DELETE;
1006         /*
1007          * it doesn't get deleted right away
1008          * because the vcp points to it
1009          */
1010         unp = uidp->unp;
1011         lock_ReleaseMutex(&uidp->mx);
1012
1013 #ifdef COMMENT
1014         /* we can't do this.  we get logoff messages prior to a session
1015          * disconnect even though it doesn't mean the user is logging out.
1016          * we need to create a new pioctl and EventLogoff handler to set
1017          * SMB_USERNAMEFLAG_LOGOFF.
1018          */
1019         if (unp && smb_LogoffTokenTransfer) {
1020             lock_ObtainMutex(&unp->mx);
1021             unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1022             unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1023             lock_ReleaseMutex(&unp->mx);
1024         }
1025 #endif
1026
1027         smb_ReleaseUID(uidp);
1028     }
1029     else    
1030         osi_Log0(smb_logp, "SMB3 user logoffX");
1031
1032     smb_SetSMBDataLength(outp, 0);
1033     return 0;
1034 }
1035
1036 #define SMB_SUPPORT_SEARCH_BITS        0x0001
1037 #define SMB_SHARE_IS_IN_DFS            0x0002
1038
1039 /* SMB_COM_TREE_CONNECT_ANDX */
1040 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1041 {
1042     smb_tid_t *tidp;
1043     smb_user_t *uidp = NULL;
1044     unsigned short newTid;
1045     clientchar_t shareName[AFSPATHMAX];
1046     clientchar_t *sharePath;
1047     int shareFound;
1048     char *tp;
1049     clientchar_t *slashp;
1050     clientchar_t *pathp;
1051     clientchar_t *passwordp;
1052     clientchar_t *servicep;
1053     cm_user_t *userp = NULL;
1054     int ipc = 0;
1055         
1056     osi_Log0(smb_logp, "SMB3 receive tree connect");
1057
1058     /* parse input parameters */
1059     tp = smb_GetSMBData(inp, NULL);
1060     passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1061     pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1062     servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1063
1064     slashp = cm_ClientStrRChr(pathp, '\\');
1065     if (!slashp) {
1066         return CM_ERROR_BADSMB;
1067     }
1068     cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1069
1070     osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1071              osi_LogSaveClientString(smb_logp, pathp),
1072              osi_LogSaveClientString(smb_logp, shareName),
1073              osi_LogSaveClientString(smb_logp, servicep));
1074
1075     if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1076         cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1077 #ifndef NO_IPC
1078         osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1079         ipc = 1;
1080 #else
1081         return CM_ERROR_NOIPC;
1082 #endif
1083     }
1084
1085     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1086     if (uidp)
1087         userp = smb_GetUserFromUID(uidp);
1088
1089     lock_ObtainMutex(&vcp->mx);
1090     newTid = vcp->tidCounter++;
1091     lock_ReleaseMutex(&vcp->mx);
1092         
1093     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1094
1095     if (!ipc) {
1096         if (!cm_ClientStrCmp(shareName, _C("*.")))
1097             cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1098         shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1099         if (!shareFound) {
1100             if (uidp)
1101                 smb_ReleaseUID(uidp);
1102             smb_ReleaseTID(tidp, FALSE);
1103             return CM_ERROR_BADSHARENAME;
1104         }
1105
1106         if (vcp->flags & SMB_VCFLAG_USENT)
1107         {
1108             int policy = smb_FindShareCSCPolicy(shareName);
1109             HKEY parmKey;
1110             DWORD code;
1111             DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1112
1113             code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1114                                  0, KEY_QUERY_VALUE, &parmKey);
1115             if (code == ERROR_SUCCESS) {
1116                 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1117                                        (BYTE *)&dwAdvertiseDFS, &dwSize);
1118                 if (code != ERROR_SUCCESS)
1119                     dwAdvertiseDFS = 0;
1120                 RegCloseKey (parmKey);
1121             }
1122             smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | 
1123                            (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1124                            (policy << 2));
1125         }
1126     } else {
1127         smb_SetSMBParm(outp, 2, 0);
1128         sharePath = NULL;
1129     }
1130     if (uidp)
1131         smb_ReleaseUID(uidp);
1132
1133     lock_ObtainMutex(&tidp->mx);
1134     tidp->userp = userp;
1135     tidp->pathname = sharePath;
1136     if (ipc) 
1137         tidp->flags |= SMB_TIDFLAG_IPC;
1138     lock_ReleaseMutex(&tidp->mx);
1139     smb_ReleaseTID(tidp, FALSE);
1140
1141     ((smb_t *)outp)->tid = newTid;
1142     ((smb_t *)inp)->tid = newTid;
1143     tp = smb_GetSMBData(outp, NULL);
1144     if (!ipc) {
1145         size_t cb_data = 0;
1146
1147         tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1148         tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1149         smb_SetSMBDataLength(outp, cb_data);
1150     } else {
1151         size_t cb_data = 0;
1152
1153         tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1154         smb_SetSMBDataLength(outp, cb_data);
1155     }
1156
1157     osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1158     return 0;
1159 }
1160
1161 /* must be called with global tran lock held */
1162 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1163 {
1164     smb_tran2Packet_t *tp;
1165     smb_t *smbp;
1166         
1167     smbp = (smb_t *) inp->data;
1168     for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1169         if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1170             return tp;
1171     }
1172     return NULL;
1173 }
1174
1175 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1176                                       int totalParms, int totalData)
1177 {
1178     smb_tran2Packet_t *tp;
1179     smb_t *smbp;
1180         
1181     smbp = (smb_t *) inp->data;
1182     tp = malloc(sizeof(*tp));
1183     memset(tp, 0, sizeof(*tp));
1184     tp->vcp = vcp;
1185     smb_HoldVC(vcp);
1186     tp->curData = tp->curParms = 0;
1187     tp->totalData = totalData;
1188     tp->totalParms = totalParms;
1189     tp->tid = smbp->tid;
1190     tp->mid = smbp->mid;
1191     tp->uid = smbp->uid;
1192     tp->pid = smbp->pid;
1193     tp->res[0] = smbp->res[0];
1194     osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1195     if (totalParms != 0)
1196         tp->parmsp = malloc(totalParms);
1197     if (totalData != 0)
1198         tp->datap = malloc(totalData);
1199     if (smbp->com == 0x25 || smbp->com == 0x26)
1200         tp->com = 0x25;
1201     else {
1202         tp->opcode = smb_GetSMBParm(inp, 14);
1203         tp->com = 0x32;
1204     }
1205     tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1206 #ifdef SMB_UNICODE
1207     if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1208         tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1209 #endif
1210     return tp;
1211 }
1212
1213 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1214                                               smb_tran2Packet_t *inp, smb_packet_t *outp,
1215                                               int totalParms, int totalData)  
1216 {
1217     smb_tran2Packet_t *tp;
1218     unsigned short parmOffset;
1219     unsigned short dataOffset;
1220     unsigned short dataAlign;
1221
1222     tp = malloc(sizeof(*tp));
1223     memset(tp, 0, sizeof(*tp));
1224     smb_HoldVC(vcp);
1225     tp->vcp = vcp;
1226     tp->curData = tp->curParms = 0;
1227     tp->totalData = totalData;
1228     tp->totalParms = totalParms;
1229     tp->oldTotalParms = totalParms;
1230     tp->tid = inp->tid;
1231     tp->mid = inp->mid;
1232     tp->uid = inp->uid;
1233     tp->pid = inp->pid;
1234     tp->res[0] = inp->res[0];
1235     tp->opcode = inp->opcode;
1236     tp->com = inp->com;
1237
1238     /*
1239      * We calculate where the parameters and data will start.
1240      * This calculation must parallel the calculation in
1241      * smb_SendTran2Packet.
1242      */
1243
1244     parmOffset = 10*2 + 35;
1245     parmOffset++;                       /* round to even */
1246     tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1247
1248     dataOffset = parmOffset + totalParms;
1249     dataAlign = dataOffset & 2; /* quad-align */
1250     dataOffset += dataAlign;
1251     tp->datap = outp->data + dataOffset;
1252
1253     return tp;
1254 }       
1255
1256 /* free a tran2 packet */
1257 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1258 {
1259     if (t2p->vcp) {
1260         smb_ReleaseVC(t2p->vcp);
1261         t2p->vcp = NULL;
1262     }
1263     if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1264         if (t2p->parmsp)
1265             free(t2p->parmsp);
1266         if (t2p->datap)
1267             free(t2p->datap);
1268     }       
1269     while (t2p->stringsp) {
1270         cm_space_t * ns;
1271
1272         ns = t2p->stringsp;
1273         t2p->stringsp = ns->nextp;
1274         cm_FreeSpace(ns);
1275     }
1276     free(t2p);
1277 }
1278
1279 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1280                                     char ** chainpp, int flags)
1281 {
1282     size_t cb;
1283
1284 #ifdef SMB_UNICODE
1285     if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1286         flags |= SMB_STRF_FORCEASCII;
1287 #endif
1288
1289     cb = p->totalParms - (inp - (char *)p->parmsp);
1290     if (inp < (char *) p->parmsp ||
1291         inp >= ((char *) p->parmsp) + p->totalParms) {
1292 #ifdef DEBUG_UNICODE
1293         DebugBreak();
1294 #endif
1295         cb = p->totalParms;
1296     }
1297
1298     return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1299                               inp, &cb, chainpp, flags);
1300 }
1301
1302 /* called with a VC, an input packet to respond to, and an error code.
1303  * sends an error response.
1304  */
1305 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1306                         smb_packet_t *tp, long code)
1307 {
1308     smb_t *smbp;
1309     unsigned short errCode;
1310     unsigned char errClass;
1311     unsigned long NTStatus;
1312
1313     if (vcp->flags & SMB_VCFLAG_STATUS32)
1314         smb_MapNTError(code, &NTStatus);
1315     else
1316         smb_MapCoreError(code, vcp, &errCode, &errClass);
1317
1318     smb_FormatResponsePacket(vcp, NULL, tp);
1319     smbp = (smb_t *) tp;
1320
1321     /* We can handle long names */
1322     if (vcp->flags & SMB_VCFLAG_USENT)
1323         smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1324         
1325     /* now copy important fields from the tran 2 packet */
1326     smbp->com = t2p->com;
1327     smbp->tid = t2p->tid;
1328     smbp->mid = t2p->mid;
1329     smbp->pid = t2p->pid;
1330     smbp->uid = t2p->uid;
1331     smbp->res[0] = t2p->res[0];
1332     if (vcp->flags & SMB_VCFLAG_STATUS32) {
1333         smbp->rcls = (unsigned char) (NTStatus & 0xff);
1334         smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1335         smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1336         smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1337         smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1338     }
1339     else {
1340         smbp->rcls = errClass;
1341         smbp->errLow = (unsigned char) (errCode & 0xff);
1342         smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1343     }
1344         
1345     /* send packet */
1346     smb_SendPacket(vcp, tp);
1347 }        
1348
1349 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1350 {
1351     smb_t *smbp;
1352     unsigned short parmOffset;
1353     unsigned short dataOffset;
1354     unsigned short totalLength;
1355     unsigned short dataAlign;
1356     char *datap;
1357
1358     smb_FormatResponsePacket(vcp, NULL, tp);
1359     smbp = (smb_t *) tp;
1360
1361     /* We can handle long names */
1362     if (vcp->flags & SMB_VCFLAG_USENT)
1363         smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1364
1365     /* now copy important fields from the tran 2 packet */
1366     smbp->com = t2p->com;
1367     smbp->tid = t2p->tid;
1368     smbp->mid = t2p->mid;
1369     smbp->pid = t2p->pid;
1370     smbp->uid = t2p->uid;
1371     smbp->res[0] = t2p->res[0];
1372
1373     totalLength = 1 + t2p->totalData + t2p->totalParms;
1374
1375     /* now add the core parameters (tran2 info) to the packet */
1376     smb_SetSMBParm(tp, 0, t2p->totalParms);     /* parm bytes */
1377     smb_SetSMBParm(tp, 1, t2p->totalData);      /* data bytes */
1378     smb_SetSMBParm(tp, 2, 0);           /* reserved */
1379     smb_SetSMBParm(tp, 3, t2p->totalParms);     /* parm bytes in this packet */
1380     parmOffset = 10*2 + 35;                     /* parm offset in packet */
1381     parmOffset++;                               /* round to even */
1382     smb_SetSMBParm(tp, 4, parmOffset);  /* 11 parm words plus *
1383     * hdr, bcc and wct */
1384     smb_SetSMBParm(tp, 5, 0);           /* parm displacement */
1385     smb_SetSMBParm(tp, 6, t2p->totalData);      /* data in this packet */
1386     dataOffset = parmOffset + t2p->oldTotalParms;
1387     dataAlign = dataOffset & 2;         /* quad-align */
1388     dataOffset += dataAlign;
1389     smb_SetSMBParm(tp, 7, dataOffset);  /* offset of data */
1390     smb_SetSMBParm(tp, 8, 0);           /* data displacement */
1391     smb_SetSMBParm(tp, 9, 0);           /* low: setup word count *
1392                                          * high: resvd */
1393
1394     datap = smb_GetSMBData(tp, NULL);
1395     *datap++ = 0;                               /* we rounded to even */
1396
1397     totalLength += dataAlign;
1398     smb_SetSMBDataLength(tp, totalLength);
1399         
1400     /* next, send the datagram */
1401     smb_SendPacket(vcp, tp);
1402 }   
1403
1404
1405 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1406 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1407 {
1408     smb_tran2Packet_t *asp;
1409     int totalParms;
1410     int totalData;
1411     int parmDisp;
1412     int dataDisp;
1413     int parmOffset;
1414     int dataOffset;
1415     int parmCount;
1416     int dataCount;
1417     int firstPacket;
1418     int rapOp;
1419     long code = 0;
1420
1421     /* We sometimes see 0 word count.  What to do? */
1422     if (*inp->wctp == 0) {
1423         osi_Log0(smb_logp, "Transaction2 word count = 0"); 
1424         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1425
1426         smb_SetSMBDataLength(outp, 0);
1427         smb_SendPacket(vcp, outp);
1428         return 0;
1429     }
1430
1431     totalParms = smb_GetSMBParm(inp, 0);
1432     totalData = smb_GetSMBParm(inp, 1);
1433         
1434     firstPacket = (inp->inCom == 0x25);
1435         
1436     /* find the packet we're reassembling */
1437     lock_ObtainWrite(&smb_globalLock);
1438     asp = smb_FindTran2Packet(vcp, inp);
1439     if (!asp) {
1440         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1441     }
1442     lock_ReleaseWrite(&smb_globalLock);
1443         
1444     /* now merge in this latest packet; start by looking up offsets */
1445     if (firstPacket) {
1446         parmDisp = dataDisp = 0;
1447         parmOffset = smb_GetSMBParm(inp, 10);
1448         dataOffset = smb_GetSMBParm(inp, 12);
1449         parmCount = smb_GetSMBParm(inp, 9);
1450         dataCount = smb_GetSMBParm(inp, 11);
1451         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1452         asp->maxReturnData = smb_GetSMBParm(inp, 3);
1453
1454         osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1455                   totalData, dataCount, asp->maxReturnData);
1456     }
1457     else {
1458         parmDisp = smb_GetSMBParm(inp, 4);
1459         parmOffset = smb_GetSMBParm(inp, 3);
1460         dataDisp = smb_GetSMBParm(inp, 7);
1461         dataOffset = smb_GetSMBParm(inp, 6);
1462         parmCount = smb_GetSMBParm(inp, 2);
1463         dataCount = smb_GetSMBParm(inp, 5);
1464
1465         osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1466                  parmCount, dataCount);
1467     }   
1468
1469     /* now copy the parms and data */
1470     if ( asp->totalParms > 0 && parmCount != 0 )
1471     {
1472         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1473     }
1474     if ( asp->totalData > 0 && dataCount != 0 ) {
1475         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1476     }
1477
1478     /* account for new bytes */
1479     asp->curData += dataCount;
1480     asp->curParms += parmCount;
1481
1482     /* finally, if we're done, remove the packet from the queue and dispatch it */
1483     if (asp->totalParms > 0 &&
1484         asp->curParms > 0 &&
1485         asp->totalData <= asp->curData &&
1486         asp->totalParms <= asp->curParms) {
1487         /* we've received it all */
1488         lock_ObtainWrite(&smb_globalLock);
1489         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1490         lock_ReleaseWrite(&smb_globalLock);
1491
1492         /* now dispatch it */
1493         rapOp = asp->parmsp[0];
1494
1495         if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1496             osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1497             code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1498             osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return  code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1499         }
1500         else {
1501             osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1502             code = CM_ERROR_BADOP;
1503         }
1504
1505         /* if an error is returned, we're supposed to send an error packet,
1506          * otherwise the dispatched function already did the data sending.
1507          * We give dispatched proc the responsibility since it knows how much
1508          * space to allocate.
1509          */
1510         if (code != 0) {
1511             smb_SendTran2Error(vcp, asp, outp, code);
1512         }
1513
1514         /* free the input tran 2 packet */
1515         smb_FreeTran2Packet(asp);
1516     }
1517     else if (firstPacket) {
1518         /* the first packet in a multi-packet request, we need to send an
1519          * ack to get more data.
1520          */
1521         smb_SetSMBDataLength(outp, 0);
1522         smb_SendPacket(vcp, outp);
1523     }
1524
1525     return 0;
1526 }
1527
1528 /* ANSI versions. */
1529
1530 #pragma pack(push, 1)
1531
1532 typedef struct smb_rap_share_info_0 {
1533     BYTE                shi0_netname[13];
1534 } smb_rap_share_info_0_t;
1535
1536 typedef struct smb_rap_share_info_1 {
1537     BYTE                shi1_netname[13];
1538     BYTE                shi1_pad;
1539     WORD                        shi1_type;
1540     DWORD                       shi1_remark; /* char *shi1_remark; data offset */
1541 } smb_rap_share_info_1_t;
1542
1543 typedef struct smb_rap_share_info_2 {
1544     BYTE                shi2_netname[13];
1545     BYTE                shi2_pad;
1546     WORD                shi2_type;
1547     DWORD                       shi2_remark; /* char *shi2_remark; data offset */
1548     WORD                shi2_permissions;
1549     WORD                shi2_max_uses;
1550     WORD                shi2_current_uses;
1551     DWORD                       shi2_path;  /* char *shi2_path; data offset */
1552     WORD                shi2_passwd[9];
1553     WORD                shi2_pad2;
1554 } smb_rap_share_info_2_t;
1555
1556 #define SMB_RAP_MAX_SHARES 512
1557
1558 typedef struct smb_rap_share_list {
1559     int cShare;
1560     int maxShares;
1561     smb_rap_share_info_0_t * shares;
1562 } smb_rap_share_list_t;
1563
1564 #pragma pack(pop)
1565
1566 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1567     smb_rap_share_list_t * sp;
1568
1569     if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1570         return 0; /* skip over '.' and '..' */
1571
1572     sp = (smb_rap_share_list_t *) vrockp;
1573
1574     strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1575     sp->shares[sp->cShare].shi0_netname[12] = 0;
1576
1577     sp->cShare++;
1578
1579     if (sp->cShare >= sp->maxShares)
1580         return CM_ERROR_STOPNOW;
1581     else
1582         return 0;
1583 }       
1584
1585 /* RAP NetShareEnumRequest */
1586 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1587 {
1588     smb_tran2Packet_t *outp;
1589     unsigned short * tp;
1590     int len;
1591     int infoLevel;
1592     int bufsize;
1593     int outParmsTotal;  /* total parameter bytes */
1594     int outDataTotal;   /* total data bytes */
1595     int code = 0;
1596     DWORD rv;
1597     DWORD allSubmount = 0;
1598     USHORT nShares = 0;
1599     DWORD nRegShares = 0;
1600     DWORD nSharesRet = 0;
1601     HKEY hkParam;
1602     HKEY hkSubmount = NULL;
1603     smb_rap_share_info_1_t * shares;
1604     USHORT cshare = 0;
1605     char * cstrp;
1606     clientchar_t thisShare[AFSPATHMAX];
1607     int i,j;
1608     DWORD dw;
1609     int nonrootShares;
1610     smb_rap_share_list_t rootShares;
1611     cm_req_t req;
1612     cm_user_t * userp;
1613     osi_hyper_t thyper;
1614
1615     tp = p->parmsp + 1; /* skip over function number (always 0) */
1616
1617     {
1618         clientchar_t * cdescp;
1619
1620         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1621         if (cm_ClientStrCmp(cdescp,  _C("WrLeh")))
1622             return CM_ERROR_INVAL;
1623         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1624         if (cm_ClientStrCmp(cdescp,  _C("B13BWz")))
1625             return CM_ERROR_INVAL;
1626     }
1627
1628     infoLevel = tp[0];
1629     bufsize = tp[1];
1630
1631     if (infoLevel != 1) {
1632         return CM_ERROR_INVAL;
1633     }
1634
1635     /* We are supposed to use the same ASCII data structure even if
1636        Unicode is negotiated, which ultimately means that the share
1637        names that we return must be at most 13 characters in length,
1638        including the NULL terminator.
1639
1640        The RAP specification states that shares with names longer than
1641        12 characters should not be included in the enumeration.
1642        However, since we support prefix cell references and since many
1643        cell names are going to exceed 12 characters, we lie and send
1644        the first 12 characters.
1645     */
1646
1647     /* first figure out how many shares there are */
1648     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1649                       KEY_QUERY_VALUE, &hkParam);
1650     if (rv == ERROR_SUCCESS) {
1651         len = sizeof(allSubmount);
1652         rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1653                              (BYTE *) &allSubmount, &len);
1654         if (rv != ERROR_SUCCESS || allSubmount != 0) {
1655             allSubmount = 1;
1656         }
1657         RegCloseKey (hkParam);
1658     }
1659
1660     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1661                       0, KEY_QUERY_VALUE, &hkSubmount);
1662     if (rv == ERROR_SUCCESS) {
1663         rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1664                              NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1665         if (rv != ERROR_SUCCESS)
1666             nRegShares = 0;
1667     } else {
1668         hkSubmount = NULL;
1669     }
1670
1671     /* fetch the root shares */
1672     rootShares.maxShares = SMB_RAP_MAX_SHARES;
1673     rootShares.cShare = 0;
1674     rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1675
1676     smb_InitReq(&req);
1677
1678     userp = smb_GetTran2User(vcp,p);
1679
1680     thyper.HighPart = 0;
1681     thyper.LowPart = 0;
1682
1683     cm_HoldSCache(cm_data.rootSCachep);
1684     cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1685     cm_ReleaseSCache(cm_data.rootSCachep);
1686
1687     cm_ReleaseUser(userp);
1688
1689     nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1690
1691 #define REMARK_LEN 1
1692     outParmsTotal = 8; /* 4 dwords */
1693     outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1694     if(outDataTotal > bufsize) {
1695         nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1696         outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1697     }
1698     else {
1699         nSharesRet = nShares;
1700     }
1701     
1702     outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1703
1704     /* now for the submounts */
1705     shares = (smb_rap_share_info_1_t *) outp->datap;
1706     cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1707
1708     memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1709
1710     if (allSubmount) {
1711         StringCchCopyA(shares[cshare].shi1_netname,
1712                        lengthof(shares[cshare].shi1_netname), "all" );
1713         shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1714         /* type and pad are zero already */
1715         cshare++;
1716         cstrp+=REMARK_LEN;
1717     }
1718
1719     if (hkSubmount) {
1720         for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1721             len = sizeof(thisShare);
1722             rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1723             if (rv == ERROR_SUCCESS &&
1724                 cm_ClientStrLen(thisShare) &&
1725                 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
1726                 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
1727                                       lengthof( shares[cshare].shi1_netname ));
1728                 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1729                 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1730                 cshare++;
1731                 cstrp+=REMARK_LEN;
1732             }
1733             else
1734                 nShares--; /* uncount key */
1735         }
1736
1737         RegCloseKey(hkSubmount);
1738     }
1739
1740     nonrootShares = cshare;
1741
1742     for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1743         /* in case there are collisions with submounts, submounts have
1744            higher priority */           
1745         for (j=0; j < nonrootShares; j++)
1746             if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1747                 break;
1748                 
1749         if (j < nonrootShares) {
1750             nShares--; /* uncount */
1751             continue;
1752         }
1753
1754         StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
1755                        rootShares.shares[i].shi0_netname);
1756         shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1757         cshare++;
1758         cstrp+=REMARK_LEN;
1759     }
1760
1761     outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1762     outp->parmsp[1] = 0;
1763     outp->parmsp[2] = cshare;
1764     outp->parmsp[3] = nShares;
1765
1766     outp->totalData = (int)(cstrp - outp->datap);
1767     outp->totalParms = outParmsTotal;
1768
1769     smb_SendTran2Packet(vcp, outp, op);
1770     smb_FreeTran2Packet(outp);
1771
1772     free(rootShares.shares);
1773
1774     return code;
1775 }
1776
1777 /* RAP NetShareGetInfo */
1778 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1779 {
1780     smb_tran2Packet_t *outp;
1781     unsigned short * tp;
1782     clientchar_t * shareName;
1783     BOOL shareFound = FALSE;
1784     unsigned short infoLevel;
1785     unsigned short bufsize;
1786     int totalData;
1787     int totalParam;
1788     DWORD len;
1789     HKEY hkParam;
1790     HKEY hkSubmount;
1791     DWORD allSubmount;
1792     LONG rv;
1793     long code = 0;
1794     cm_scache_t *scp = NULL;
1795     cm_user_t   *userp;
1796     cm_req_t    req;
1797
1798     smb_InitReq(&req);
1799
1800     tp = p->parmsp + 1; /* skip over function number (always 1) */
1801
1802     {
1803         clientchar_t * cdescp;
1804
1805         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1806         if (cm_ClientStrCmp(cdescp,  _C("zWrLh")))
1807
1808             return CM_ERROR_INVAL;
1809
1810         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1811         if (cm_ClientStrCmp(cdescp,  _C("B13")) &&
1812             cm_ClientStrCmp(cdescp,  _C("B13BWz")) &&
1813             cm_ClientStrCmp(cdescp,  _C("B13BWzWWWzB9B")))
1814
1815             return CM_ERROR_INVAL;
1816     }
1817     shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1818
1819     infoLevel = *tp++;
1820     bufsize = *tp++;
1821     
1822     totalParam = 6;
1823
1824     if (infoLevel == 0)
1825         totalData = sizeof(smb_rap_share_info_0_t);
1826     else if(infoLevel == SMB_INFO_STANDARD)
1827         totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1828     else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1829         totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1830     else
1831         return CM_ERROR_INVAL;
1832
1833     if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
1834         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1835                           KEY_QUERY_VALUE, &hkParam);
1836         if (rv == ERROR_SUCCESS) {
1837             len = sizeof(allSubmount);
1838             rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1839                                   (BYTE *) &allSubmount, &len);
1840             if (rv != ERROR_SUCCESS || allSubmount != 0) {
1841                 allSubmount = 1;
1842             }
1843             RegCloseKey (hkParam);
1844         }
1845
1846         if (allSubmount)
1847             shareFound = TRUE;
1848
1849     } else {
1850         userp = smb_GetTran2User(vcp, p);
1851         if (!userp) {
1852             osi_Log1(smb_logp,"ReceiveRAPNetShareGetInfo unable to resolve user [%d]", p->uid);
1853             return CM_ERROR_BADSMB;
1854         }   
1855         code = cm_NameI(cm_data.rootSCachep, shareName,
1856                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1857                          userp, NULL, &req, &scp);
1858         if (code == 0) {
1859             cm_ReleaseSCache(scp);
1860             shareFound = TRUE;
1861         } else {
1862             rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1863                               KEY_QUERY_VALUE, &hkSubmount);
1864             if (rv == ERROR_SUCCESS) {
1865                 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1866                 if (rv == ERROR_SUCCESS) {
1867                     shareFound = TRUE;
1868                 }
1869                 RegCloseKey(hkSubmount);
1870             }
1871         }
1872     }
1873
1874     if (!shareFound)
1875         return CM_ERROR_BADSHARENAME;
1876
1877     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1878     memset(outp->datap, 0, totalData);
1879
1880     outp->parmsp[0] = 0;
1881     outp->parmsp[1] = 0;
1882     outp->parmsp[2] = totalData;
1883
1884     if (infoLevel == 0) {
1885         smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1886         cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
1887                               lengthof(info->shi0_netname));
1888     } else if(infoLevel == SMB_INFO_STANDARD) {
1889         smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1890         cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
1891         info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1892         info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1893         /* type and pad are already zero */
1894     } else { /* infoLevel==2 */
1895         smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1896         cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
1897         info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1898         info->shi2_permissions = ACCESS_ALL;
1899         info->shi2_max_uses = (unsigned short) -1;
1900         info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1901     }
1902
1903     outp->totalData = totalData;
1904     outp->totalParms = totalParam;
1905
1906     smb_SendTran2Packet(vcp, outp, op);
1907     smb_FreeTran2Packet(outp);
1908
1909     return code;
1910 }
1911
1912 #pragma pack(push, 1)
1913
1914 typedef struct smb_rap_wksta_info_10 {
1915     DWORD       wki10_computername;     /*char *wki10_computername;*/
1916     DWORD       wki10_username; /* char *wki10_username; */
1917     DWORD       wki10_langroup; /* char *wki10_langroup;*/
1918     BYTE        wki10_ver_major;
1919     BYTE        wki10_ver_minor;
1920     DWORD       wki10_logon_domain;     /*char *wki10_logon_domain;*/
1921     DWORD       wki10_oth_domains; /* char *wki10_oth_domains;*/
1922 } smb_rap_wksta_info_10_t;
1923
1924 #pragma pack(pop)
1925
1926 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1927 {
1928     smb_tran2Packet_t *outp;
1929     long code = 0;
1930     int infoLevel;
1931     int bufsize;
1932     unsigned short * tp;
1933     int totalData;
1934     int totalParams;
1935     smb_rap_wksta_info_10_t * info;
1936     char * cstrp;
1937     smb_user_t *uidp;
1938
1939     tp = p->parmsp + 1; /* Skip over function number */
1940
1941     {
1942         clientchar_t * cdescp;
1943
1944         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1945                                        SMB_STRF_FORCEASCII);
1946         if (cm_ClientStrCmp(cdescp,  _C("WrLh")))
1947             return CM_ERROR_INVAL;
1948
1949         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1950                                        SMB_STRF_FORCEASCII);
1951         if (cm_ClientStrCmp(cdescp,  _C("zzzBBzz")))
1952             return CM_ERROR_INVAL;
1953     }
1954
1955     infoLevel = *tp++;
1956     bufsize = *tp++;
1957
1958     if (infoLevel != 10) {
1959         return CM_ERROR_INVAL;
1960     }
1961
1962     totalParams = 6;
1963         
1964     /* infolevel 10 */
1965     totalData = sizeof(*info) +         /* info */
1966         MAX_COMPUTERNAME_LENGTH +       /* wki10_computername */
1967         SMB_MAX_USERNAME_LENGTH +       /* wki10_username */
1968         MAX_COMPUTERNAME_LENGTH +       /* wki10_langroup */
1969         MAX_COMPUTERNAME_LENGTH +       /* wki10_logon_domain */
1970         1;                              /* wki10_oth_domains (null)*/
1971
1972     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1973
1974     memset(outp->parmsp,0,totalParams);
1975     memset(outp->datap,0,totalData);
1976
1977     info = (smb_rap_wksta_info_10_t *) outp->datap;
1978     cstrp = (char *) (info + 1);
1979
1980     info->wki10_computername = (DWORD) (cstrp - outp->datap);
1981     StringCbCopyA(cstrp, totalData, smb_localNamep);
1982     cstrp += strlen(cstrp) + 1;
1983
1984     info->wki10_username = (DWORD) (cstrp - outp->datap);
1985     uidp = smb_FindUID(vcp, p->uid, 0);
1986     if (uidp) {
1987         lock_ObtainMutex(&uidp->mx);
1988         if(uidp->unp && uidp->unp->name)
1989             cm_ClientStringToUtf8(uidp->unp->name, -1,
1990                                   cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
1991         lock_ReleaseMutex(&uidp->mx);
1992         smb_ReleaseUID(uidp);
1993     }
1994     cstrp += strlen(cstrp) + 1;
1995
1996     info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1997     StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
1998     cstrp += strlen(cstrp) + 1;
1999
2000     /* TODO: Not sure what values these should take, but these work */
2001     info->wki10_ver_major = 5;
2002     info->wki10_ver_minor = 1;
2003
2004     info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2005     cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2006                           cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2007     cstrp += strlen(cstrp) + 1;
2008
2009     info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2010     cstrp ++; /* no other domains */
2011
2012     outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2013     outp->parmsp[2] = outp->totalData;
2014     outp->totalParms = totalParams;
2015
2016     smb_SendTran2Packet(vcp,outp,op);
2017     smb_FreeTran2Packet(outp);
2018
2019     return code;
2020 }
2021
2022 #pragma pack(push, 1)
2023
2024 typedef struct smb_rap_server_info_0 {
2025     BYTE    sv0_name[16];
2026 } smb_rap_server_info_0_t;
2027
2028 typedef struct smb_rap_server_info_1 {
2029     BYTE            sv1_name[16];
2030     BYTE            sv1_version_major;
2031     BYTE            sv1_version_minor;
2032     DWORD           sv1_type;
2033     DWORD           sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2034 } smb_rap_server_info_1_t;
2035
2036 #pragma pack(pop)
2037
2038 char smb_ServerComment[] = "OpenAFS Client";
2039 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2040
2041 #define SMB_SV_TYPE_SERVER              0x00000002L
2042 #define SMB_SV_TYPE_NT              0x00001000L
2043 #define SMB_SV_TYPE_SERVER_NT       0x00008000L
2044
2045 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2046 {
2047     smb_tran2Packet_t *outp;
2048     long code = 0;
2049     int infoLevel;
2050     int bufsize;
2051     unsigned short * tp;
2052     int totalData;
2053     int totalParams;
2054     smb_rap_server_info_0_t * info0;
2055     smb_rap_server_info_1_t * info1;
2056     char * cstrp;
2057
2058     tp = p->parmsp + 1; /* Skip over function number */
2059
2060     {
2061         clientchar_t * cdescp;
2062
2063         cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2064                                        SMB_STRF_FORCEASCII);
2065         if (cm_ClientStrCmp(cdescp,  _C("WrLh")))
2066             return CM_ERROR_INVAL;
2067         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2068                                        SMB_STRF_FORCEASCII);
2069         if (cm_ClientStrCmp(cdescp,  _C("B16")) ||
2070             cm_ClientStrCmp(cdescp,  _C("B16BBDz")))
2071             return CM_ERROR_INVAL;
2072     }
2073
2074     infoLevel = *tp++;
2075     bufsize = *tp++;
2076
2077     if (infoLevel != 0 && infoLevel != 1) {
2078         return CM_ERROR_INVAL;
2079     }
2080
2081     totalParams = 6;
2082
2083     totalData = 
2084         (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2085         : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2086
2087     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2088
2089     memset(outp->parmsp,0,totalParams);
2090     memset(outp->datap,0,totalData);
2091
2092     if (infoLevel == 0) {
2093         info0 = (smb_rap_server_info_0_t *) outp->datap;
2094         cstrp = (char *) (info0 + 1);
2095         StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2096     } else { /* infoLevel == SMB_INFO_STANDARD */
2097         info1 = (smb_rap_server_info_1_t *) outp->datap;
2098         cstrp = (char *) (info1 + 1);
2099         StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2100
2101         info1->sv1_type = 
2102             SMB_SV_TYPE_SERVER |
2103             SMB_SV_TYPE_NT |
2104             SMB_SV_TYPE_SERVER_NT;
2105
2106         info1->sv1_version_major = 5;
2107         info1->sv1_version_minor = 1;
2108         info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2109
2110         StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2111
2112         cstrp += smb_ServerCommentLen / sizeof(char);
2113     }
2114
2115     totalData = (DWORD)(cstrp - outp->datap);
2116     outp->totalData = min(bufsize,totalData); /* actual data size */
2117     outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2118     outp->parmsp[2] = totalData;
2119     outp->totalParms = totalParams;
2120
2121     smb_SendTran2Packet(vcp,outp,op);
2122     smb_FreeTran2Packet(outp);
2123
2124     return code;
2125 }
2126
2127 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2128 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2129 {
2130     smb_tran2Packet_t *asp;
2131     int totalParms;
2132     int totalData;
2133     int parmDisp;
2134     int dataDisp;
2135     int parmOffset;
2136     int dataOffset;
2137     int parmCount;
2138     int dataCount;
2139     int firstPacket;
2140     long code = 0;
2141     DWORD oldTime, newTime;
2142
2143     /* We sometimes see 0 word count.  What to do? */
2144     if (*inp->wctp == 0) {
2145         osi_Log0(smb_logp, "Transaction2 word count = 0"); 
2146         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2147
2148         smb_SetSMBDataLength(outp, 0);
2149         smb_SendPacket(vcp, outp);
2150         return 0;
2151     }
2152
2153     totalParms = smb_GetSMBParm(inp, 0);
2154     totalData = smb_GetSMBParm(inp, 1);
2155         
2156     firstPacket = (inp->inCom == 0x32);
2157         
2158     /* find the packet we're reassembling */
2159     lock_ObtainWrite(&smb_globalLock);
2160     asp = smb_FindTran2Packet(vcp, inp);
2161     if (!asp) {
2162         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2163     }
2164     lock_ReleaseWrite(&smb_globalLock);
2165         
2166     /* now merge in this latest packet; start by looking up offsets */
2167     if (firstPacket) {
2168         parmDisp = dataDisp = 0;
2169         parmOffset = smb_GetSMBParm(inp, 10);
2170         dataOffset = smb_GetSMBParm(inp, 12);
2171         parmCount = smb_GetSMBParm(inp, 9);
2172         dataCount = smb_GetSMBParm(inp, 11);
2173         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2174         asp->maxReturnData = smb_GetSMBParm(inp, 3);
2175
2176         osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2177                  totalData, dataCount, asp->maxReturnData);
2178     }
2179     else {
2180         parmDisp = smb_GetSMBParm(inp, 4);
2181         parmOffset = smb_GetSMBParm(inp, 3);
2182         dataDisp = smb_GetSMBParm(inp, 7);
2183         dataOffset = smb_GetSMBParm(inp, 6);
2184         parmCount = smb_GetSMBParm(inp, 2);
2185         dataCount = smb_GetSMBParm(inp, 5);
2186
2187         osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2188                  parmCount, dataCount);
2189     }   
2190
2191     /* now copy the parms and data */
2192     if ( asp->totalParms > 0 && parmCount != 0 )
2193     {
2194         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2195     }
2196     if ( asp->totalData > 0 && dataCount != 0 ) {
2197         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2198     }
2199
2200     /* account for new bytes */
2201     asp->curData += dataCount;
2202     asp->curParms += parmCount;
2203
2204     /* finally, if we're done, remove the packet from the queue and dispatch it */
2205     if (asp->totalParms > 0 &&
2206         asp->curParms > 0 &&
2207         asp->totalData <= asp->curData &&
2208         asp->totalParms <= asp->curParms) {
2209         /* we've received it all */
2210         lock_ObtainWrite(&smb_globalLock);
2211         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2212         lock_ReleaseWrite(&smb_globalLock);
2213
2214         oldTime = GetTickCount();
2215
2216         /* now dispatch it */
2217         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2218             osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2219             code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2220         }
2221         else {
2222             osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2223             code = CM_ERROR_BADOP;
2224         }
2225
2226         /* if an error is returned, we're supposed to send an error packet,
2227          * otherwise the dispatched function already did the data sending.
2228          * We give dispatched proc the responsibility since it knows how much
2229          * space to allocate.
2230          */
2231         if (code != 0) {
2232             smb_SendTran2Error(vcp, asp, outp, code);
2233         }
2234
2235         newTime = GetTickCount();
2236         if (newTime - oldTime > 45000) {
2237             smb_user_t *uidp;
2238             smb_fid_t *fidp;
2239             clientchar_t *treepath = NULL;  /* do not free */
2240             clientchar_t *pathname = NULL;
2241             cm_fid_t afid = {0,0,0,0,0};
2242
2243             uidp = smb_FindUID(vcp, asp->uid, 0);
2244             smb_LookupTIDPath(vcp, asp->tid, &treepath);
2245             fidp = smb_FindFID(vcp, inp->fid, 0);
2246
2247             if (fidp) {
2248                 lock_ObtainMutex(&fidp->mx);
2249                 if (fidp->NTopen_pathp)
2250                     pathname = fidp->NTopen_pathp;
2251                 if (fidp->scp)
2252                     afid = fidp->scp->fid;
2253             } else {
2254                 if (inp->stringsp->wdata)
2255                     pathname = inp->stringsp->wdata;
2256             }
2257
2258             afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)", 
2259                       myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2260                       asp->uid, uidp ? uidp->unp->name : NULL,
2261                       asp->pid, asp->mid, asp->tid,
2262                       treepath,
2263                       pathname, 
2264                       afid.cell, afid.volume, afid.vnode, afid.unique);
2265
2266             if (fidp)
2267                 lock_ReleaseMutex(&fidp->mx);
2268
2269             if (uidp)
2270                 smb_ReleaseUID(uidp);
2271             if (fidp)
2272                 smb_ReleaseFID(fidp);
2273         }
2274
2275         /* free the input tran 2 packet */
2276         smb_FreeTran2Packet(asp);
2277     }
2278     else if (firstPacket) {
2279         /* the first packet in a multi-packet request, we need to send an
2280          * ack to get more data.
2281          */
2282         smb_SetSMBDataLength(outp, 0);
2283         smb_SendPacket(vcp, outp);
2284     }
2285
2286     return 0;
2287 }
2288
2289 /* TRANS2_OPEN2 */
2290 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2291 {
2292     clientchar_t *pathp;
2293     smb_tran2Packet_t *outp;
2294     long code = 0;
2295     cm_space_t *spacep;
2296     int excl;
2297     cm_user_t *userp;
2298     cm_scache_t *dscp;          /* dir we're dealing with */
2299     cm_scache_t *scp;           /* file we're creating */
2300     cm_attr_t setAttr;
2301     int initialModeBits;
2302     smb_fid_t *fidp;
2303     int attributes;
2304     clientchar_t *lastNamep;
2305     afs_uint32 dosTime;
2306     int openFun;
2307     int trunc;
2308     int openMode;
2309     int extraInfo;
2310     int openAction;
2311     int parmSlot;                       /* which parm we're dealing with */
2312     long returnEALength;
2313     clientchar_t *tidPathp;
2314     cm_req_t req;
2315     int created = 0;
2316
2317     smb_InitReq(&req);
2318
2319     scp = NULL;
2320         
2321     extraInfo = (p->parmsp[0] & 1);     /* return extra info */
2322     returnEALength = (p->parmsp[0] & 8);        /* return extended attr length */
2323
2324     openFun = p->parmsp[6];             /* open function */
2325     excl = ((openFun & 3) == 0);
2326     trunc = ((openFun & 3) == 2);       /* truncate it */
2327     openMode = (p->parmsp[1] & 0x7);
2328     openAction = 0;                     /* tracks what we did */
2329
2330     attributes = p->parmsp[3];
2331     dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2332         
2333     /* compute initial mode bits based on read-only flag in attributes */
2334     initialModeBits = 0666;
2335     if (attributes & SMB_ATTR_READONLY) 
2336         initialModeBits &= ~0222;
2337         
2338     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[14]), NULL,
2339                                   SMB_STRF_ANSIPATH);
2340     
2341     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2342
2343     spacep = cm_GetSpace();
2344     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2345
2346     if (lastNamep && 
2347         (cm_ClientStrCmpI(lastNamep,  _C(SMB_IOCTL_FILENAME)) == 0 ||
2348          cm_ClientStrCmpI(lastNamep,  _C("\\srvsvc")) == 0 ||
2349          cm_ClientStrCmpI(lastNamep,  _C("\\wkssvc")) == 0 ||
2350          cm_ClientStrCmpI(lastNamep,  _C("\\ipc$")) == 0)) {
2351         /* special case magic file name for receiving IOCTL requests
2352          * (since IOCTL calls themselves aren't getting through).
2353          */
2354         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2355         smb_SetupIoctlFid(fidp, spacep);
2356
2357         /* copy out remainder of the parms */
2358         parmSlot = 0;
2359         outp->parmsp[parmSlot++] = fidp->fid;
2360         if (extraInfo) {
2361             outp->parmsp[parmSlot++] = 0;       /* attrs */
2362             outp->parmsp[parmSlot++] = 0;       /* mod time */
2363             outp->parmsp[parmSlot++] = 0; 
2364             outp->parmsp[parmSlot++] = 0;       /* len */
2365             outp->parmsp[parmSlot++] = 0x7fff;
2366             outp->parmsp[parmSlot++] = openMode;
2367             outp->parmsp[parmSlot++] = 0;       /* file type 0 ==> normal file or dir */
2368             outp->parmsp[parmSlot++] = 0;       /* IPC junk */
2369         }   
2370         /* and the final "always present" stuff */
2371         outp->parmsp[parmSlot++] = 1;           /* openAction found existing file */
2372         /* next write out the "unique" ID */
2373         outp->parmsp[parmSlot++] = 0x1234;
2374         outp->parmsp[parmSlot++] = 0x5678;
2375         outp->parmsp[parmSlot++] = 0;
2376         if (returnEALength) {
2377             outp->parmsp[parmSlot++] = 0;
2378             outp->parmsp[parmSlot++] = 0;
2379         }       
2380                 
2381         outp->totalData = 0;
2382         outp->totalParms = parmSlot * 2;
2383                 
2384         smb_SendTran2Packet(vcp, outp, op);
2385                 
2386         smb_FreeTran2Packet(outp);
2387
2388         /* and clean up fid reference */
2389         smb_ReleaseFID(fidp);
2390         return 0;
2391     }
2392
2393     if (!cm_IsValidClientString(pathp)) {
2394 #ifdef DEBUG
2395         clientchar_t * hexp;
2396
2397         hexp = cm_GetRawCharsAlloc(pathp, -1);
2398         osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2399                  osi_LogSaveClientString(smb_logp, hexp));
2400         if (hexp)
2401             free(hexp);
2402 #else
2403         osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2404 #endif
2405         smb_FreeTran2Packet(outp);
2406         return CM_ERROR_BADNTFILENAME;
2407     }
2408
2409 #ifdef DEBUG_VERBOSE
2410     {
2411         char *hexp, *asciip;
2412         asciip = (lastNamep ? lastNamep : pathp);
2413         hexp = osi_HexifyString( asciip );
2414         DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2415         free(hexp);
2416     }       
2417 #endif
2418
2419     userp = smb_GetTran2User(vcp, p);
2420     /* In the off chance that userp is NULL, we log and abandon */
2421     if (!userp) {
2422         osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2423         smb_FreeTran2Packet(outp);
2424         return CM_ERROR_BADSMB;
2425     }
2426
2427     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2428     if (code == CM_ERROR_TIDIPC) {
2429         /* Attempt to use a TID allocated for IPC.  The client
2430          * is probably looking for DCE RPC end points which we
2431          * don't support OR it could be looking to make a DFS
2432          * referral request. 
2433          */
2434         osi_Log0(smb_logp, "Tran2Open received IPC TID");
2435 #ifndef DFS_SUPPORT
2436         cm_ReleaseUser(userp);
2437         smb_FreeTran2Packet(outp);
2438         return CM_ERROR_NOSUCHPATH;
2439 #endif
2440     }
2441
2442     dscp = NULL;
2443     code = cm_NameI(cm_data.rootSCachep, pathp,
2444                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2445                      userp, tidPathp, &req, &scp);
2446     if (code != 0) {
2447         code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2448                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2449                          userp, tidPathp, &req, &dscp);
2450         cm_FreeSpace(spacep);
2451
2452         if (code) {
2453             cm_ReleaseUser(userp);
2454             smb_FreeTran2Packet(outp);
2455             return code;
2456         }
2457         
2458 #ifdef DFS_SUPPORT
2459         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2460             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2461                                                       (clientchar_t*) spacep->data);
2462             cm_ReleaseSCache(dscp);
2463             cm_ReleaseUser(userp);
2464             smb_FreeTran2Packet(outp);
2465             if ( WANTS_DFS_PATHNAMES(p) || pnc )
2466                 return CM_ERROR_PATH_NOT_COVERED;
2467             else
2468                 return CM_ERROR_NOSUCHPATH;
2469         }
2470 #endif /* DFS_SUPPORT */
2471
2472         /* otherwise, scp points to the parent directory.  Do a lookup,
2473          * and truncate the file if we find it, otherwise we create the
2474          * file.
2475          */
2476         if (!lastNamep) 
2477             lastNamep = pathp;
2478         else 
2479             lastNamep++;
2480         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2481                          &req, &scp);
2482         if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2483             cm_ReleaseSCache(dscp);
2484             cm_ReleaseUser(userp);
2485             smb_FreeTran2Packet(outp);
2486             return code;
2487         }
2488     } else {
2489 #ifdef DFS_SUPPORT
2490         if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2491             int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2492             cm_ReleaseSCache(scp);
2493             cm_ReleaseUser(userp);
2494             smb_FreeTran2Packet(outp);
2495             if ( WANTS_DFS_PATHNAMES(p) || pnc )
2496                 return CM_ERROR_PATH_NOT_COVERED;
2497             else
2498                 return CM_ERROR_NOSUCHPATH;
2499         }
2500 #endif /* DFS_SUPPORT */
2501
2502         /* macintosh is expensive to program for it */
2503         cm_FreeSpace(spacep);
2504     }
2505         
2506     /* if we get here, if code is 0, the file exists and is represented by
2507      * scp.  Otherwise, we have to create it.
2508      */
2509     if (code == 0) {
2510         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2511         if (code) {
2512             if (dscp) 
2513                 cm_ReleaseSCache(dscp);
2514             cm_ReleaseSCache(scp);
2515             cm_ReleaseUser(userp);
2516             smb_FreeTran2Packet(outp);
2517             return code;
2518         }
2519
2520         if (excl) {
2521             /* oops, file shouldn't be there */
2522             if (dscp) 
2523                 cm_ReleaseSCache(dscp);
2524             cm_ReleaseSCache(scp);
2525             cm_ReleaseUser(userp);
2526             smb_FreeTran2Packet(outp);
2527             return CM_ERROR_EXISTS;
2528         }
2529
2530         if (trunc) {
2531             setAttr.mask = CM_ATTRMASK_LENGTH;
2532             setAttr.length.LowPart = 0;
2533             setAttr.length.HighPart = 0;
2534             code = cm_SetAttr(scp, &setAttr, userp, &req);
2535             openAction = 3;     /* truncated existing file */
2536         }   
2537         else 
2538             openAction = 1;     /* found existing file */
2539     }
2540     else if (!(openFun & 0x10)) {
2541         /* don't create if not found */
2542         if (dscp) 
2543             cm_ReleaseSCache(dscp);
2544         osi_assertx(scp == NULL, "null cm_scache_t");
2545         cm_ReleaseUser(userp);
2546         smb_FreeTran2Packet(outp);
2547         return CM_ERROR_NOSUCHFILE;
2548     }
2549     else {
2550         osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2551         openAction = 2; /* created file */
2552         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2553         smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2554         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2555                           &req);
2556         if (code == 0) {
2557             created = 1;
2558             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2559                 smb_NotifyChange(FILE_ACTION_ADDED,
2560                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,  
2561                                   dscp, lastNamep, NULL, TRUE);
2562         } else if (!excl && code == CM_ERROR_EXISTS) {
2563             /* not an exclusive create, and someone else tried
2564              * creating it already, then we open it anyway.  We
2565              * don't bother retrying after this, since if this next
2566              * fails, that means that the file was deleted after we
2567              * started this call.
2568              */
2569             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2570                               userp, &req, &scp);
2571             if (code == 0) {
2572                 if (trunc) {
2573                     setAttr.mask = CM_ATTRMASK_LENGTH;
2574                     setAttr.length.LowPart = 0;
2575                     setAttr.length.HighPart = 0;
2576                     code = cm_SetAttr(scp, &setAttr, userp,
2577                                        &req);
2578                 }   
2579             }   /* lookup succeeded */
2580         }
2581     }
2582         
2583     /* we don't need this any longer */
2584     if (dscp) 
2585         cm_ReleaseSCache(dscp);
2586
2587     if (code) {
2588         /* something went wrong creating or truncating the file */
2589         if (scp) 
2590             cm_ReleaseSCache(scp);
2591         cm_ReleaseUser(userp);
2592         smb_FreeTran2Packet(outp);
2593         return code;
2594     }
2595         
2596     /* make sure we're about to open a file */
2597     if (scp->fileType != CM_SCACHETYPE_FILE) {
2598         code = 0;
2599         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2600             cm_scache_t * targetScp = 0;
2601             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2602             if (code == 0) {
2603                 /* we have a more accurate file to use (the
2604                  * target of the symbolic link).  Otherwise,
2605                  * we'll just use the symlink anyway.
2606                  */
2607                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2608                           scp, targetScp);
2609                 cm_ReleaseSCache(scp);
2610                 scp = targetScp;
2611             }
2612         }
2613         if (scp->fileType != CM_SCACHETYPE_FILE) {
2614             cm_ReleaseSCache(scp);
2615             cm_ReleaseUser(userp);
2616             smb_FreeTran2Packet(outp);
2617             return CM_ERROR_ISDIR;
2618         }
2619     }
2620
2621     /* now all we have to do is open the file itself */
2622     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2623     osi_assertx(fidp, "null smb_fid_t");
2624         
2625     cm_HoldUser(userp);
2626     lock_ObtainMutex(&fidp->mx);
2627     /* save a pointer to the vnode */
2628     osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2629     fidp->scp = scp;
2630     lock_ObtainWrite(&scp->rw);
2631     scp->flags |= CM_SCACHEFLAG_SMB_FID;
2632     lock_ReleaseWrite(&scp->rw);
2633     
2634     /* and the user */
2635     fidp->userp = userp;
2636         
2637     /* compute open mode */
2638     if (openMode != 1) 
2639         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2640     if (openMode == 1 || openMode == 2)
2641         fidp->flags |= SMB_FID_OPENWRITE;
2642
2643     /* remember that the file was newly created */
2644     if (created)
2645         fidp->flags |= SMB_FID_CREATED;
2646
2647     lock_ReleaseMutex(&fidp->mx);
2648
2649     smb_ReleaseFID(fidp);
2650         
2651     cm_Open(scp, 0, userp);
2652
2653     /* copy out remainder of the parms */
2654     parmSlot = 0;
2655     outp->parmsp[parmSlot++] = fidp->fid;
2656     lock_ObtainRead(&scp->rw);
2657     if (extraInfo) {
2658         outp->parmsp[parmSlot++] = smb_Attributes(scp);
2659         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2660         outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2661         outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2662         outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2663         outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2664         outp->parmsp[parmSlot++] = openMode;
2665         outp->parmsp[parmSlot++] = 0;   /* file type 0 ==> normal file or dir */
2666         outp->parmsp[parmSlot++] = 0;   /* IPC junk */
2667     }   
2668     /* and the final "always present" stuff */
2669     outp->parmsp[parmSlot++] = openAction;
2670     /* next write out the "unique" ID */
2671     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff); 
2672     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff); 
2673     outp->parmsp[parmSlot++] = 0; 
2674     if (returnEALength) {
2675         outp->parmsp[parmSlot++] = 0; 
2676         outp->parmsp[parmSlot++] = 0; 
2677     }   
2678     lock_ReleaseRead(&scp->rw);
2679     outp->totalData = 0;                /* total # of data bytes */
2680     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
2681
2682     smb_SendTran2Packet(vcp, outp, op);
2683
2684     smb_FreeTran2Packet(outp);
2685
2686     cm_ReleaseUser(userp);
2687     /* leave scp held since we put it in fidp->scp */
2688     return 0;
2689 }   
2690
2691 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2692 {
2693     unsigned short fid;
2694     unsigned short infolevel;
2695
2696     infolevel = p->parmsp[0];
2697     fid = p->parmsp[1];
2698     osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2699     
2700     return CM_ERROR_BAD_LEVEL;
2701 }
2702
2703 /* TRANS2_QUERY_FS_INFORMATION */
2704 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2705 {
2706     smb_tran2Packet_t *outp;
2707     smb_tran2QFSInfo_t qi;
2708     int responseSize;
2709     size_t sz = 0;
2710         
2711     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2712
2713     switch (p->parmsp[0]) {
2714     case SMB_INFO_ALLOCATION: 
2715         /* alloc info */
2716         responseSize = sizeof(qi.u.allocInfo); 
2717
2718         qi.u.allocInfo.FSID = 0;
2719         qi.u.allocInfo.sectorsPerAllocUnit = 1;
2720         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2721         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2722         qi.u.allocInfo.bytesPerSector = 1024;
2723         break;
2724
2725     case SMB_INFO_VOLUME: 
2726         /* volume info */
2727         qi.u.volumeInfo.vsn = 1234;  /* Volume serial number */
2728         qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
2729
2730         /* we're supposed to pad it out with zeroes to the end */
2731         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2732         smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2733
2734         responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2735         break;
2736
2737     case SMB_QUERY_FS_VOLUME_INFO: 
2738         /* FS volume info */
2739         responseSize = sizeof(qi.u.FSvolumeInfo);
2740
2741         {
2742             FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2743             memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2744         }
2745
2746         qi.u.FSvolumeInfo.vsn = 1234;
2747         qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
2748         memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
2749         memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2750         break;
2751
2752     case SMB_QUERY_FS_SIZE_INFO: 
2753         /* FS size info */
2754         responseSize = sizeof(qi.u.FSsizeInfo); 
2755
2756         qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2757         qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2758         qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2759         qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2760         qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2761         qi.u.FSsizeInfo.bytesPerSector = 1024;
2762         break;
2763
2764     case SMB_QUERY_FS_DEVICE_INFO: 
2765         /* FS device info */
2766         responseSize = sizeof(qi.u.FSdeviceInfo); 
2767
2768         qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2769         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2770         break;
2771
2772     case SMB_QUERY_FS_ATTRIBUTE_INFO: 
2773         /* FS attribute info */
2774
2775         /* attributes, defined in WINNT.H:
2776          *      FILE_CASE_SENSITIVE_SEARCH      0x1
2777          *      FILE_CASE_PRESERVED_NAMES       0x2
2778          *      FILE_UNICODE_ON_DISK            0x4
2779          *      FILE_VOLUME_QUOTAS              0x10
2780          *      <no name defined>               0x4000
2781          *         If bit 0x4000 is not set, Windows 95 thinks
2782          *         we can't handle long (non-8.3) names,
2783          *         despite our protestations to the contrary.
2784          */
2785         qi.u.FSattributeInfo.attributes = 0x4003;
2786         /* The maxCompLength is supposed to be in bytes */
2787 #ifdef SMB_UNICODE
2788         qi.u.FSattributeInfo.attributes |= 0x04;
2789 #endif
2790         qi.u.FSattributeInfo.maxCompLength = 255;
2791         smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2792         qi.u.FSattributeInfo.FSnameLength = sz;
2793
2794         responseSize =
2795             sizeof(qi.u.FSattributeInfo.attributes) +
2796             sizeof(qi.u.FSattributeInfo.maxCompLength) +
2797             sizeof(qi.u.FSattributeInfo.FSnameLength) +
2798             sz;
2799
2800         break;
2801
2802     case SMB_INFO_UNIX:         /* CIFS Unix Info */
2803     case SMB_INFO_MACOS:        /* Mac FS Info */
2804     default: 
2805         return CM_ERROR_BADOP;
2806     }   
2807         
2808     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2809         
2810     /* copy out return data, and set corresponding sizes */
2811     outp->totalParms = 0;
2812     outp->totalData = responseSize;
2813     memcpy(outp->datap, &qi, responseSize);
2814
2815     /* send and free the packets */
2816     smb_SendTran2Packet(vcp, outp, op);
2817     smb_FreeTran2Packet(outp);
2818
2819     return 0;
2820 }
2821
2822 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2823 {
2824     osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2825     return CM_ERROR_BADOP;
2826 }
2827
2828 struct smb_ShortNameRock {
2829     clientchar_t *maskp;
2830     unsigned int vnode;
2831     clientchar_t *shortName;
2832     size_t shortNameLen;
2833 };      
2834
2835 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2836                          osi_hyper_t *offp)
2837 {       
2838     struct smb_ShortNameRock *rockp;
2839     normchar_t normName[MAX_PATH];
2840     clientchar_t *shortNameEnd;
2841
2842     rockp = vrockp;
2843
2844     if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
2845         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
2846                  osi_LogSaveString(smb_logp, dep->name));
2847         return 0;
2848     }
2849
2850     /* compare both names and vnodes, though probably just comparing vnodes
2851      * would be safe enough.
2852      */
2853     if (cm_NormStrCmpI(normName,  rockp->maskp) != 0)
2854         return 0;
2855     if (ntohl(dep->fid.vnode) != rockp->vnode)
2856         return 0;
2857
2858     /* This is the entry */
2859     cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2860     rockp->shortNameLen = shortNameEnd - rockp->shortName;
2861
2862     return CM_ERROR_STOPNOW;
2863 }
2864
2865 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
2866         clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
2867 {
2868     struct smb_ShortNameRock rock;
2869     clientchar_t *lastNamep;
2870     cm_space_t *spacep;
2871     cm_scache_t *dscp;
2872     int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2873     long code = 0;
2874     osi_hyper_t thyper;
2875
2876     spacep = cm_GetSpace();
2877     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
2878
2879     code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2880                     caseFold, userp, tidPathp,
2881                     reqp, &dscp);
2882     cm_FreeSpace(spacep);
2883     if (code) 
2884         return code;
2885
2886 #ifdef DFS_SUPPORT
2887     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2888         cm_ReleaseSCache(dscp);
2889         cm_ReleaseUser(userp);
2890 #ifdef DEBUG
2891         DebugBreak();
2892 #endif
2893         return CM_ERROR_PATH_NOT_COVERED;
2894     }
2895 #endif /* DFS_SUPPORT */
2896
2897     if (!lastNamep) lastNamep = pathp;
2898     else lastNamep++;
2899     thyper.LowPart = 0;
2900     thyper.HighPart = 0;
2901     rock.shortName = shortName;
2902     rock.vnode = vnode;
2903     rock.maskp = lastNamep;
2904     code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2905
2906     cm_ReleaseSCache(dscp);
2907
2908     if (code == 0)
2909         return CM_ERROR_NOSUCHFILE;
2910     if (code == CM_ERROR_STOPNOW) {
2911         *shortNameLenp = rock.shortNameLen;
2912         return 0;
2913     }
2914     return code;
2915 }
2916
2917 /* TRANS2_QUERY_PATH_INFORMATION */
2918 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2919 {
2920     smb_tran2Packet_t *outp;
2921     afs_uint32 dosTime;
2922     FILETIME ft;
2923     unsigned short infoLevel;
2924     smb_tran2QPathInfo_t qpi;
2925     int responseSize;
2926     unsigned short attributes;
2927     unsigned long extAttributes;
2928     clientchar_t shortName[13];
2929     size_t len;
2930     cm_user_t *userp;
2931     cm_space_t *spacep;
2932     cm_scache_t *scp, *dscp;
2933     int scp_rw_held = 0;
2934     int delonclose = 0;
2935     long code = 0;
2936     clientchar_t *pathp;
2937     clientchar_t *tidPathp;
2938     clientchar_t *lastComp;
2939     cm_req_t req;
2940
2941     smb_InitReq(&req);
2942
2943     infoLevel = p->parmsp[0];
2944     if (infoLevel == SMB_INFO_IS_NAME_VALID) 
2945         responseSize = 0;
2946     else if (infoLevel == SMB_INFO_STANDARD) 
2947         responseSize = sizeof(qpi.u.QPstandardInfo);
2948     else if (infoLevel == SMB_INFO_QUERY_EA_SIZE) 
2949         responseSize = sizeof(qpi.u.QPeaSizeInfo);
2950     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2951         responseSize = sizeof(qpi.u.QPfileBasicInfo);
2952     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2953         responseSize = sizeof(qpi.u.QPfileStandardInfo);
2954     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2955         responseSize = sizeof(qpi.u.QPfileEaInfo);
2956     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
2957         responseSize = sizeof(qpi.u.QPfileNameInfo);
2958     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) 
2959         responseSize = sizeof(qpi.u.QPfileAllInfo);
2960     else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) 
2961         responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2962     else {
2963         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2964                   p->opcode, infoLevel);
2965         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2966         return 0;
2967     }
2968
2969     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
2970     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
2971               osi_LogSaveClientString(smb_logp, pathp));
2972
2973     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2974
2975     if (infoLevel > 0x100)
2976         outp->totalParms = 2;
2977     else
2978         outp->totalParms = 0;
2979     outp->totalData = responseSize;
2980         
2981     /* now, if we're at infoLevel 6, we're only being asked to check
2982      * the syntax, so we just OK things now.  In particular, we're *not*
2983      * being asked to verify anything about the state of any parent dirs.
2984      */
2985     if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2986         smb_SendTran2Packet(vcp, outp, opx);
2987         smb_FreeTran2Packet(outp);
2988         return 0;
2989     }   
2990         
2991     userp = smb_GetTran2User(vcp, p);
2992     if (!userp) {
2993         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2994         smb_FreeTran2Packet(outp);
2995         return CM_ERROR_BADSMB;
2996     }
2997
2998     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2999     if(code) {
3000         cm_ReleaseUser(userp);
3001         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3002         smb_FreeTran2Packet(outp);
3003         return 0;
3004     }
3005
3006     /*
3007      * XXX Strange hack XXX
3008      *
3009      * As of Patch 7 (13 January 98), we are having the following problem:
3010      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3011      * requests to look up "desktop.ini" in all the subdirectories.
3012      * This can cause zillions of timeouts looking up non-existent cells
3013      * and volumes, especially in the top-level directory.
3014      *
3015      * We have not found any way to avoid this or work around it except
3016      * to explicitly ignore the requests for mount points that haven't
3017      * yet been evaluated and for directories that haven't yet been
3018      * fetched.
3019      */
3020     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3021         spacep = cm_GetSpace();
3022         smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3023 #ifndef SPECIAL_FOLDERS
3024         /* Make sure that lastComp is not NULL */
3025         if (lastComp) {
3026             if (cm_ClientStrCmpIA(lastComp,  _C("\\desktop.ini")) == 0) {
3027                 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3028                                  CM_FLAG_CASEFOLD
3029                                  | CM_FLAG_DIRSEARCH
3030                                  | CM_FLAG_FOLLOW,
3031                                  userp, tidPathp, &req, &dscp);
3032                 if (code == 0) {
3033 #ifdef DFS_SUPPORT
3034                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3035                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3036                                                                   spacep->wdata);
3037                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3038                             code = CM_ERROR_PATH_NOT_COVERED;
3039                         else
3040                             code = CM_ERROR_NOSUCHPATH;
3041                     } else
3042 #endif /* DFS_SUPPORT */
3043                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3044                         code = CM_ERROR_NOSUCHFILE;
3045                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3046                         cm_buf_t *bp = buf_Find(dscp, &hzero);
3047                         if (bp) {
3048                             buf_Release(bp);
3049                             bp = NULL;
3050                         }
3051                         else
3052                             code = CM_ERROR_NOSUCHFILE;
3053                     }
3054                     cm_ReleaseSCache(dscp);
3055                     if (code) {
3056                         cm_FreeSpace(spacep);
3057                         cm_ReleaseUser(userp);
3058                         smb_SendTran2Error(vcp, p, opx, code);
3059                         smb_FreeTran2Packet(outp);
3060                         return 0;
3061                     }
3062                 }
3063             }
3064         }
3065 #endif /* SPECIAL_FOLDERS */
3066
3067         cm_FreeSpace(spacep);
3068     }
3069
3070     /* now do namei and stat, and copy out the info */
3071     code = cm_NameI(cm_data.rootSCachep, pathp,
3072                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3073
3074     if (code) {
3075         cm_ReleaseUser(userp);
3076         smb_SendTran2Error(vcp, p, opx, code);
3077         smb_FreeTran2Packet(outp);
3078         return 0;
3079     }
3080
3081 #ifdef DFS_SUPPORT
3082     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3083         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3084         cm_ReleaseSCache(scp);
3085         cm_ReleaseUser(userp);
3086         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3087             code = CM_ERROR_PATH_NOT_COVERED;
3088         else
3089             code = CM_ERROR_NOSUCHPATH;
3090         smb_SendTran2Error(vcp, p, opx, code);
3091         smb_FreeTran2Packet(outp);
3092         return 0;
3093     }
3094 #endif /* DFS_SUPPORT */
3095
3096     lock_ObtainWrite(&scp->rw);
3097     scp_rw_held = 2;
3098     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3099                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3100     if (code)
3101         goto done;
3102
3103     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3104         
3105     lock_ConvertWToR(&scp->rw);
3106     scp_rw_held = 1;
3107
3108     len = 0;
3109
3110     /* now we have the status in the cache entry, and everything is locked.
3111      * Marshall the output data.
3112      */
3113     /* for info level 108, figure out short name */
3114     if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3115         code = cm_GetShortName(pathp, userp, &req,
3116                                 tidPathp, scp->fid.vnode, shortName,
3117                                &len);
3118         if (code) {
3119             goto done;
3120         }
3121
3122         smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3123         qpi.u.QPfileAltNameInfo.fileNameLength = len;
3124
3125         goto done;
3126     }
3127     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3128         smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3129         qpi.u.QPfileNameInfo.fileNameLength = len;
3130
3131         goto done;
3132     }
3133     else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3134         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3135         qpi.u.QPstandardInfo.creationDateTime = dosTime;
3136         qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3137         qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3138         qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3139         qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3140         attributes = smb_Attributes(scp);
3141         qpi.u.QPstandardInfo.attributes = attributes;
3142         qpi.u.QPstandardInfo.eaSize = 0;
3143     }
3144     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3145         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3146         qpi.u.QPfileBasicInfo.creationTime = ft;
3147         qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3148         qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3149         qpi.u.QPfileBasicInfo.changeTime = ft;
3150         extAttributes = smb_ExtAttributes(scp);
3151         qpi.u.QPfileBasicInfo.attributes = extAttributes;
3152         qpi.u.QPfileBasicInfo.reserved = 0;
3153     }
3154     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3155         smb_fid_t * fidp;
3156             
3157         lock_ReleaseRead(&scp->rw);
3158         scp_rw_held = 0;
3159         fidp = smb_FindFIDByScache(vcp, scp);
3160
3161         qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3162         qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3163         qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3164         qpi.u.QPfileStandardInfo.directory = 
3165             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3166               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3167               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3168         qpi.u.QPfileStandardInfo.reserved = 0;
3169
3170         if (fidp) {
3171             lock_ObtainMutex(&fidp->mx);
3172             delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3173             lock_ReleaseMutex(&fidp->mx);
3174             smb_ReleaseFID(fidp);
3175         }
3176         qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3177     }
3178     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3179         qpi.u.QPfileEaInfo.eaSize = 0;
3180     }
3181     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3182         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3183         qpi.u.QPfileAllInfo.creationTime = ft;
3184         qpi.u.QPfileAllInfo.lastAccessTime = ft;
3185         qpi.u.QPfileAllInfo.lastWriteTime = ft;
3186         qpi.u.QPfileAllInfo.changeTime = ft;
3187         extAttributes = smb_ExtAttributes(scp);
3188         qpi.u.QPfileAllInfo.attributes = extAttributes;
3189         qpi.u.QPfileAllInfo.allocationSize = scp->length;
3190         qpi.u.QPfileAllInfo.endOfFile = scp->length;
3191         qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3192         qpi.u.QPfileAllInfo.deletePending = 0;
3193         qpi.u.QPfileAllInfo.directory = 
3194             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3195               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3196               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3197         qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3198         qpi.u.QPfileAllInfo.indexNumber.LowPart  = scp->fid.volume;
3199         qpi.u.QPfileAllInfo.eaSize = 0;
3200         qpi.u.QPfileAllInfo.accessFlags = 0;
3201         qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3202         qpi.u.QPfileAllInfo.indexNumber2.LowPart  = scp->fid.unique;
3203         qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3204         qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3205         qpi.u.QPfileAllInfo.mode = 0;
3206         qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3207
3208         smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3209         qpi.u.QPfileAllInfo.fileNameLength = len;
3210     }
3211
3212     /* send and free the packets */
3213   done:
3214     switch (scp_rw_held) {
3215     case 1:
3216         lock_ReleaseRead(&scp->rw);
3217         break;
3218     case 2:
3219         lock_ReleaseWrite(&scp->rw);
3220         break;
3221     }
3222     scp_rw_held = 0;
3223     cm_ReleaseSCache(scp);
3224     cm_ReleaseUser(userp);
3225     if (code == 0) {
3226         memcpy(outp->datap, &qpi, responseSize);
3227         smb_SendTran2Packet(vcp, outp, opx);
3228     } else {
3229         smb_SendTran2Error(vcp, p, opx, code);
3230     }
3231     smb_FreeTran2Packet(outp);
3232
3233     return 0;
3234 }
3235
3236 /* TRANS2_SET_PATH_INFORMATION */
3237 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3238 {
3239 #if 0
3240     osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3241     return CM_ERROR_BADOP;
3242 #else
3243     long code = 0;
3244     unsigned short infoLevel;
3245     clientchar_t * pathp;
3246     smb_tran2Packet_t *outp;
3247     smb_tran2QPathInfo_t *spi;
3248     cm_user_t *userp;
3249     cm_scache_t *scp, *dscp;
3250     cm_req_t req;
3251     cm_space_t *spacep;
3252     clientchar_t *tidPathp;
3253     clientchar_t *lastComp;
3254
3255     smb_InitReq(&req);
3256
3257     infoLevel = p->parmsp[0];
3258     osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3259     if (infoLevel != SMB_INFO_STANDARD && 
3260         infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3261         infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3262         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3263                   p->opcode, infoLevel);
3264         smb_SendTran2Error(vcp, p, opx, 
3265                            infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3266         return 0;
3267     }
3268
3269     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3270
3271     osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3272               osi_LogSaveClientString(smb_logp, pathp));
3273
3274     userp = smb_GetTran2User(vcp, p);
3275     if (!userp) {
3276         osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3277         code = CM_ERROR_BADSMB;
3278         goto done;
3279     }   
3280
3281     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3282     if (code == CM_ERROR_TIDIPC) {
3283         /* Attempt to use a TID allocated for IPC.  The client
3284          * is probably looking for DCE RPC end points which we
3285          * don't support OR it could be looking to make a DFS
3286          * referral request. 
3287          */
3288         osi_Log0(smb_logp, "Tran2Open received IPC TID");
3289         cm_ReleaseUser(userp);
3290         return CM_ERROR_NOSUCHPATH;
3291     }
3292
3293     /*
3294     * XXX Strange hack XXX
3295     *
3296     * As of Patch 7 (13 January 98), we are having the following problem:
3297     * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3298     * requests to look up "desktop.ini" in all the subdirectories.
3299     * This can cause zillions of timeouts looking up non-existent cells
3300     * and volumes, especially in the top-level directory.
3301     *
3302     * We have not found any way to avoid this or work around it except
3303     * to explicitly ignore the requests for mount points that haven't
3304     * yet been evaluated and for directories that haven't yet been
3305     * fetched.
3306     */
3307     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3308         spacep = cm_GetSpace();
3309         smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3310 #ifndef SPECIAL_FOLDERS
3311         /* Make sure that lastComp is not NULL */
3312         if (lastComp) {
3313             if (cm_ClientStrCmpI(lastComp,  _C("\\desktop.ini")) == 0) {
3314                 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3315                                  CM_FLAG_CASEFOLD
3316                                  | CM_FLAG_DIRSEARCH
3317                                  | CM_FLAG_FOLLOW,
3318                                  userp, tidPathp, &req, &dscp);
3319                 if (code == 0) {
3320 #ifdef DFS_SUPPORT
3321                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3322                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3323                                                                   spacep->wdata);
3324                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3325                             code = CM_ERROR_PATH_NOT_COVERED;
3326                         else
3327                             code = CM_ERROR_NOSUCHPATH;
3328                     } else
3329 #endif /* DFS_SUPPORT */
3330                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3331                         code = CM_ERROR_NOSUCHFILE;
3332                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3333                         cm_buf_t *bp = buf_Find(dscp, &hzero);
3334                         if (bp) {
3335                             buf_Release(bp);
3336                             bp = NULL;
3337                         }
3338                         else
3339                             code = CM_ERROR_NOSUCHFILE;
3340                     }
3341                     cm_ReleaseSCache(dscp);
3342                     if (code) {
3343                         cm_FreeSpace(spacep);
3344                         cm_ReleaseUser(userp);
3345                         smb_SendTran2Error(vcp, p, opx, code);
3346                         return 0;
3347                     }
3348                 }
3349             }
3350         }
3351 #endif /* SPECIAL_FOLDERS */
3352
3353         cm_FreeSpace(spacep);
3354     }
3355
3356     /* now do namei and stat, and copy out the info */
3357     code = cm_NameI(cm_data.rootSCachep, pathp,
3358                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3359     if (code) {
3360         cm_ReleaseUser(userp);
3361         smb_SendTran2Error(vcp, p, opx, code);
3362         return 0;
3363     }
3364
3365     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3366
3367     outp->totalParms = 2;
3368     outp->totalData = 0;
3369
3370     spi = (smb_tran2QPathInfo_t *)p->datap;
3371     if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3372         cm_attr_t attr;
3373
3374         /* lock the vnode with a callback; we need the current status
3375          * to determine what the new status is, in some cases.
3376          */
3377         lock_ObtainWrite(&scp->rw);
3378         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3379                           CM_SCACHESYNC_GETSTATUS
3380                          | CM_SCACHESYNC_NEEDCALLBACK);
3381         if (code) {
3382             lock_ReleaseWrite(&scp->rw);
3383             goto done;
3384         }
3385         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3386
3387         /* prepare for setattr call */
3388         attr.mask = CM_ATTRMASK_LENGTH;
3389         attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3390         attr.length.HighPart = 0;
3391
3392         if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3393             smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3394             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3395         }
3396                 
3397         if (spi->u.QPstandardInfo.attributes != 0) {
3398             if ((scp->unixModeBits & 0222)
3399                  && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3400                 /* make a writable file read-only */
3401                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3402                 attr.unixModeBits = scp->unixModeBits & ~0222;
3403             }
3404             else if ((scp->unixModeBits & 0222) == 0
3405                       && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3406                 /* make a read-only file writable */
3407                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3408                 attr.unixModeBits = scp->unixModeBits | 0222;
3409             }
3410         }
3411         lock_ReleaseRead(&scp->rw);
3412
3413         /* call setattr */
3414         if (attr.mask)
3415             code = cm_SetAttr(scp, &attr, userp, &req);
3416         else
3417             code = 0;
3418     }               
3419     else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3420         /* we don't support EAs */
3421         code = CM_ERROR_EAS_NOT_SUPPORTED;
3422     }       
3423
3424   done:
3425     cm_ReleaseSCache(scp);
3426     cm_ReleaseUser(userp);
3427     if (code == 0) 
3428         smb_SendTran2Packet(vcp, outp, opx);
3429     else 
3430         smb_SendTran2Error(vcp, p, opx, code);
3431     smb_FreeTran2Packet(outp);
3432
3433     return 0;
3434 #endif
3435 }
3436
3437 /* TRANS2_QUERY_FILE_INFORMATION */
3438 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3439 {
3440     smb_tran2Packet_t *outp;
3441     FILETIME ft;
3442     unsigned long attributes;
3443     unsigned short infoLevel;
3444     int responseSize;
3445     unsigned short fid;
3446     int delonclose = 0;
3447     cm_user_t *userp;
3448     smb_fid_t *fidp;
3449     cm_scache_t *scp;
3450     smb_tran2QFileInfo_t qfi;
3451     long code = 0;
3452     int  readlock = 0;
3453     cm_req_t req;
3454
3455     smb_InitReq(&req);
3456
3457     fid = p->parmsp[0];
3458     fidp = smb_FindFID(vcp, fid, 0);
3459
3460     if (fidp == NULL) {
3461         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3462         return 0;
3463     }
3464
3465     lock_ObtainMutex(&fidp->mx);
3466     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3467         lock_ReleaseMutex(&fidp->mx);
3468         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3469         smb_CloseFID(vcp, fidp, NULL, 0);
3470         smb_ReleaseFID(fidp);
3471         return 0;
3472     }
3473     lock_ReleaseMutex(&fidp->mx);
3474
3475     infoLevel = p->parmsp[1];
3476     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) 
3477         responseSize = sizeof(qfi.u.QFbasicInfo);
3478     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) 
3479         responseSize = sizeof(qfi.u.QFstandardInfo);
3480     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3481         responseSize = sizeof(qfi.u.QFeaInfo);
3482     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
3483         responseSize = sizeof(qfi.u.QFfileNameInfo);
3484     else {
3485         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3486                   p->opcode, infoLevel);
3487         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3488         smb_ReleaseFID(fidp);
3489         return 0;
3490     }
3491     osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3492
3493     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3494
3495     if (infoLevel > 0x100)
3496         outp->totalParms = 2;
3497     else
3498         outp->totalParms = 0;
3499     outp->totalData = responseSize;
3500
3501     userp = smb_GetTran2User(vcp, p);
3502     if (!userp) {
3503         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3504         code = CM_ERROR_BADSMB;
3505         goto done;
3506     }   
3507
3508     lock_ObtainMutex(&fidp->mx);
3509     delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3510     scp = fidp->scp;
3511     osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3512     cm_HoldSCache(scp);
3513     lock_ReleaseMutex(&fidp->mx);
3514     lock_ObtainWrite(&scp->rw);
3515     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3516                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3517     if (code) 
3518         goto done;
3519
3520     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3521
3522     lock_ConvertWToR(&scp->rw);
3523     readlock = 1;
3524
3525     /* now we have the status in the cache entry, and everything is locked.
3526      * Marshall the output data.
3527      */
3528     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3529         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3530         qfi.u.QFbasicInfo.creationTime = ft;
3531         qfi.u.QFbasicInfo.lastAccessTime = ft;
3532         qfi.u.QFbasicInfo.lastWriteTime = ft;
3533         qfi.u.QFbasicInfo.lastChangeTime = ft;
3534         attributes = smb_ExtAttributes(scp);
3535         qfi.u.QFbasicInfo.attributes = attributes;
3536     }
3537     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3538         qfi.u.QFstandardInfo.allocationSize = scp->length;
3539         qfi.u.QFstandardInfo.endOfFile = scp->length;
3540         qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3541         qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3542         qfi.u.QFstandardInfo.directory = 
3543             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3544               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3545               scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3546     }
3547     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3548         qfi.u.QFeaInfo.eaSize = 0;
3549     }
3550     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3551         size_t len = 0;
3552         clientchar_t *name;
3553
3554         lock_ReleaseRead(&scp->rw);
3555         lock_ObtainMutex(&fidp->mx);
3556         lock_ObtainRead(&scp->rw);
3557         if (fidp->NTopen_wholepathp)
3558             name = fidp->NTopen_wholepathp;
3559         else
3560             name = _C("\\");    /* probably can't happen */
3561         lock_ReleaseMutex(&fidp->mx);
3562
3563         smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3564         outp->totalData = len + 4;      /* this is actually what we want to return */
3565         qfi.u.QFfileNameInfo.fileNameLength = len;
3566     }
3567
3568     /* send and free the packets */
3569   done:
3570     if (readlock)
3571         lock_ReleaseRead(&scp->rw);
3572     else
3573         lock_ReleaseWrite(&scp->rw);
3574     cm_ReleaseSCache(scp);
3575     cm_ReleaseUser(userp);
3576     smb_ReleaseFID(fidp);
3577     if (code == 0) {
3578         memcpy(outp->datap, &qfi, responseSize);
3579         smb_SendTran2Packet(vcp, outp, opx);
3580     } else {
3581         smb_SendTran2Error(vcp, p, opx, code);
3582     }
3583     smb_FreeTran2Packet(outp);
3584
3585     return 0;
3586 }       
3587
3588
3589 /* TRANS2_SET_FILE_INFORMATION */
3590 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3591 {
3592     long code = 0;
3593     unsigned short fid;
3594     smb_fid_t *fidp;
3595     unsigned short infoLevel;
3596     smb_tran2Packet_t *outp;
3597     cm_user_t *userp = NULL;
3598     cm_scache_t *scp = NULL;
3599     cm_req_t req;
3600
3601     smb_InitReq(&req);
3602
3603     fid = p->parmsp[0];
3604     fidp = smb_FindFID(vcp, fid, 0);
3605
3606     if (fidp == NULL) {
3607         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3608         return 0;
3609     }
3610
3611     infoLevel = p->parmsp[1];