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