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