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