68b44d9f9b928abbd405bb59d81324640d00a76f
[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("\\ipc$")) == 0) && (is_rpc = TRUE)))) {
2528
2529         unsigned short file_type = 0;
2530         unsigned short device_state = 0;
2531
2532         /* special case magic file name for receiving IOCTL requests
2533          * (since IOCTL calls themselves aren't getting through).
2534          */
2535         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2536
2537         if (is_rpc) {
2538             code = smb_SetupRPCFid(fidp, lastNamep, &file_type, &device_state);
2539             osi_Log2(smb_logp, "smb_ReceiveTran2Open Creating RPC Fid [%d] code [%d]",
2540                      fidp->fid, code);
2541         } else {
2542             smb_SetupIoctlFid(fidp, spacep);
2543             osi_Log1(smb_logp, "smb_ReceiveTran2Open Creating IOCTL Fid [%d]", fidp->fid);
2544         }
2545
2546         /* copy out remainder of the parms */
2547         parmSlot = 0;
2548         outp->parmsp[parmSlot++] = fidp->fid;
2549         if (extraInfo) {
2550             outp->parmsp[parmSlot++] = 0;       /* attrs */
2551             outp->parmsp[parmSlot++] = 0;       /* mod time */
2552             outp->parmsp[parmSlot++] = 0; 
2553             outp->parmsp[parmSlot++] = 0;       /* len */
2554             outp->parmsp[parmSlot++] = 0x7fff;
2555             outp->parmsp[parmSlot++] = openMode;
2556             outp->parmsp[parmSlot++] = file_type;
2557             outp->parmsp[parmSlot++] = device_state;
2558         }   
2559         /* and the final "always present" stuff */
2560         outp->parmsp[parmSlot++] = 1;           /* openAction found existing file */
2561         /* next write out the "unique" ID */
2562         outp->parmsp[parmSlot++] = 0x1234;
2563         outp->parmsp[parmSlot++] = 0x5678;
2564         outp->parmsp[parmSlot++] = 0;
2565         if (returnEALength) {
2566             outp->parmsp[parmSlot++] = 0;
2567             outp->parmsp[parmSlot++] = 0;
2568         }       
2569                 
2570         outp->totalData = 0;
2571         outp->totalParms = parmSlot * 2;
2572                 
2573         smb_SendTran2Packet(vcp, outp, op);
2574                 
2575         smb_FreeTran2Packet(outp);
2576
2577         /* and clean up fid reference */
2578         smb_ReleaseFID(fidp);
2579         return 0;
2580     }
2581
2582     if (!cm_IsValidClientString(pathp)) {
2583 #ifdef DEBUG
2584         clientchar_t * hexp;
2585
2586         hexp = cm_GetRawCharsAlloc(pathp, -1);
2587         osi_Log1(smb_logp, "Tran2Open rejecting invalid name. [%S]",
2588                  osi_LogSaveClientString(smb_logp, hexp));
2589         if (hexp)
2590             free(hexp);
2591 #else
2592         osi_Log0(smb_logp, "Tran2Open rejecting invalid name");
2593 #endif
2594         smb_FreeTran2Packet(outp);
2595         return CM_ERROR_BADNTFILENAME;
2596     }
2597
2598 #ifdef DEBUG_VERBOSE
2599     {
2600         char *hexp, *asciip;
2601         asciip = (lastNamep ? lastNamep : pathp);
2602         hexp = osi_HexifyString( asciip );
2603         DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2604         free(hexp);
2605     }       
2606 #endif
2607
2608     userp = smb_GetTran2User(vcp, p);
2609     /* In the off chance that userp is NULL, we log and abandon */
2610     if (!userp) {
2611         osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2612         smb_FreeTran2Packet(outp);
2613         return CM_ERROR_BADSMB;
2614     }
2615
2616     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2617     if (code == CM_ERROR_TIDIPC) {
2618         /* Attempt to use a TID allocated for IPC.  The client
2619          * is probably looking for DCE RPC end points which we
2620          * don't support OR it could be looking to make a DFS
2621          * referral request. 
2622          */
2623         osi_Log0(smb_logp, "Tran2Open received IPC TID");
2624 #ifndef DFS_SUPPORT
2625         cm_ReleaseUser(userp);
2626         smb_FreeTran2Packet(outp);
2627         return CM_ERROR_NOSUCHPATH;
2628 #endif
2629     }
2630
2631     dscp = NULL;
2632     code = cm_NameI(cm_data.rootSCachep, pathp,
2633                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2634                      userp, tidPathp, &req, &scp);
2635     if (code != 0) {
2636         code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
2637                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2638                          userp, tidPathp, &req, &dscp);
2639         cm_FreeSpace(spacep);
2640
2641         if (code) {
2642             cm_ReleaseUser(userp);
2643             smb_FreeTran2Packet(outp);
2644             return code;
2645         }
2646         
2647 #ifdef DFS_SUPPORT
2648         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2649             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
2650                                                       (clientchar_t*) spacep->data);
2651             cm_ReleaseSCache(dscp);
2652             cm_ReleaseUser(userp);
2653             smb_FreeTran2Packet(outp);
2654             if ( WANTS_DFS_PATHNAMES(p) || pnc )
2655                 return CM_ERROR_PATH_NOT_COVERED;
2656             else
2657                 return CM_ERROR_NOSUCHPATH;
2658         }
2659 #endif /* DFS_SUPPORT */
2660
2661         /* otherwise, scp points to the parent directory.  Do a lookup,
2662          * and truncate the file if we find it, otherwise we create the
2663          * file.
2664          */
2665         if (!lastNamep) 
2666             lastNamep = pathp;
2667         else 
2668             lastNamep++;
2669         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2670                          &req, &scp);
2671         if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2672             cm_ReleaseSCache(dscp);
2673             cm_ReleaseUser(userp);
2674             smb_FreeTran2Packet(outp);
2675             return code;
2676         }
2677     } else {
2678 #ifdef DFS_SUPPORT
2679         if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2680             int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2681             cm_ReleaseSCache(scp);
2682             cm_ReleaseUser(userp);
2683             smb_FreeTran2Packet(outp);
2684             if ( WANTS_DFS_PATHNAMES(p) || pnc )
2685                 return CM_ERROR_PATH_NOT_COVERED;
2686             else
2687                 return CM_ERROR_NOSUCHPATH;
2688         }
2689 #endif /* DFS_SUPPORT */
2690
2691         /* macintosh is expensive to program for it */
2692         cm_FreeSpace(spacep);
2693     }
2694         
2695     /* if we get here, if code is 0, the file exists and is represented by
2696      * scp.  Otherwise, we have to create it.
2697      */
2698     if (code == 0) {
2699         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2700         if (code) {
2701             if (dscp) 
2702                 cm_ReleaseSCache(dscp);
2703             cm_ReleaseSCache(scp);
2704             cm_ReleaseUser(userp);
2705             smb_FreeTran2Packet(outp);
2706             return code;
2707         }
2708
2709         if (excl) {
2710             /* oops, file shouldn't be there */
2711             if (dscp) 
2712                 cm_ReleaseSCache(dscp);
2713             cm_ReleaseSCache(scp);
2714             cm_ReleaseUser(userp);
2715             smb_FreeTran2Packet(outp);
2716             return CM_ERROR_EXISTS;
2717         }
2718
2719         if (trunc) {
2720             setAttr.mask = CM_ATTRMASK_LENGTH;
2721             setAttr.length.LowPart = 0;
2722             setAttr.length.HighPart = 0;
2723             code = cm_SetAttr(scp, &setAttr, userp, &req);
2724             openAction = 3;     /* truncated existing file */
2725         }   
2726         else 
2727             openAction = 1;     /* found existing file */
2728     }
2729     else if (!(openFun & 0x10)) {
2730         /* don't create if not found */
2731         if (dscp) 
2732             cm_ReleaseSCache(dscp);
2733         osi_assertx(scp == NULL, "null cm_scache_t");
2734         cm_ReleaseUser(userp);
2735         smb_FreeTran2Packet(outp);
2736         return CM_ERROR_NOSUCHFILE;
2737     }
2738     else {
2739         osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2740         openAction = 2; /* created file */
2741         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2742         smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2743         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2744                           &req);
2745         if (code == 0) {
2746             created = 1;
2747             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2748                 smb_NotifyChange(FILE_ACTION_ADDED,
2749                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,  
2750                                   dscp, lastNamep, NULL, TRUE);
2751         } else if (!excl && code == CM_ERROR_EXISTS) {
2752             /* not an exclusive create, and someone else tried
2753              * creating it already, then we open it anyway.  We
2754              * don't bother retrying after this, since if this next
2755              * fails, that means that the file was deleted after we
2756              * started this call.
2757              */
2758             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2759                               userp, &req, &scp);
2760             if (code == 0) {
2761                 if (trunc) {
2762                     setAttr.mask = CM_ATTRMASK_LENGTH;
2763                     setAttr.length.LowPart = 0;
2764                     setAttr.length.HighPart = 0;
2765                     code = cm_SetAttr(scp, &setAttr, userp,
2766                                        &req);
2767                 }   
2768             }   /* lookup succeeded */
2769         }
2770     }
2771         
2772     /* we don't need this any longer */
2773     if (dscp) 
2774         cm_ReleaseSCache(dscp);
2775
2776     if (code) {
2777         /* something went wrong creating or truncating the file */
2778         if (scp) 
2779             cm_ReleaseSCache(scp);
2780         cm_ReleaseUser(userp);
2781         smb_FreeTran2Packet(outp);
2782         return code;
2783     }
2784         
2785     /* make sure we're about to open a file */
2786     if (scp->fileType != CM_SCACHETYPE_FILE) {
2787         code = 0;
2788         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2789             cm_scache_t * targetScp = 0;
2790             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2791             if (code == 0) {
2792                 /* we have a more accurate file to use (the
2793                  * target of the symbolic link).  Otherwise,
2794                  * we'll just use the symlink anyway.
2795                  */
2796                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2797                           scp, targetScp);
2798                 cm_ReleaseSCache(scp);
2799                 scp = targetScp;
2800             }
2801         }
2802         if (scp->fileType != CM_SCACHETYPE_FILE) {
2803             cm_ReleaseSCache(scp);
2804             cm_ReleaseUser(userp);
2805             smb_FreeTran2Packet(outp);
2806             return CM_ERROR_ISDIR;
2807         }
2808     }
2809
2810     /* now all we have to do is open the file itself */
2811     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2812     osi_assertx(fidp, "null smb_fid_t");
2813         
2814     cm_HoldUser(userp);
2815     lock_ObtainMutex(&fidp->mx);
2816     /* save a pointer to the vnode */
2817     osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2818     fidp->scp = scp;
2819     lock_ObtainWrite(&scp->rw);
2820     scp->flags |= CM_SCACHEFLAG_SMB_FID;
2821     lock_ReleaseWrite(&scp->rw);
2822     
2823     /* and the user */
2824     fidp->userp = userp;
2825         
2826     /* compute open mode */
2827     if (openMode != 1) 
2828         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2829     if (openMode == 1 || openMode == 2)
2830         fidp->flags |= SMB_FID_OPENWRITE;
2831
2832     /* remember that the file was newly created */
2833     if (created)
2834         fidp->flags |= SMB_FID_CREATED;
2835
2836     lock_ReleaseMutex(&fidp->mx);
2837
2838     smb_ReleaseFID(fidp);
2839         
2840     cm_Open(scp, 0, userp);
2841
2842     /* copy out remainder of the parms */
2843     parmSlot = 0;
2844     outp->parmsp[parmSlot++] = fidp->fid;
2845     lock_ObtainRead(&scp->rw);
2846     if (extraInfo) {
2847         outp->parmsp[parmSlot++] = smb_Attributes(scp);
2848         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2849         outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2850         outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2851         outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2852         outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2853         outp->parmsp[parmSlot++] = openMode;
2854         outp->parmsp[parmSlot++] = 0;   /* file type 0 ==> normal file or dir */
2855         outp->parmsp[parmSlot++] = 0;   /* IPC junk */
2856     }   
2857     /* and the final "always present" stuff */
2858     outp->parmsp[parmSlot++] = openAction;
2859     /* next write out the "unique" ID */
2860     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff); 
2861     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff); 
2862     outp->parmsp[parmSlot++] = 0; 
2863     if (returnEALength) {
2864         outp->parmsp[parmSlot++] = 0; 
2865         outp->parmsp[parmSlot++] = 0; 
2866     }   
2867     lock_ReleaseRead(&scp->rw);
2868     outp->totalData = 0;                /* total # of data bytes */
2869     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
2870
2871     smb_SendTran2Packet(vcp, outp, op);
2872
2873     smb_FreeTran2Packet(outp);
2874
2875     cm_ReleaseUser(userp);
2876     /* leave scp held since we put it in fidp->scp */
2877     return 0;
2878 }   
2879
2880 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2881 {
2882     unsigned short fid;
2883     unsigned short infolevel;
2884
2885     infolevel = p->parmsp[0];
2886     fid = p->parmsp[1];
2887     osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2888     
2889     return CM_ERROR_BAD_LEVEL;
2890 }
2891
2892 /* TRANS2_QUERY_FS_INFORMATION */
2893 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2894 {
2895     smb_tran2Packet_t *outp;
2896     smb_tran2QFSInfo_t qi;
2897     int responseSize;
2898     size_t sz = 0;
2899         
2900     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2901
2902     switch (p->parmsp[0]) {
2903     case SMB_INFO_ALLOCATION: 
2904         /* alloc info */
2905         responseSize = sizeof(qi.u.allocInfo); 
2906
2907         qi.u.allocInfo.FSID = 0;
2908         qi.u.allocInfo.sectorsPerAllocUnit = 1;
2909         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2910         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2911         qi.u.allocInfo.bytesPerSector = 1024;
2912         break;
2913
2914     case SMB_INFO_VOLUME: 
2915         /* volume info */
2916         qi.u.volumeInfo.vsn = 1234;  /* Volume serial number */
2917         qi.u.volumeInfo.vnCount = 3; /* Number of characters in label (AFS\0)*/
2918
2919         /* we're supposed to pad it out with zeroes to the end */
2920         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2921         smb_UnparseString(op, qi.u.volumeInfo.label, _C("AFS"), &sz, 0);
2922
2923         responseSize = sizeof(unsigned long) + sizeof(char) + max(12, sz);
2924         break;
2925
2926     case SMB_QUERY_FS_VOLUME_INFO: 
2927         /* FS volume info */
2928         responseSize = sizeof(qi.u.FSvolumeInfo);
2929
2930         {
2931             FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
2932             memcpy(&qi.u.FSvolumeInfo.vct, &ft, sizeof(ft));
2933         }
2934
2935         qi.u.FSvolumeInfo.vsn = 1234;
2936         qi.u.FSvolumeInfo.vnCount = 6; /* This is always in Unicode */
2937         memset(&qi.u.FSvolumeInfo.label, 0, sizeof(qi.u.FSvolumeInfo.label));
2938         memcpy(qi.u.FSvolumeInfo.label, L"AFS", sizeof(L"AFS"));
2939         break;
2940
2941     case SMB_QUERY_FS_SIZE_INFO: 
2942         /* FS size info */
2943         responseSize = sizeof(qi.u.FSsizeInfo); 
2944
2945         qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2946         qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2947         qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2948         qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2949         qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2950         qi.u.FSsizeInfo.bytesPerSector = 1024;
2951         break;
2952
2953     case SMB_QUERY_FS_DEVICE_INFO: 
2954         /* FS device info */
2955         responseSize = sizeof(qi.u.FSdeviceInfo); 
2956
2957         qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2958         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2959         break;
2960
2961     case SMB_QUERY_FS_ATTRIBUTE_INFO: 
2962         /* FS attribute info */
2963
2964         /* attributes, defined in WINNT.H:
2965          *      FILE_CASE_SENSITIVE_SEARCH      0x1
2966          *      FILE_CASE_PRESERVED_NAMES       0x2
2967          *      FILE_UNICODE_ON_DISK            0x4
2968          *      FILE_VOLUME_QUOTAS              0x10
2969          *      <no name defined>               0x4000
2970          *         If bit 0x4000 is not set, Windows 95 thinks
2971          *         we can't handle long (non-8.3) names,
2972          *         despite our protestations to the contrary.
2973          */
2974         qi.u.FSattributeInfo.attributes = 0x4003;
2975         /* The maxCompLength is supposed to be in bytes */
2976 #ifdef SMB_UNICODE
2977         qi.u.FSattributeInfo.attributes |= 0x04;
2978 #endif
2979         qi.u.FSattributeInfo.maxCompLength = 255;
2980         smb_UnparseString(op, qi.u.FSattributeInfo.FSname, _C("AFS"), &sz, SMB_STRF_IGNORENUL);
2981         qi.u.FSattributeInfo.FSnameLength = sz;
2982
2983         responseSize =
2984             sizeof(qi.u.FSattributeInfo.attributes) +
2985             sizeof(qi.u.FSattributeInfo.maxCompLength) +
2986             sizeof(qi.u.FSattributeInfo.FSnameLength) +
2987             sz;
2988
2989         break;
2990
2991     case SMB_INFO_UNIX:         /* CIFS Unix Info */
2992     case SMB_INFO_MACOS:        /* Mac FS Info */
2993     default: 
2994         return CM_ERROR_BADOP;
2995     }   
2996         
2997     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2998         
2999     /* copy out return data, and set corresponding sizes */
3000     outp->totalParms = 0;
3001     outp->totalData = responseSize;
3002     memcpy(outp->datap, &qi, responseSize);
3003
3004     /* send and free the packets */
3005     smb_SendTran2Packet(vcp, outp, op);
3006     smb_FreeTran2Packet(outp);
3007
3008     return 0;
3009 }
3010
3011 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3012 {
3013     osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
3014     return CM_ERROR_BADOP;
3015 }
3016
3017 struct smb_ShortNameRock {
3018     clientchar_t *maskp;
3019     unsigned int vnode;
3020     clientchar_t *shortName;
3021     size_t shortNameLen;
3022 };      
3023
3024 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
3025                          osi_hyper_t *offp)
3026 {       
3027     struct smb_ShortNameRock *rockp;
3028     normchar_t normName[MAX_PATH];
3029     clientchar_t *shortNameEnd;
3030
3031     rockp = vrockp;
3032
3033     if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(clientchar_t)) == 0) {
3034         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
3035                  osi_LogSaveString(smb_logp, dep->name));
3036         return 0;
3037     }
3038
3039     /* compare both names and vnodes, though probably just comparing vnodes
3040      * would be safe enough.
3041      */
3042     if (cm_NormStrCmpI(normName,  rockp->maskp) != 0)
3043         return 0;
3044     if (ntohl(dep->fid.vnode) != rockp->vnode)
3045         return 0;
3046
3047     /* This is the entry */
3048     cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
3049     rockp->shortNameLen = shortNameEnd - rockp->shortName;
3050
3051     return CM_ERROR_STOPNOW;
3052 }
3053
3054 long cm_GetShortName(clientchar_t *pathp, cm_user_t *userp, cm_req_t *reqp,
3055         clientchar_t *tidPathp, int vnode, clientchar_t *shortName, size_t *shortNameLenp)
3056 {
3057     struct smb_ShortNameRock rock;
3058     clientchar_t *lastNamep;
3059     cm_space_t *spacep;
3060     cm_scache_t *dscp;
3061     int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3062     long code = 0;
3063     osi_hyper_t thyper;
3064
3065     spacep = cm_GetSpace();
3066     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
3067
3068     code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3069                     caseFold, userp, tidPathp,
3070                     reqp, &dscp);
3071     cm_FreeSpace(spacep);
3072     if (code) 
3073         return code;
3074
3075 #ifdef DFS_SUPPORT
3076     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3077         cm_ReleaseSCache(dscp);
3078         cm_ReleaseUser(userp);
3079 #ifdef DEBUG
3080         DebugBreak();
3081 #endif
3082         return CM_ERROR_PATH_NOT_COVERED;
3083     }
3084 #endif /* DFS_SUPPORT */
3085
3086     if (!lastNamep) lastNamep = pathp;
3087     else lastNamep++;
3088     thyper.LowPart = 0;
3089     thyper.HighPart = 0;
3090     rock.shortName = shortName;
3091     rock.vnode = vnode;
3092     rock.maskp = lastNamep;
3093     code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
3094
3095     cm_ReleaseSCache(dscp);
3096
3097     if (code == 0)
3098         return CM_ERROR_NOSUCHFILE;
3099     if (code == CM_ERROR_STOPNOW) {
3100         *shortNameLenp = rock.shortNameLen;
3101         return 0;
3102     }
3103     return code;
3104 }
3105
3106 /* TRANS2_QUERY_PATH_INFORMATION */
3107 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3108 {
3109     smb_tran2Packet_t *outp;
3110     afs_uint32 dosTime;
3111     FILETIME ft;
3112     unsigned short infoLevel;
3113     smb_tran2QPathInfo_t qpi;
3114     int responseSize;
3115     unsigned short attributes;
3116     unsigned long extAttributes;
3117     clientchar_t shortName[13];
3118     size_t len;
3119     cm_user_t *userp;
3120     cm_space_t *spacep;
3121     cm_scache_t *scp, *dscp;
3122     int scp_rw_held = 0;
3123     int delonclose = 0;
3124     long code = 0;
3125     clientchar_t *pathp;
3126     clientchar_t *tidPathp;
3127     clientchar_t *lastComp;
3128     cm_req_t req;
3129
3130     smb_InitReq(&req);
3131
3132     infoLevel = p->parmsp[0];
3133     if (infoLevel == SMB_INFO_IS_NAME_VALID) 
3134         responseSize = 0;
3135     else if (infoLevel == SMB_INFO_STANDARD) 
3136         responseSize = sizeof(qpi.u.QPstandardInfo);
3137     else if (infoLevel == SMB_INFO_QUERY_EA_SIZE) 
3138         responseSize = sizeof(qpi.u.QPeaSizeInfo);
3139     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
3140         responseSize = sizeof(qpi.u.QPfileBasicInfo);
3141     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
3142         responseSize = sizeof(qpi.u.QPfileStandardInfo);
3143     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3144         responseSize = sizeof(qpi.u.QPfileEaInfo);
3145     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
3146         responseSize = sizeof(qpi.u.QPfileNameInfo);
3147     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) 
3148         responseSize = sizeof(qpi.u.QPfileAllInfo);
3149     else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) 
3150         responseSize = sizeof(qpi.u.QPfileAltNameInfo);
3151     else {
3152         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3153                   p->opcode, infoLevel);
3154         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3155         return 0;
3156     }
3157
3158     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3159     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %S", infoLevel,
3160               osi_LogSaveClientString(smb_logp, pathp));
3161
3162     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3163
3164     if (infoLevel > 0x100)
3165         outp->totalParms = 2;
3166     else
3167         outp->totalParms = 0;
3168     outp->totalData = responseSize;
3169         
3170     /* now, if we're at infoLevel 6, we're only being asked to check
3171      * the syntax, so we just OK things now.  In particular, we're *not*
3172      * being asked to verify anything about the state of any parent dirs.
3173      */
3174     if (infoLevel == SMB_INFO_IS_NAME_VALID) {
3175         smb_SendTran2Packet(vcp, outp, opx);
3176         smb_FreeTran2Packet(outp);
3177         return 0;
3178     }   
3179         
3180     userp = smb_GetTran2User(vcp, p);
3181     if (!userp) {
3182         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
3183         smb_FreeTran2Packet(outp);
3184         return CM_ERROR_BADSMB;
3185     }
3186
3187     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3188     if(code) {
3189         cm_ReleaseUser(userp);
3190         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
3191         smb_FreeTran2Packet(outp);
3192         return 0;
3193     }
3194
3195     /*
3196      * XXX Strange hack XXX
3197      *
3198      * As of Patch 7 (13 January 98), we are having the following problem:
3199      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3200      * requests to look up "desktop.ini" in all the subdirectories.
3201      * This can cause zillions of timeouts looking up non-existent cells
3202      * and volumes, especially in the top-level directory.
3203      *
3204      * We have not found any way to avoid this or work around it except
3205      * to explicitly ignore the requests for mount points that haven't
3206      * yet been evaluated and for directories that haven't yet been
3207      * fetched.
3208      */
3209     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3210         spacep = cm_GetSpace();
3211         smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3212 #ifndef SPECIAL_FOLDERS
3213         /* Make sure that lastComp is not NULL */
3214         if (lastComp) {
3215             if (cm_ClientStrCmpIA(lastComp,  _C("\\desktop.ini")) == 0) {
3216                 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3217                                  CM_FLAG_CASEFOLD
3218                                  | CM_FLAG_DIRSEARCH
3219                                  | CM_FLAG_FOLLOW,
3220                                  userp, tidPathp, &req, &dscp);
3221                 if (code == 0) {
3222 #ifdef DFS_SUPPORT
3223                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3224                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3225                                                                   spacep->wdata);
3226                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3227                             code = CM_ERROR_PATH_NOT_COVERED;
3228                         else
3229                             code = CM_ERROR_NOSUCHPATH;
3230                     } else
3231 #endif /* DFS_SUPPORT */
3232                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3233                         code = CM_ERROR_NOSUCHFILE;
3234                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3235                         cm_buf_t *bp = buf_Find(dscp, &hzero);
3236                         if (bp) {
3237                             buf_Release(bp);
3238                             bp = NULL;
3239                         }
3240                         else
3241                             code = CM_ERROR_NOSUCHFILE;
3242                     }
3243                     cm_ReleaseSCache(dscp);
3244                     if (code) {
3245                         cm_FreeSpace(spacep);
3246                         cm_ReleaseUser(userp);
3247                         smb_SendTran2Error(vcp, p, opx, code);
3248                         smb_FreeTran2Packet(outp);
3249                         return 0;
3250                     }
3251                 }
3252             }
3253         }
3254 #endif /* SPECIAL_FOLDERS */
3255
3256         cm_FreeSpace(spacep);
3257     }
3258
3259     /* now do namei and stat, and copy out the info */
3260     code = cm_NameI(cm_data.rootSCachep, pathp,
3261                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3262
3263     if (code) {
3264         cm_ReleaseUser(userp);
3265         smb_SendTran2Error(vcp, p, opx, code);
3266         smb_FreeTran2Packet(outp);
3267         return 0;
3268     }
3269
3270 #ifdef DFS_SUPPORT
3271     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3272         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
3273         cm_ReleaseSCache(scp);
3274         cm_ReleaseUser(userp);
3275         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3276             code = CM_ERROR_PATH_NOT_COVERED;
3277         else
3278             code = CM_ERROR_NOSUCHPATH;
3279         smb_SendTran2Error(vcp, p, opx, code);
3280         smb_FreeTran2Packet(outp);
3281         return 0;
3282     }
3283 #endif /* DFS_SUPPORT */
3284
3285     lock_ObtainWrite(&scp->rw);
3286     scp_rw_held = 2;
3287     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3288                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3289     if (code)
3290         goto done;
3291
3292     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3293         
3294     lock_ConvertWToR(&scp->rw);
3295     scp_rw_held = 1;
3296
3297     len = 0;
3298
3299     /* now we have the status in the cache entry, and everything is locked.
3300      * Marshall the output data.
3301      */
3302     /* for info level 108, figure out short name */
3303     if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
3304         code = cm_GetShortName(pathp, userp, &req,
3305                                 tidPathp, scp->fid.vnode, shortName,
3306                                &len);
3307         if (code) {
3308             goto done;
3309         }
3310
3311         smb_UnparseString(opx, qpi.u.QPfileAltNameInfo.fileName, shortName, &len, SMB_STRF_IGNORENUL);
3312         qpi.u.QPfileAltNameInfo.fileNameLength = len;
3313
3314         goto done;
3315     }
3316     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3317         smb_UnparseString(opx, qpi.u.QPfileNameInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3318         qpi.u.QPfileNameInfo.fileNameLength = len;
3319
3320         goto done;
3321     }
3322     else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3323         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3324         qpi.u.QPstandardInfo.creationDateTime = dosTime;
3325         qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
3326         qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
3327         qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
3328         qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
3329         attributes = smb_Attributes(scp);
3330         qpi.u.QPstandardInfo.attributes = attributes;
3331         qpi.u.QPstandardInfo.eaSize = 0;
3332     }
3333     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3334         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3335         qpi.u.QPfileBasicInfo.creationTime = ft;
3336         qpi.u.QPfileBasicInfo.lastAccessTime = ft;
3337         qpi.u.QPfileBasicInfo.lastWriteTime = ft;
3338         qpi.u.QPfileBasicInfo.changeTime = ft;
3339         extAttributes = smb_ExtAttributes(scp);
3340         qpi.u.QPfileBasicInfo.attributes = extAttributes;
3341         qpi.u.QPfileBasicInfo.reserved = 0;
3342     }
3343     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3344         smb_fid_t * fidp;
3345             
3346         lock_ReleaseRead(&scp->rw);
3347         scp_rw_held = 0;
3348         fidp = smb_FindFIDByScache(vcp, scp);
3349
3350         qpi.u.QPfileStandardInfo.allocationSize = scp->length;
3351         qpi.u.QPfileStandardInfo.endOfFile = scp->length;
3352         qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
3353         qpi.u.QPfileStandardInfo.directory = 
3354             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3355               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3356               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3357         qpi.u.QPfileStandardInfo.reserved = 0;
3358
3359         if (fidp) {
3360             lock_ObtainMutex(&fidp->mx);
3361             delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3362             lock_ReleaseMutex(&fidp->mx);
3363             smb_ReleaseFID(fidp);
3364         }
3365         qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
3366     }
3367     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3368         qpi.u.QPfileEaInfo.eaSize = 0;
3369     }
3370     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
3371         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3372         qpi.u.QPfileAllInfo.creationTime = ft;
3373         qpi.u.QPfileAllInfo.lastAccessTime = ft;
3374         qpi.u.QPfileAllInfo.lastWriteTime = ft;
3375         qpi.u.QPfileAllInfo.changeTime = ft;
3376         extAttributes = smb_ExtAttributes(scp);
3377         qpi.u.QPfileAllInfo.attributes = extAttributes;
3378         qpi.u.QPfileAllInfo.allocationSize = scp->length;
3379         qpi.u.QPfileAllInfo.endOfFile = scp->length;
3380         qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
3381         qpi.u.QPfileAllInfo.deletePending = 0;
3382         qpi.u.QPfileAllInfo.directory = 
3383             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3384               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3385               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
3386         qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
3387         qpi.u.QPfileAllInfo.indexNumber.LowPart  = scp->fid.volume;
3388         qpi.u.QPfileAllInfo.eaSize = 0;
3389         qpi.u.QPfileAllInfo.accessFlags = 0;
3390         qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
3391         qpi.u.QPfileAllInfo.indexNumber2.LowPart  = scp->fid.unique;
3392         qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
3393         qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
3394         qpi.u.QPfileAllInfo.mode = 0;
3395         qpi.u.QPfileAllInfo.alignmentRequirement = 0;
3396
3397         smb_UnparseString(opx, qpi.u.QPfileAllInfo.fileName, lastComp, &len, SMB_STRF_IGNORENUL);
3398         qpi.u.QPfileAllInfo.fileNameLength = len;
3399     }
3400
3401     /* send and free the packets */
3402   done:
3403     switch (scp_rw_held) {
3404     case 1:
3405         lock_ReleaseRead(&scp->rw);
3406         break;
3407     case 2:
3408         lock_ReleaseWrite(&scp->rw);
3409         break;
3410     }
3411     scp_rw_held = 0;
3412     cm_ReleaseSCache(scp);
3413     cm_ReleaseUser(userp);
3414     if (code == 0) {
3415         memcpy(outp->datap, &qpi, responseSize);
3416         smb_SendTran2Packet(vcp, outp, opx);
3417     } else {
3418         smb_SendTran2Error(vcp, p, opx, code);
3419     }
3420     smb_FreeTran2Packet(outp);
3421
3422     return 0;
3423 }
3424
3425 /* TRANS2_SET_PATH_INFORMATION */
3426 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3427 {
3428 #if 0
3429     osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
3430     return CM_ERROR_BADOP;
3431 #else
3432     long code = 0;
3433     unsigned short infoLevel;
3434     clientchar_t * pathp;
3435     smb_tran2Packet_t *outp;
3436     smb_tran2QPathInfo_t *spi;
3437     cm_user_t *userp;
3438     cm_scache_t *scp, *dscp;
3439     cm_req_t req;
3440     cm_space_t *spacep;
3441     clientchar_t *tidPathp;
3442     clientchar_t *lastComp;
3443
3444     smb_InitReq(&req);
3445
3446     infoLevel = p->parmsp[0];
3447     osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
3448     if (infoLevel != SMB_INFO_STANDARD && 
3449         infoLevel != SMB_INFO_QUERY_EA_SIZE &&
3450         infoLevel != SMB_INFO_QUERY_ALL_EAS) {
3451         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3452                   p->opcode, infoLevel);
3453         smb_SendTran2Error(vcp, p, opx, 
3454                            infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
3455         return 0;
3456     }
3457
3458     pathp = smb_ParseStringT2Parm(p, (char *) (&p->parmsp[3]), NULL, SMB_STRF_ANSIPATH);
3459
3460     osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %S", infoLevel,
3461               osi_LogSaveClientString(smb_logp, pathp));
3462
3463     userp = smb_GetTran2User(vcp, p);
3464     if (!userp) {
3465         osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3466         code = CM_ERROR_BADSMB;
3467         goto done;
3468     }   
3469
3470     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3471     if (code == CM_ERROR_TIDIPC) {
3472         /* Attempt to use a TID allocated for IPC.  The client
3473          * is probably looking for DCE RPC end points which we
3474          * don't support OR it could be looking to make a DFS
3475          * referral request. 
3476          */
3477         osi_Log0(smb_logp, "Tran2Open received IPC TID");
3478         cm_ReleaseUser(userp);
3479         return CM_ERROR_NOSUCHPATH;
3480     }
3481
3482     /*
3483     * XXX Strange hack XXX
3484     *
3485     * As of Patch 7 (13 January 98), we are having the following problem:
3486     * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3487     * requests to look up "desktop.ini" in all the subdirectories.
3488     * This can cause zillions of timeouts looking up non-existent cells
3489     * and volumes, especially in the top-level directory.
3490     *
3491     * We have not found any way to avoid this or work around it except
3492     * to explicitly ignore the requests for mount points that haven't
3493     * yet been evaluated and for directories that haven't yet been
3494     * fetched.
3495     */
3496     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3497         spacep = cm_GetSpace();
3498         smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
3499 #ifndef SPECIAL_FOLDERS
3500         /* Make sure that lastComp is not NULL */
3501         if (lastComp) {
3502             if (cm_ClientStrCmpI(lastComp,  _C("\\desktop.ini")) == 0) {
3503                 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
3504                                  CM_FLAG_CASEFOLD
3505                                  | CM_FLAG_DIRSEARCH
3506                                  | CM_FLAG_FOLLOW,
3507                                  userp, tidPathp, &req, &dscp);
3508                 if (code == 0) {
3509 #ifdef DFS_SUPPORT
3510                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3511                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
3512                                                                   spacep->wdata);
3513                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3514                             code = CM_ERROR_PATH_NOT_COVERED;
3515                         else
3516                             code = CM_ERROR_NOSUCHPATH;
3517                     } else
3518 #endif /* DFS_SUPPORT */
3519                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3520                         code = CM_ERROR_NOSUCHFILE;
3521                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3522                         cm_buf_t *bp = buf_Find(dscp, &hzero);
3523                         if (bp) {
3524                             buf_Release(bp);
3525                             bp = NULL;
3526                         }
3527                         else
3528                             code = CM_ERROR_NOSUCHFILE;
3529                     }
3530                     cm_ReleaseSCache(dscp);
3531                     if (code) {
3532                         cm_FreeSpace(spacep);
3533                         cm_ReleaseUser(userp);
3534                         smb_SendTran2Error(vcp, p, opx, code);
3535                         return 0;
3536                     }
3537                 }
3538             }
3539         }
3540 #endif /* SPECIAL_FOLDERS */
3541
3542         cm_FreeSpace(spacep);
3543     }
3544
3545     /* now do namei and stat, and copy out the info */
3546     code = cm_NameI(cm_data.rootSCachep, pathp,
3547                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3548     if (code) {
3549         cm_ReleaseUser(userp);
3550         smb_SendTran2Error(vcp, p, opx, code);
3551         return 0;
3552     }
3553
3554     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3555
3556     outp->totalParms = 2;
3557     outp->totalData = 0;
3558
3559     spi = (smb_tran2QPathInfo_t *)p->datap;
3560     if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3561         cm_attr_t attr;
3562
3563         /* lock the vnode with a callback; we need the current status
3564          * to determine what the new status is, in some cases.
3565          */
3566         lock_ObtainWrite(&scp->rw);
3567         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3568                           CM_SCACHESYNC_GETSTATUS
3569                          | CM_SCACHESYNC_NEEDCALLBACK);
3570         if (code) {
3571             lock_ReleaseWrite(&scp->rw);
3572             goto done;
3573         }
3574         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3575
3576         /* prepare for setattr call */
3577         attr.mask = CM_ATTRMASK_LENGTH;
3578         attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3579         attr.length.HighPart = 0;
3580
3581         if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3582             smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3583             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3584         }
3585                 
3586         if (spi->u.QPstandardInfo.attributes != 0) {
3587             if ((scp->unixModeBits & 0222)
3588                  && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3589                 /* make a writable file read-only */
3590                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3591                 attr.unixModeBits = scp->unixModeBits & ~0222;
3592             }
3593             else if ((scp->unixModeBits & 0222) == 0
3594                       && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3595                 /* make a read-only file writable */
3596                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3597                 attr.unixModeBits = scp->unixModeBits | 0222;
3598             }
3599         }
3600         lock_ReleaseRead(&scp->rw);
3601
3602         /* call setattr */
3603         if (attr.mask)
3604             code = cm_SetAttr(scp, &attr, userp, &req);
3605         else
3606             code = 0;
3607     }               
3608     else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3609         /* we don't support EAs */
3610         code = CM_ERROR_EAS_NOT_SUPPORTED;
3611     }       
3612
3613   done:
3614     cm_ReleaseSCache(scp);
3615     cm_ReleaseUser(userp);
3616     if (code == 0) 
3617         smb_SendTran2Packet(vcp, outp, opx);
3618     else 
3619         smb_SendTran2Error(vcp, p, opx, code);
3620     smb_FreeTran2Packet(outp);
3621
3622     return 0;
3623 #endif
3624 }
3625
3626 /* TRANS2_QUERY_FILE_INFORMATION */
3627 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3628 {
3629     smb_tran2Packet_t *outp;
3630     FILETIME ft;
3631     unsigned long attributes;
3632     unsigned short infoLevel;
3633     int responseSize;
3634     unsigned short fid;
3635     int delonclose = 0;
3636     cm_user_t *userp;
3637     smb_fid_t *fidp;
3638     cm_scache_t *scp;
3639     smb_tran2QFileInfo_t qfi;
3640     long code = 0;
3641     int  readlock = 0;
3642     cm_req_t req;
3643
3644     smb_InitReq(&req);
3645
3646     fid = p->parmsp[0];
3647     fidp = smb_FindFID(vcp, fid, 0);
3648
3649     if (fidp == NULL) {
3650         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3651         return 0;
3652     }
3653
3654     lock_ObtainMutex(&fidp->mx);
3655     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3656         lock_ReleaseMutex(&fidp->mx);
3657         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3658         smb_CloseFID(vcp, fidp, NULL, 0);
3659         smb_ReleaseFID(fidp);
3660         return 0;
3661     }
3662     lock_ReleaseMutex(&fidp->mx);
3663
3664     infoLevel = p->parmsp[1];
3665     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) 
3666         responseSize = sizeof(qfi.u.QFbasicInfo);
3667     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) 
3668         responseSize = sizeof(qfi.u.QFstandardInfo);
3669     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3670         responseSize = sizeof(qfi.u.QFeaInfo);
3671     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
3672         responseSize = sizeof(qfi.u.QFfileNameInfo);
3673     else {
3674         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3675                   p->opcode, infoLevel);
3676         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3677         smb_ReleaseFID(fidp);
3678         return 0;
3679     }
3680     osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3681
3682     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3683
3684     if (infoLevel > 0x100)
3685         outp->totalParms = 2;
3686     else
3687         outp->totalParms = 0;
3688     outp->totalData = responseSize;
3689
3690     userp = smb_GetTran2User(vcp, p);
3691     if (!userp) {
3692         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3693         code = CM_ERROR_BADSMB;
3694         goto done;
3695     }   
3696
3697     lock_ObtainMutex(&fidp->mx);
3698     delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3699     scp = fidp->scp;
3700     osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3701     cm_HoldSCache(scp);
3702     lock_ReleaseMutex(&fidp->mx);
3703     lock_ObtainWrite(&scp->rw);
3704     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3705                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3706     if (code) 
3707         goto done;
3708
3709     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3710
3711     lock_ConvertWToR(&scp->rw);
3712     readlock = 1;
3713
3714     /* now we have the status in the cache entry, and everything is locked.
3715      * Marshall the output data.
3716      */
3717     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3718         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3719         qfi.u.QFbasicInfo.creationTime = ft;
3720         qfi.u.QFbasicInfo.lastAccessTime = ft;
3721         qfi.u.QFbasicInfo.lastWriteTime = ft;
3722         qfi.u.QFbasicInfo.lastChangeTime = ft;
3723         attributes = smb_ExtAttributes(scp);
3724         qfi.u.QFbasicInfo.attributes = attributes;
3725     }
3726     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3727         qfi.u.QFstandardInfo.allocationSize = scp->length;
3728         qfi.u.QFstandardInfo.endOfFile = scp->length;
3729         qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3730         qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3731         qfi.u.QFstandardInfo.directory = 
3732             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3733               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3734               scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3735     }
3736     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3737         qfi.u.QFeaInfo.eaSize = 0;
3738     }
3739     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3740         size_t len = 0;
3741         clientchar_t *name;
3742
3743         lock_ReleaseRead(&scp->rw);
3744         lock_ObtainMutex(&fidp->mx);
3745         lock_ObtainRead(&scp->rw);
3746         if (fidp->NTopen_wholepathp)
3747             name = fidp->NTopen_wholepathp;
3748         else
3749             name = _C("\\");    /* probably can't happen */
3750         lock_ReleaseMutex(&fidp->mx);
3751
3752         smb_UnparseString(opx, qfi.u.QFfileNameInfo.fileName, name, &len, SMB_STRF_IGNORENUL);
3753         outp->totalData = len + 4;      /* this is actually what we want to return */
3754         qfi.u.QFfileNameInfo.fileNameLength = len;
3755     }
3756
3757     /* send and free the packets */
3758   done:
3759     if (readlock)
3760         lock_ReleaseRead(&scp->rw);
3761     else
3762         lock_ReleaseWrite(&scp->rw);
3763     cm_ReleaseSCache(scp);
3764     cm_ReleaseUser(userp);
3765     smb_ReleaseFID(fidp);
3766     if (code == 0) {
3767         memcpy(outp->datap, &qfi, responseSize);
3768         smb_SendTran2Packet(vcp, outp, opx);
3769     } else {
3770         smb_SendTran2Error(vcp, p, opx, code);
3771     }
3772     smb_FreeTran2Packet(outp);
3773
3774     return 0;
3775 }       
3776
3777
3778 /* TRANS2_SET_FILE_INFORMATION */
3779 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3780 {
3781     long code = 0;
3782     unsigned short fid;
3783     smb_fid_t *fidp;
3784     unsigned short infoLevel;
3785     smb_tran2Packet_t *outp;
3786     cm_user_t *userp = NULL;
3787     cm_scache_t *scp = NULL;
3788     cm_req_t req;
3789
3790     smb_InitReq(&req);
3791
3792     fid = p->parmsp[0];
3793     fidp = smb_FindFID(vcp, fid, 0);
3794
3795     if (fidp == NULL) {
3796         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3797         return 0;
3798     }
3799
3800     infoLevel = p->parmsp[1];
3801     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3802     if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3803         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3804                   p->opcode, infoLevel);
3805         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3806         smb_ReleaseFID(fidp);
3807         return 0;
3808     }
3809
3810     lock_ObtainMutex(&fidp->mx);
3811     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3812         lock_ReleaseMutex(&fidp->mx);
3813         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3814         smb_CloseFID(vcp, fidp, NULL, 0);
3815         smb_ReleaseFID(fidp);
3816         return 0;
3817     }
3818
3819     if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && 
3820         !(fidp->flags & SMB_FID_OPENDELETE)) {
3821         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x", 
3822                   fidp, fidp->scp, fidp->flags);
3823         lock_ReleaseMutex(&fidp->mx);
3824         smb_ReleaseFID(fidp);
3825         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3826         return 0;
3827     }
3828     if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO || 
3829          infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3830          && !(fidp->flags & SMB_FID_OPENWRITE)) {
3831         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x", 
3832                   fidp, fidp->scp, fidp->flags);
3833         lock_ReleaseMutex(&fidp->mx);
3834         smb_ReleaseFID(fidp);
3835         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3836         return 0;
3837     }
3838
3839     scp = fidp->scp;
3840     osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3841     cm_HoldSCache(scp);
3842     lock_ReleaseMutex(&fidp->mx);
3843
3844     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3845
3846     outp->totalParms = 2;
3847     outp->totalData = 0;
3848
3849     userp = smb_GetTran2User(vcp, p);
3850     if (!userp) {
3851         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3852         code = CM_ERROR_BADSMB;
3853         goto done;
3854     }   
3855
3856     if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3857         FILETIME lastMod;
3858         unsigned int attribute;
3859         cm_attr_t attr;
3860         smb_tran2QFileInfo_t *sfi;
3861
3862         sfi = (smb_tran2QFileInfo_t *)p->datap;
3863
3864         /* lock the vnode with a callback; we need the current status
3865          * to determine what the new status is, in some cases.
3866          */
3867         lock_ObtainWrite(&scp->rw);
3868         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3869                           CM_SCACHESYNC_GETSTATUS
3870                          | CM_SCACHESYNC_NEEDCALLBACK);
3871         if (code) {
3872             lock_ReleaseWrite(&scp->rw);
3873             goto done;
3874         }
3875
3876         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3877
3878         lock_ReleaseWrite(&scp->rw);
3879         lock_ObtainMutex(&fidp->mx);
3880         lock_ObtainRead(&scp->rw);
3881
3882         /* prepare for setattr call */
3883         attr.mask = 0;
3884
3885         lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3886         /* when called as result of move a b, lastMod is (-1, -1). 
3887          * If the check for -1 is not present, timestamp
3888          * of the resulting file will be 1969 (-1)
3889          */
3890         if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
3891              lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3892             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3893             smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3894             fidp->flags |= SMB_FID_MTIMESETDONE;
3895         }
3896                 
3897         attribute = sfi->u.QFbasicInfo.attributes;
3898         if (attribute != 0) {
3899             if ((scp->unixModeBits & 0222)
3900                  && (attribute & SMB_ATTR_READONLY) != 0) {
3901                 /* make a writable file read-only */
3902                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3903                 attr.unixModeBits = scp->unixModeBits & ~0222;
3904             }
3905             else if ((scp->unixModeBits & 0222) == 0
3906                       && (attribute & SMB_ATTR_READONLY) == 0) {
3907                 /* make a read-only file writable */
3908                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3909                 attr.unixModeBits = scp->unixModeBits | 0222;
3910             }
3911         }
3912         lock_ReleaseRead(&scp->rw);
3913         lock_ReleaseMutex(&fidp->mx);
3914
3915         /* call setattr */
3916         if (attr.mask)
3917             code = cm_SetAttr(scp, &attr, userp, &req);
3918         else
3919             code = 0;
3920     }
3921     else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3922         int delflag = *((char *)(p->datap));
3923         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p", 
3924                  delflag, fidp, scp);
3925         if (*((char *)(p->datap))) {    /* File is Deleted */
3926             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3927                                      &req);
3928             if (code == 0) {
3929                 lock_ObtainMutex(&fidp->mx);
3930                 fidp->flags |= SMB_FID_DELONCLOSE;
3931                 lock_ReleaseMutex(&fidp->mx);
3932             } else {
3933                 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x", 
3934                          fidp, scp, code);
3935             }
3936         }               
3937         else {  
3938             code = 0;
3939             lock_ObtainMutex(&fidp->mx);
3940             fidp->flags &= ~SMB_FID_DELONCLOSE;
3941             lock_ReleaseMutex(&fidp->mx);
3942         }
3943     }       
3944     else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3945              infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3946         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3947         cm_attr_t attr;
3948
3949         attr.mask = CM_ATTRMASK_LENGTH;
3950         attr.length.LowPart = size.LowPart;
3951         attr.length.HighPart = size.HighPart;
3952         code = cm_SetAttr(scp, &attr, userp, &req);
3953     }       
3954
3955   done:
3956     cm_ReleaseSCache(scp);
3957     cm_ReleaseUser(userp);
3958     smb_ReleaseFID(fidp);
3959     if (code == 0) 
3960         smb_SendTran2Packet(vcp, outp, opx);
3961     else 
3962         smb_SendTran2Error(vcp, p, opx, code);
3963     smb_FreeTran2Packet(outp);
3964
3965     return 0;
3966 }
3967
3968 /* TRANS2_FSCTL */
3969 long 
3970 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3971 {
3972     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3973     return CM_ERROR_BADOP;
3974 }
3975
3976 /* TRANS2_IOCTL2 */
3977 long 
3978 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3979 {
3980     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3981     return CM_ERROR_BADOP;
3982 }
3983
3984 /* TRANS2_FIND_NOTIFY_FIRST */
3985 long 
3986 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3987 {
3988     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3989     return CM_ERROR_BADOP;
3990 }
3991
3992 /* TRANS2_FIND_NOTIFY_NEXT */
3993 long 
3994 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3995 {
3996     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3997     return CM_ERROR_BADOP;
3998 }
3999
4000 /* TRANS2_CREATE_DIRECTORY */
4001 long 
4002 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4003 {
4004     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
4005     return CM_ERROR_BADOP;
4006 }
4007
4008 /* TRANS2_SESSION_SETUP */
4009 long 
4010 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4011 {
4012     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
4013     return CM_ERROR_BADOP;
4014 }
4015
4016 struct smb_v2_referral {
4017     USHORT ServerType;
4018     USHORT ReferralFlags;
4019     ULONG  Proximity;
4020     ULONG  TimeToLive;
4021     USHORT DfsPathOffset;
4022     USHORT DfsAlternativePathOffset;
4023     USHORT NetworkAddressOffset;
4024 };
4025
4026 /* TRANS2_GET_DFS_REFERRAL */
4027 long 
4028 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
4029 {
4030     /* This is a UNICODE only request (bit15 of Flags2) */
4031     /* The TID must be IPC$ */
4032
4033     /* The documentation for the Flags response field is contradictory */
4034
4035     /* Use Version 1 Referral Element Format */
4036     /* ServerType = 0; indicates the next server should be queried for the file */
4037     /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
4038     /* Node = UnicodeString of UNC path of the next share name */
4039 #ifdef DFS_SUPPORT
4040     long code = 0;
4041     int maxReferralLevel = 0;
4042     clientchar_t requestFileName[1024] = _C("");
4043     clientchar_t referralPath[1024] = _C("");
4044     smb_tran2Packet_t *outp = 0;
4045     cm_user_t *userp = 0;
4046     cm_scache_t *scp = 0;
4047     cm_scache_t *dscp = 0;
4048     cm_req_t req;
4049     CPINFO CodePageInfo;
4050     int i, nbnLen, reqLen, refLen;
4051     int idx;
4052
4053     smb_InitReq(&req);
4054
4055     maxReferralLevel = p->parmsp[0];
4056
4057     GetCPInfo(CP_ACP, &CodePageInfo);
4058     cm_Utf16ToClientString(&p->parmsp[1], -1, requestFileName, lengthof(requestFileName));
4059
4060     osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%S]", 
4061              maxReferralLevel, osi_LogSaveClientString(smb_logp, requestFileName));
4062
4063     nbnLen = (int)cm_ClientStrLen(cm_NetbiosNameC);
4064     reqLen = (int)cm_ClientStrLen(requestFileName);
4065
4066     if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
4067         !cm_ClientStrCmpNI(cm_NetbiosNameC, &requestFileName[1], nbnLen) &&
4068         requestFileName[nbnLen+1] == '\\') 
4069     {
4070         int found = 0;
4071
4072         if (!cm_ClientStrCmpNI(_C("all"), &requestFileName[nbnLen+2], 3) ||
4073             !cm_ClientStrCmpNI(_C("*."), &requestFileName[nbnLen+2], 2)) {
4074             found = 1;
4075             cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4076             refLen = reqLen;
4077         } else {
4078             userp = smb_GetTran2User(vcp, p);
4079             if (!userp) {
4080                 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
4081                 code = CM_ERROR_BADSMB;
4082                 goto done;
4083             }   
4084             
4085             /* 
4086              * We have a requested path.  Check to see if it is something 
4087              * we know about.
4088              *
4089              * But be careful because the name that we might be searching
4090              * for might be a known name with the final character stripped
4091              * off.
4092              */
4093             code = cm_NameI(cm_data.rootSCachep, &requestFileName[nbnLen+2],
4094                             CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
4095                             userp, NULL, &req, &scp);
4096             if (code == 0) {
4097                 /* Yes it is. */
4098                 found = 1;
4099                 cm_ClientStrCpy(referralPath, lengthof(referralPath), requestFileName);
4100                 refLen = reqLen;
4101             } else if (code == CM_ERROR_PATH_NOT_COVERED ) {
4102                 clientchar_t temp[1024];
4103                 clientchar_t pathName[1024];
4104                 clientchar_t *lastComponent;
4105                 /* 
4106                  * we have a msdfs link somewhere in the path
4107                  * we should figure out where in the path the link is.
4108                  * and return it.
4109                  */
4110                 osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral PATH_NOT_COVERED [%S]", requestFileName);
4111
4112                 cm_ClientStrCpy(temp, lengthof(temp), &requestFileName[nbnLen+2]);
4113
4114                 do {
4115                     if (dscp) {
4116                         cm_ReleaseSCache(dscp);
4117                         dscp = 0;
4118                     }
4119                     if (scp) {
4120                         cm_ReleaseSCache(scp);
4121                         scp = 0;
4122                     }
4123                     smb_StripLastComponent(pathName, &lastComponent, temp);
4124
4125                     code = cm_NameI(cm_data.rootSCachep, pathName,
4126                                     CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
4127                                     userp, NULL, &req, &dscp);
4128                     if (code == 0) {
4129                         code = cm_NameI(dscp, ++lastComponent,
4130                                         CM_FLAG_CASEFOLD,
4131                                         userp, NULL, &req, &scp);
4132                         if (code == 0 && scp->fileType == CM_SCACHETYPE_DFSLINK)
4133                             break;
4134                     }
4135                 } while (code == CM_ERROR_PATH_NOT_COVERED);
4136
4137                 /* scp should now be the DfsLink we are looking for */
4138                 if (scp) {
4139                     /* figure out how much of the input path was used */
4140                     reqLen = (int)(nbnLen+2 + cm_ClientStrLen(pathName) + 1 + cm_ClientStrLen(lastComponent));
4141
4142                     cm_FsStringToClientString(&scp->mountPointStringp[strlen("msdfs:")], -1,
4143                                               referralPath, lengthof(referralPath));
4144                     refLen = (int)cm_ClientStrLen(referralPath);
4145                     found = 1;
4146                 }
4147             } else {
4148                 clientchar_t shareName[MAX_PATH + 1];
4149                 clientchar_t *p, *q;
4150                 /* we may have a sharename that is a volume reference */
4151
4152                 for (p = &requestFileName[nbnLen+2], q = shareName; *p && *p != '\\'; p++, q++)
4153                 {
4154                     *q = *p;
4155                 }
4156                 *q = '\0';
4157                 
4158                 if (smb_FindShare(vcp, vcp->usersp, shareName, &p)) {
4159                     code = cm_NameI(cm_data.rootSCachep, _C(""), 
4160                                     CM_FLAG_CASEFOLD | CM_FLAG_FOLLOW,
4161                                     userp, p, &req, &scp);
4162                     free(p);
4163
4164                     if (code == 0) {
4165                         found = 1;
4166                         cm_ClientStrCpy(referralPath, lengthof(referralPath),
4167                                         requestFileName);
4168                         refLen = reqLen;
4169                     }
4170                 }
4171             }
4172         }
4173         
4174         if (found)
4175         {
4176             USHORT * sp;
4177             struct smb_v2_referral * v2ref;
4178             outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (refLen + 8));
4179
4180             sp = (USHORT *)outp->datap;
4181             idx = 0;
4182             sp[idx++] = reqLen;   /* path consumed */
4183             sp[idx++] = 1;        /* number of referrals */
4184             sp[idx++] = 0x03;     /* flags */
4185 #ifdef DFS_VERSION_1
4186             sp[idx++] = 1;        /* Version Number */
4187             sp[idx++] = refLen + 4;  /* Referral Size */ 
4188             sp[idx++] = 1;        /* Type = SMB Server */
4189             sp[idx++] = 0;        /* Do not strip path consumed */
4190             for ( i=0;i<=refLen; i++ )
4191                 sp[i+idx] = referralPath[i];
4192 #else /* DFS_VERSION_2 */
4193             sp[idx++] = 2;      /* Version Number */
4194             sp[idx++] = sizeof(struct smb_v2_referral);     /* Referral Size */
4195             idx += (sizeof(struct smb_v2_referral) / 2);
4196             v2ref = (struct smb_v2_referral *) &sp[5];
4197             v2ref->ServerType = 1;  /* SMB Server */
4198             v2ref->ReferralFlags = 0x03;
4199             v2ref->Proximity = 0;   /* closest */
4200             v2ref->TimeToLive = 3600; /* seconds */
4201             v2ref->DfsPathOffset = idx * 2;
4202             v2ref->DfsAlternativePathOffset = idx * 2;
4203             v2ref->NetworkAddressOffset = 0;
4204             for ( i=0;i<=refLen; i++ )
4205                 sp[i+idx] = referralPath[i];
4206 #endif
4207         } 
4208     } else {
4209         code = CM_ERROR_NOSUCHPATH;
4210     }
4211          
4212   done:
4213     if (dscp)
4214         cm_ReleaseSCache(dscp);
4215     if (scp)
4216         cm_ReleaseSCache(scp);
4217     if (userp)
4218         cm_ReleaseUser(userp);
4219     if (code == 0) 
4220         smb_SendTran2Packet(vcp, outp, op);
4221     else 
4222         smb_SendTran2Error(vcp, p, op, code);
4223     if (outp)
4224         smb_FreeTran2Packet(outp);
4225  
4226     return 0;
4227 #else /* DFS_SUPPORT */
4228     osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED"); 
4229     return CM_ERROR_NOSUCHDEVICE;
4230 #endif /* DFS_SUPPORT */
4231 }
4232
4233 /* TRANS2_REPORT_DFS_INCONSISTENCY */
4234 long 
4235 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
4236 {
4237     /* This is a UNICODE only request (bit15 of Flags2) */