windows-afsd-badsharename-20090317
[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         LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_RESET_ALL_VCS);
719         osi_Log0(smb_logp, "Resetting all VCs");
720         smb_MarkAllVCsDead(vcp);
721     }
722
723     if (vcp->flags & SMB_VCFLAG_USENT) {
724         if (smb_authType == SMB_AUTH_EXTENDED) {
725             /* extended authentication */
726             char *secBlobIn;
727             int secBlobInLength;
728
729             OutputDebugF(_C("NT Session Setup: Extended"));
730         
731             if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
732                 caps = smb_GetSMBParm(inp,10) | (((unsigned long) smb_GetSMBParm(inp,11)) << 16);
733             }
734
735             secBlobInLength = smb_GetSMBParm(inp, 7);
736             secBlobIn = smb_GetSMBData(inp, NULL);
737
738             code = smb_AuthenticateUserExt(vcp, usern, secBlobIn, secBlobInLength, &secBlobOut, &secBlobOutLength);
739
740             if (code == CM_ERROR_GSSCONTINUE) {
741                 size_t cb_data = 0;
742
743                 smb_SetSMBParm(outp, 2, 0);
744                 smb_SetSMBParm(outp, 3, secBlobOutLength);
745
746                 tp = smb_GetSMBData(outp, NULL);
747                 if (secBlobOutLength) {
748                     memcpy(tp, secBlobOut, secBlobOutLength);
749                     free(secBlobOut);
750                     tp += secBlobOutLength;
751                     cb_data += secBlobOutLength;
752                 }       
753                 tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
754                 tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
755                 tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
756
757                 smb_SetSMBDataLength(outp, cb_data);
758             }
759
760             /* TODO: handle return code and continue auth. Also free secBlobOut if applicable. */
761         } else {
762             unsigned ciPwdLength, csPwdLength;
763             char *ciPwd, *csPwd;
764             clientchar_t *accountName;
765             clientchar_t *primaryDomain;
766             int  datalen;
767
768             if (smb_authType == SMB_AUTH_NTLM)
769                 OutputDebugF(_C("NT Session Setup: NTLM"));
770             else
771                 OutputDebugF(_C("NT Session Setup: None"));
772
773             /* TODO: parse for extended auth as well */
774             ciPwdLength = smb_GetSMBParm(inp, 7); /* case insensitive password length */
775             csPwdLength = smb_GetSMBParm(inp, 8); /* case sensitive password length */
776
777             tp = smb_GetSMBData(inp, &datalen);
778
779             OutputDebugF(_C("Session packet data size [%d]"),datalen);
780
781             ciPwd = tp;
782             tp += ciPwdLength;
783             csPwd = tp;
784             tp += csPwdLength;
785
786             accountName = smb_ParseString(inp, tp, &tp, 0);
787             primaryDomain = smb_ParseString(inp, tp, NULL, 0);
788
789             OutputDebugF(_C("Account Name: %s"),accountName);
790             OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
791             OutputDebugF(_C("Case Sensitive Password: %s"),
792                          csPwd && csPwd[0] ? _C("yes") : _C("no"));
793             OutputDebugF(_C("Case Insensitive Password: %s"),
794                          ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
795
796             if (smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
797                 /* shouldn't happen */
798                 code = CM_ERROR_BADSMB;
799                 goto after_read_packet;
800             }
801
802             /* capabilities are only valid for first session packet */
803             if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
804                 caps = smb_GetSMBParm(inp, 11) | (((unsigned long)smb_GetSMBParm(inp, 12)) << 16);
805             }
806
807             if (smb_authType == SMB_AUTH_NTLM) {
808                 code = smb_AuthenticateUserLM(vcp, accountName, primaryDomain, ciPwd, ciPwdLength, csPwd, csPwdLength);
809                 if ( code )
810                     OutputDebugF(_C("LM authentication failed [%d]"), code);
811                 else
812                     OutputDebugF(_C("LM authentication succeeded"));
813             }
814         }
815     }  else { /* V3 */
816         unsigned ciPwdLength;
817         char *ciPwd;
818         clientchar_t *accountName;
819         clientchar_t *primaryDomain;
820
821         switch ( smb_authType ) {
822         case SMB_AUTH_EXTENDED:
823             OutputDebugF(_C("V3 Session Setup: Extended"));
824             break;
825         case SMB_AUTH_NTLM:
826             OutputDebugF(_C("V3 Session Setup: NTLM"));
827             break;
828         default:
829             OutputDebugF(_C("V3 Session Setup: None"));
830         }
831         ciPwdLength = smb_GetSMBParm(inp, 7);
832         tp = smb_GetSMBData(inp, NULL);
833         ciPwd = tp;
834         tp += ciPwdLength;
835
836         accountName = smb_ParseString(inp, tp, &tp, 0);
837         primaryDomain = smb_ParseString(inp, tp, NULL, 0);
838
839         OutputDebugF(_C("Account Name: %s"),accountName);
840         OutputDebugF(_C("Primary Domain: %s"), primaryDomain);
841         OutputDebugF(_C("Case Insensitive Password: %s"), ciPwd && ciPwd[0] ? _C("yes") : _C("no"));
842
843         if ( smb_GetNormalizedUsername(usern, accountName, primaryDomain)) {
844             /* shouldn't happen */
845             code = CM_ERROR_BADSMB;
846             goto after_read_packet;
847         }
848
849         /* even if we wanted extended auth, if we only negotiated V3, we have to fallback
850          * to NTLM.
851          */
852         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
853             code = smb_AuthenticateUserLM(vcp,accountName,primaryDomain,ciPwd,ciPwdLength,"",0);
854             if ( code )
855                 OutputDebugF(_C("LM authentication failed [%d]"), code);
856             else
857                 OutputDebugF(_C("LM authentication succeeded"));
858         }
859     }
860
861   after_read_packet:
862     /* note down that we received a session setup X and set the capabilities flag */
863     if (!(vcp->flags & SMB_VCFLAG_SESSX_RCVD)) {
864         lock_ObtainMutex(&vcp->mx);
865         vcp->flags |= SMB_VCFLAG_SESSX_RCVD;
866         /* for the moment we can only deal with NTSTATUS */
867         if (caps & NTNEGOTIATE_CAPABILITY_NTSTATUS) {
868             vcp->flags |= SMB_VCFLAG_STATUS32;
869         }       
870
871 #ifdef SMB_UNICODE
872         if ((caps & NTNEGOTIATE_CAPABILITY_UNICODE) && smb_UseUnicode) {
873             vcp->flags |= SMB_VCFLAG_USEUNICODE;
874         }
875 #endif
876         lock_ReleaseMutex(&vcp->mx);
877     }
878
879     /* code would be non-zero if there was an authentication failure.
880        Ideally we would like to invalidate the uid for this session or break
881        early to avoid accidently stealing someone else's tokens. */
882
883     if (code) {
884         return code;
885     }
886
887     OutputDebugF(_C("Received username=[%s]"), usern);
888
889     /* On Windows 2000, this function appears to be called more often than
890        it is expected to be called. This resulted in multiple smb_user_t
891        records existing all for the same user session which results in all
892        of the users tokens disappearing.
893
894        To avoid this problem, we look for an existing smb_user_t record
895        based on the users name, and use that one if we find it.
896     */
897
898     uidp = smb_FindUserByNameThisSession(vcp, usern);
899     if (uidp) {   /* already there, so don't create a new one */
900         unp = uidp->unp;
901         newUid = uidp->userID;
902         osi_Log3(smb_logp,"smb_ReceiveV3SessionSetupX FindUserByName:Lana[%d],lsn[%d],userid[%d]",
903                  vcp->lana,vcp->lsn,newUid);
904         smb_ReleaseUID(uidp);
905     }
906     else {
907         cm_user_t *userp;
908
909         /* do a global search for the username/machine name pair */
910         unp = smb_FindUserByName(usern, vcp->rname, SMB_FLAG_CREATE);
911         lock_ObtainMutex(&unp->mx);
912         if (unp->flags & SMB_USERNAMEFLAG_AFSLOGON) {
913             /* clear the afslogon flag so that the tickets can now 
914              * be freed when the refCount returns to zero.
915              */
916             unp->flags &= ~SMB_USERNAMEFLAG_AFSLOGON;
917         }
918         lock_ReleaseMutex(&unp->mx);
919
920         /* Create a new UID and cm_user_t structure */
921         userp = unp->userp;
922         if (!userp)
923             userp = cm_NewUser();
924         cm_HoldUserVCRef(userp);
925         lock_ObtainMutex(&vcp->mx);
926         if (!vcp->uidCounter)
927             vcp->uidCounter++; /* handle unlikely wraparounds */
928         newUid = (cm_ClientStrLen(usern)==0)?0:vcp->uidCounter++;
929         lock_ReleaseMutex(&vcp->mx);
930
931         /* Create a new smb_user_t structure and connect them up */
932         lock_ObtainMutex(&unp->mx);
933         unp->userp = userp;
934         lock_ReleaseMutex(&unp->mx);
935
936         uidp = smb_FindUID(vcp, newUid, SMB_FLAG_CREATE);
937         if (uidp) {
938             lock_ObtainMutex(&uidp->mx);
939             uidp->unp = unp;
940             osi_Log4(smb_logp,"smb_ReceiveV3SessionSetupX MakeNewUser:VCP[%p],Lana[%d],lsn[%d],userid[%d]",vcp,vcp->lana,vcp->lsn,newUid);
941             lock_ReleaseMutex(&uidp->mx);
942             smb_ReleaseUID(uidp);
943         }
944     }
945
946     /* Return UID to the client */
947     ((smb_t *)outp)->uid = newUid;
948     /* Also to the next chained message */
949     ((smb_t *)inp)->uid = newUid;
950
951     osi_Log3(smb_logp, "SMB3 session setup name %S creating ID %d%S",
952              osi_LogSaveClientString(smb_logp, usern), newUid,
953              osi_LogSaveClientString(smb_logp, s1));
954
955     smb_SetSMBParm(outp, 2, 0);
956
957     if (vcp->flags & SMB_VCFLAG_USENT) {
958         if (smb_authType == SMB_AUTH_EXTENDED) {
959             size_t cb_data = 0;
960
961             smb_SetSMBParm(outp, 3, secBlobOutLength);
962
963             tp = smb_GetSMBData(outp, NULL);
964             if (secBlobOutLength) {
965                 memcpy(tp, secBlobOut, secBlobOutLength);
966                 free(secBlobOut);
967                 tp += secBlobOutLength;
968                 cb_data +=  secBlobOutLength;
969             }   
970
971             tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
972             tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
973             tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
974
975             smb_SetSMBDataLength(outp, cb_data);
976         } else {
977             smb_SetSMBDataLength(outp, 0);
978         }
979     } else {
980         if (smb_authType == SMB_AUTH_EXTENDED) {
981             size_t cb_data = 0;
982
983             tp = smb_GetSMBData(outp, NULL);
984
985             tp = smb_UnparseString(outp, tp, smb_ServerOS, &cb_data, 0);
986             tp = smb_UnparseString(outp, tp, smb_ServerLanManager, &cb_data, 0);
987             tp = smb_UnparseString(outp, tp, smb_ServerDomainName, &cb_data, 0);
988
989             smb_SetSMBDataLength(outp, cb_data);
990         } else {
991             smb_SetSMBDataLength(outp, 0);
992         }
993     }
994
995     return 0;
996 }
997
998 /* SMB_COM_LOGOFF_ANDX */
999 long smb_ReceiveV3UserLogoffX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1000 {
1001     smb_user_t *uidp;
1002
1003     /* find the tree and free it */
1004     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1005     if (uidp) {
1006         smb_username_t * unp;
1007
1008         osi_Log2(smb_logp, "SMB3 user logoffX uid %d name %S", uidp->userID,
1009                  osi_LogSaveClientString(smb_logp, (uidp->unp) ? uidp->unp->name: _C(" ")));
1010
1011         lock_ObtainMutex(&uidp->mx);
1012         uidp->flags |= SMB_USERFLAG_DELETE;
1013         /*
1014          * it doesn't get deleted right away
1015          * because the vcp points to it
1016          */
1017         unp = uidp->unp;
1018         lock_ReleaseMutex(&uidp->mx);
1019
1020 #ifdef COMMENT
1021         /* we can't do this.  we get logoff messages prior to a session
1022          * disconnect even though it doesn't mean the user is logging out.
1023          * we need to create a new pioctl and EventLogoff handler to set
1024          * SMB_USERNAMEFLAG_LOGOFF.
1025          */
1026         if (unp && smb_LogoffTokenTransfer) {
1027             lock_ObtainMutex(&unp->mx);
1028             unp->flags |= SMB_USERNAMEFLAG_LOGOFF;
1029             unp->last_logoff_t = osi_Time() + smb_LogoffTransferTimeout;
1030             lock_ReleaseMutex(&unp->mx);
1031         }
1032 #endif
1033
1034         smb_ReleaseUID(uidp);
1035     }
1036     else    
1037         osi_Log0(smb_logp, "SMB3 user logoffX");
1038
1039     smb_SetSMBDataLength(outp, 0);
1040     return 0;
1041 }
1042
1043 #define SMB_SUPPORT_SEARCH_BITS        0x0001
1044 #define SMB_SHARE_IS_IN_DFS            0x0002
1045
1046 /* SMB_COM_TREE_CONNECT_ANDX */
1047 long smb_ReceiveV3TreeConnectX(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1048 {
1049     smb_tid_t *tidp;
1050     smb_user_t *uidp = NULL;
1051     unsigned short newTid;
1052     clientchar_t shareName[AFSPATHMAX];
1053     clientchar_t *sharePath;
1054     int shareFound;
1055     char *tp;
1056     clientchar_t *slashp;
1057     clientchar_t *pathp;
1058     clientchar_t *passwordp;
1059     clientchar_t *servicep;
1060     cm_user_t *userp = NULL;
1061     int ipc = 0;
1062         
1063     osi_Log0(smb_logp, "SMB3 receive tree connect");
1064
1065     /* parse input parameters */
1066     tp = smb_GetSMBData(inp, NULL);
1067     passwordp = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1068     pathp = smb_ParseString(inp, tp, &tp, SMB_STRF_ANSIPATH);
1069     servicep = smb_ParseString(inp, tp, &tp, SMB_STRF_FORCEASCII);
1070
1071     slashp = cm_ClientStrRChr(pathp, '\\');
1072     if (!slashp) {
1073         return CM_ERROR_BADSMB;
1074     }
1075     cm_ClientStrCpy(shareName, lengthof(shareName), slashp+1);
1076
1077     osi_Log3(smb_logp, "Tree connect pathp[%S] shareName[%S] service[%S]",
1078              osi_LogSaveClientString(smb_logp, pathp),
1079              osi_LogSaveClientString(smb_logp, shareName),
1080              osi_LogSaveClientString(smb_logp, servicep));
1081
1082     if (cm_ClientStrCmp(servicep, _C("IPC")) == 0 ||
1083         cm_ClientStrCmp(shareName, _C("IPC$")) == 0) {
1084 #ifndef NO_IPC
1085         osi_Log0(smb_logp, "TreeConnectX connecting to IPC$");
1086         ipc = 1;
1087 #else
1088         return CM_ERROR_NOIPC;
1089 #endif
1090     }
1091
1092     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1093     if (uidp)
1094         userp = smb_GetUserFromUID(uidp);
1095
1096     lock_ObtainMutex(&vcp->mx);
1097     newTid = vcp->tidCounter++;
1098     lock_ReleaseMutex(&vcp->mx);
1099         
1100     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1101
1102     if (!ipc) {
1103         if (!cm_ClientStrCmp(shareName, _C("*.")))
1104             cm_ClientStrCpy(shareName, lengthof(shareName), _C("all"));
1105         shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
1106         if (!shareFound) {
1107             if (uidp)
1108                 smb_ReleaseUID(uidp);
1109             smb_ReleaseTID(tidp, FALSE);
1110             return CM_ERROR_BADSHARENAME;
1111         }
1112
1113         if (vcp->flags & SMB_VCFLAG_USENT)
1114         {
1115             int policy = smb_FindShareCSCPolicy(shareName);
1116             HKEY parmKey;
1117             DWORD code;
1118             DWORD dwAdvertiseDFS = 0, dwSize = sizeof(DWORD);
1119
1120             code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1121                                  0, KEY_QUERY_VALUE, &parmKey);
1122             if (code == ERROR_SUCCESS) {
1123                 code = RegQueryValueEx(parmKey, "AdvertiseDFS", NULL, NULL,
1124                                        (BYTE *)&dwAdvertiseDFS, &dwSize);
1125                 if (code != ERROR_SUCCESS)
1126                     dwAdvertiseDFS = 0;
1127                 RegCloseKey (parmKey);
1128             }
1129             smb_SetSMBParm(outp, 2, SMB_SUPPORT_SEARCH_BITS | 
1130                            (dwAdvertiseDFS ? SMB_SHARE_IS_IN_DFS : 0) |
1131                            (policy << 2));
1132         }
1133     } else {
1134         smb_SetSMBParm(outp, 2, 0);
1135         sharePath = NULL;
1136     }
1137     if (uidp)
1138         smb_ReleaseUID(uidp);
1139
1140     lock_ObtainMutex(&tidp->mx);
1141     tidp->userp = userp;
1142     tidp->pathname = sharePath;
1143     if (ipc) 
1144         tidp->flags |= SMB_TIDFLAG_IPC;
1145     lock_ReleaseMutex(&tidp->mx);
1146     smb_ReleaseTID(tidp, FALSE);
1147
1148     ((smb_t *)outp)->tid = newTid;
1149     ((smb_t *)inp)->tid = newTid;
1150     tp = smb_GetSMBData(outp, NULL);
1151     if (!ipc) {
1152         size_t cb_data = 0;
1153
1154         tp = smb_UnparseString(outp, tp, _C("A:"), &cb_data, SMB_STRF_FORCEASCII);
1155         tp = smb_UnparseString(outp, tp, _C("AFS"), &cb_data, 0);
1156         smb_SetSMBDataLength(outp, cb_data);
1157     } else {
1158         size_t cb_data = 0;
1159
1160         tp = smb_UnparseString(outp, tp, _C("IPC"), &cb_data, SMB_STRF_FORCEASCII);
1161         smb_SetSMBDataLength(outp, cb_data);
1162     }
1163
1164     osi_Log1(smb_logp, "SMB3 tree connect created ID %d", newTid);
1165     return 0;
1166 }
1167
1168 /* must be called with global tran lock held */
1169 smb_tran2Packet_t *smb_FindTran2Packet(smb_vc_t *vcp, smb_packet_t *inp)
1170 {
1171     smb_tran2Packet_t *tp;
1172     smb_t *smbp;
1173         
1174     smbp = (smb_t *) inp->data;
1175     for (tp = smb_tran2AssemblyQueuep; tp; tp = (smb_tran2Packet_t *) osi_QNext(&tp->q)) {
1176         if (tp->vcp == vcp && tp->mid == smbp->mid && tp->tid == smbp->tid)
1177             return tp;
1178     }
1179     return NULL;
1180 }
1181
1182 smb_tran2Packet_t *smb_NewTran2Packet(smb_vc_t *vcp, smb_packet_t *inp,
1183                                       int totalParms, int totalData)
1184 {
1185     smb_tran2Packet_t *tp;
1186     smb_t *smbp;
1187         
1188     smbp = (smb_t *) inp->data;
1189     tp = malloc(sizeof(*tp));
1190     memset(tp, 0, sizeof(*tp));
1191     tp->vcp = vcp;
1192     smb_HoldVC(vcp);
1193     tp->curData = tp->curParms = 0;
1194     tp->totalData = totalData;
1195     tp->totalParms = totalParms;
1196     tp->tid = smbp->tid;
1197     tp->mid = smbp->mid;
1198     tp->uid = smbp->uid;
1199     tp->pid = smbp->pid;
1200     tp->res[0] = smbp->res[0];
1201     osi_QAdd((osi_queue_t **)&smb_tran2AssemblyQueuep, &tp->q);
1202     if (totalParms != 0)
1203         tp->parmsp = malloc(totalParms);
1204     if (totalData != 0)
1205         tp->datap = malloc(totalData);
1206     if (smbp->com == 0x25 || smbp->com == 0x26)
1207         tp->com = 0x25;
1208     else {
1209         tp->opcode = smb_GetSMBParm(inp, 14);
1210         tp->com = 0x32;
1211     }
1212     tp->flags |= SMB_TRAN2PFLAG_ALLOC;
1213 #ifdef SMB_UNICODE
1214     if (WANTS_UNICODE(inp) && (vcp->flags & SMB_VCFLAG_USEUNICODE))
1215         tp->flags |= SMB_TRAN2PFLAG_USEUNICODE;
1216 #endif
1217     return tp;
1218 }
1219
1220 smb_tran2Packet_t *smb_GetTran2ResponsePacket(smb_vc_t *vcp,
1221                                               smb_tran2Packet_t *inp, smb_packet_t *outp,
1222                                               int totalParms, int totalData)  
1223 {
1224     smb_tran2Packet_t *tp;
1225     unsigned short parmOffset;
1226     unsigned short dataOffset;
1227     unsigned short dataAlign;
1228
1229     tp = malloc(sizeof(*tp));
1230     memset(tp, 0, sizeof(*tp));
1231     smb_HoldVC(vcp);
1232     tp->vcp = vcp;
1233     tp->curData = tp->curParms = 0;
1234     tp->totalData = totalData;
1235     tp->totalParms = totalParms;
1236     tp->oldTotalParms = totalParms;
1237     tp->tid = inp->tid;
1238     tp->mid = inp->mid;
1239     tp->uid = inp->uid;
1240     tp->pid = inp->pid;
1241     tp->res[0] = inp->res[0];
1242     tp->opcode = inp->opcode;
1243     tp->com = inp->com;
1244
1245     /*
1246      * We calculate where the parameters and data will start.
1247      * This calculation must parallel the calculation in
1248      * smb_SendTran2Packet.
1249      */
1250
1251     parmOffset = 10*2 + 35;
1252     parmOffset++;                       /* round to even */
1253     tp->parmsp = (unsigned short *) (outp->data + parmOffset);
1254
1255     dataOffset = parmOffset + totalParms;
1256     dataAlign = dataOffset & 2; /* quad-align */
1257     dataOffset += dataAlign;
1258     tp->datap = outp->data + dataOffset;
1259
1260     return tp;
1261 }       
1262
1263 /* free a tran2 packet */
1264 void smb_FreeTran2Packet(smb_tran2Packet_t *t2p)
1265 {
1266     if (t2p->vcp) {
1267         smb_ReleaseVC(t2p->vcp);
1268         t2p->vcp = NULL;
1269     }
1270     if (t2p->flags & SMB_TRAN2PFLAG_ALLOC) {
1271         if (t2p->parmsp)
1272             free(t2p->parmsp);
1273         if (t2p->datap)
1274             free(t2p->datap);
1275     }       
1276     while (t2p->stringsp) {
1277         cm_space_t * ns;
1278
1279         ns = t2p->stringsp;
1280         t2p->stringsp = ns->nextp;
1281         cm_FreeSpace(ns);
1282     }
1283     free(t2p);
1284 }
1285
1286 clientchar_t *smb_ParseStringT2Parm(smb_tran2Packet_t * p, unsigned char * inp,
1287                                     char ** chainpp, int flags)
1288 {
1289     size_t cb;
1290
1291 #ifdef SMB_UNICODE
1292     if (!(p->flags & SMB_TRAN2PFLAG_USEUNICODE))
1293         flags |= SMB_STRF_FORCEASCII;
1294 #endif
1295
1296     cb = p->totalParms - (inp - (char *)p->parmsp);
1297     if (inp < (char *) p->parmsp ||
1298         inp >= ((char *) p->parmsp) + p->totalParms) {
1299 #ifdef DEBUG_UNICODE
1300         DebugBreak();
1301 #endif
1302         cb = p->totalParms;
1303     }
1304
1305     return smb_ParseStringBuf((unsigned char *) p->parmsp, &p->stringsp,
1306                               inp, &cb, chainpp, flags);
1307 }
1308
1309 /* called with a VC, an input packet to respond to, and an error code.
1310  * sends an error response.
1311  */
1312 void smb_SendTran2Error(smb_vc_t *vcp, smb_tran2Packet_t *t2p,
1313                         smb_packet_t *tp, long code)
1314 {
1315     smb_t *smbp;
1316     unsigned short errCode;
1317     unsigned char errClass;
1318     unsigned long NTStatus;
1319
1320     if (vcp->flags & SMB_VCFLAG_STATUS32)
1321         smb_MapNTError(code, &NTStatus);
1322     else
1323         smb_MapCoreError(code, vcp, &errCode, &errClass);
1324
1325     smb_FormatResponsePacket(vcp, NULL, tp);
1326     smbp = (smb_t *) tp;
1327
1328     /* We can handle long names */
1329     if (vcp->flags & SMB_VCFLAG_USENT)
1330         smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1331         
1332     /* now copy important fields from the tran 2 packet */
1333     smbp->com = t2p->com;
1334     smbp->tid = t2p->tid;
1335     smbp->mid = t2p->mid;
1336     smbp->pid = t2p->pid;
1337     smbp->uid = t2p->uid;
1338     smbp->res[0] = t2p->res[0];
1339     if (vcp->flags & SMB_VCFLAG_STATUS32) {
1340         smbp->rcls = (unsigned char) (NTStatus & 0xff);
1341         smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
1342         smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
1343         smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
1344         smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
1345     }
1346     else {
1347         smbp->rcls = errClass;
1348         smbp->errLow = (unsigned char) (errCode & 0xff);
1349         smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
1350     }
1351         
1352     /* send packet */
1353     smb_SendPacket(vcp, tp);
1354 }        
1355
1356 void smb_SendTran2Packet(smb_vc_t *vcp, smb_tran2Packet_t *t2p, smb_packet_t *tp)
1357 {
1358     smb_t *smbp;
1359     unsigned short parmOffset;
1360     unsigned short dataOffset;
1361     unsigned short totalLength;
1362     unsigned short dataAlign;
1363     char *datap;
1364
1365     smb_FormatResponsePacket(vcp, NULL, tp);
1366     smbp = (smb_t *) tp;
1367
1368     /* We can handle long names */
1369     if (vcp->flags & SMB_VCFLAG_USENT)
1370         smbp->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
1371
1372     /* now copy important fields from the tran 2 packet */
1373     smbp->com = t2p->com;
1374     smbp->tid = t2p->tid;
1375     smbp->mid = t2p->mid;
1376     smbp->pid = t2p->pid;
1377     smbp->uid = t2p->uid;
1378     smbp->res[0] = t2p->res[0];
1379
1380     totalLength = 1 + t2p->totalData + t2p->totalParms;
1381
1382     /* now add the core parameters (tran2 info) to the packet */
1383     smb_SetSMBParm(tp, 0, t2p->totalParms);     /* parm bytes */
1384     smb_SetSMBParm(tp, 1, t2p->totalData);      /* data bytes */
1385     smb_SetSMBParm(tp, 2, 0);           /* reserved */
1386     smb_SetSMBParm(tp, 3, t2p->totalParms);     /* parm bytes in this packet */
1387     parmOffset = 10*2 + 35;                     /* parm offset in packet */
1388     parmOffset++;                               /* round to even */
1389     smb_SetSMBParm(tp, 4, parmOffset);  /* 11 parm words plus *
1390     * hdr, bcc and wct */
1391     smb_SetSMBParm(tp, 5, 0);           /* parm displacement */
1392     smb_SetSMBParm(tp, 6, t2p->totalData);      /* data in this packet */
1393     dataOffset = parmOffset + t2p->oldTotalParms;
1394     dataAlign = dataOffset & 2;         /* quad-align */
1395     dataOffset += dataAlign;
1396     smb_SetSMBParm(tp, 7, dataOffset);  /* offset of data */
1397     smb_SetSMBParm(tp, 8, 0);           /* data displacement */
1398     smb_SetSMBParm(tp, 9, 0);           /* low: setup word count *
1399                                          * high: resvd */
1400
1401     datap = smb_GetSMBData(tp, NULL);
1402     *datap++ = 0;                               /* we rounded to even */
1403
1404     totalLength += dataAlign;
1405     smb_SetSMBDataLength(tp, totalLength);
1406         
1407     /* next, send the datagram */
1408     smb_SendPacket(vcp, tp);
1409 }   
1410
1411
1412 /* SMB_COM_TRANSACTION and SMB_COM_TRANSACTION_SECONDARY */
1413 long smb_ReceiveV3Trans(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1414 {
1415     smb_tran2Packet_t *asp;
1416     int totalParms;
1417     int totalData;
1418     int parmDisp;
1419     int dataDisp;
1420     int parmOffset;
1421     int dataOffset;
1422     int parmCount;
1423     int dataCount;
1424     int firstPacket;
1425     int rapOp;
1426     long code = 0;
1427
1428     /* We sometimes see 0 word count.  What to do? */
1429     if (*inp->wctp == 0) {
1430         osi_Log0(smb_logp, "Transaction2 word count = 0"); 
1431         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1432
1433         smb_SetSMBDataLength(outp, 0);
1434         smb_SendPacket(vcp, outp);
1435         return 0;
1436     }
1437
1438     totalParms = smb_GetSMBParm(inp, 0);
1439     totalData = smb_GetSMBParm(inp, 1);
1440         
1441     firstPacket = (inp->inCom == 0x25);
1442         
1443     /* find the packet we're reassembling */
1444     lock_ObtainWrite(&smb_globalLock);
1445     asp = smb_FindTran2Packet(vcp, inp);
1446     if (!asp) {
1447         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1448     }
1449     lock_ReleaseWrite(&smb_globalLock);
1450         
1451     /* now merge in this latest packet; start by looking up offsets */
1452     if (firstPacket) {
1453         parmDisp = dataDisp = 0;
1454         parmOffset = smb_GetSMBParm(inp, 10);
1455         dataOffset = smb_GetSMBParm(inp, 12);
1456         parmCount = smb_GetSMBParm(inp, 9);
1457         dataCount = smb_GetSMBParm(inp, 11);
1458         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1459         asp->maxReturnData = smb_GetSMBParm(inp, 3);
1460
1461         osi_Log3(smb_logp, "SMB3 received Trans init packet total data %d, cur data %d, max return data %d",
1462                   totalData, dataCount, asp->maxReturnData);
1463     }
1464     else {
1465         parmDisp = smb_GetSMBParm(inp, 4);
1466         parmOffset = smb_GetSMBParm(inp, 3);
1467         dataDisp = smb_GetSMBParm(inp, 7);
1468         dataOffset = smb_GetSMBParm(inp, 6);
1469         parmCount = smb_GetSMBParm(inp, 2);
1470         dataCount = smb_GetSMBParm(inp, 5);
1471
1472         osi_Log2(smb_logp, "SMB3 received Trans aux packet parms %d, data %d",
1473                  parmCount, dataCount);
1474     }   
1475
1476     /* now copy the parms and data */
1477     if ( asp->totalParms > 0 && parmCount != 0 )
1478     {
1479         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1480     }
1481     if ( asp->totalData > 0 && dataCount != 0 ) {
1482         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1483     }
1484
1485     /* account for new bytes */
1486     asp->curData += dataCount;
1487     asp->curParms += parmCount;
1488
1489     /* finally, if we're done, remove the packet from the queue and dispatch it */
1490     if (asp->totalParms > 0 &&
1491         asp->curParms > 0 &&
1492         asp->totalData <= asp->curData &&
1493         asp->totalParms <= asp->curParms) {
1494         /* we've received it all */
1495         lock_ObtainWrite(&smb_globalLock);
1496         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
1497         lock_ReleaseWrite(&smb_globalLock);
1498
1499         /* now dispatch it */
1500         rapOp = asp->parmsp[0];
1501
1502         if ( rapOp >= 0 && rapOp < SMB_RAP_NOPCODES && smb_rapDispatchTable[rapOp].procp) {
1503             osi_Log4(smb_logp,"AFS Server - Dispatch-RAP %s vcp[%p] lana[%d] lsn[%d]",myCrt_RapDispatch(rapOp),vcp,vcp->lana,vcp->lsn);
1504             code = (*smb_rapDispatchTable[rapOp].procp)(vcp, asp, outp);
1505             osi_Log4(smb_logp,"AFS Server - Dispatch-RAP return  code 0x%x vcp[%x] lana[%d] lsn[%d]",code,vcp,vcp->lana,vcp->lsn);
1506         }
1507         else {
1508             osi_Log4(smb_logp,"AFS Server - Dispatch-RAP [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", rapOp, vcp, vcp->lana, vcp->lsn);
1509             code = CM_ERROR_BADOP;
1510         }
1511
1512         /* if an error is returned, we're supposed to send an error packet,
1513          * otherwise the dispatched function already did the data sending.
1514          * We give dispatched proc the responsibility since it knows how much
1515          * space to allocate.
1516          */
1517         if (code != 0) {
1518             smb_SendTran2Error(vcp, asp, outp, code);
1519         }
1520
1521         /* free the input tran 2 packet */
1522         smb_FreeTran2Packet(asp);
1523     }
1524     else if (firstPacket) {
1525         /* the first packet in a multi-packet request, we need to send an
1526          * ack to get more data.
1527          */
1528         smb_SetSMBDataLength(outp, 0);
1529         smb_SendPacket(vcp, outp);
1530     }
1531
1532     return 0;
1533 }
1534
1535 /* ANSI versions. */
1536
1537 #pragma pack(push, 1)
1538
1539 typedef struct smb_rap_share_info_0 {
1540     BYTE                shi0_netname[13];
1541 } smb_rap_share_info_0_t;
1542
1543 typedef struct smb_rap_share_info_1 {
1544     BYTE                shi1_netname[13];
1545     BYTE                shi1_pad;
1546     WORD                        shi1_type;
1547     DWORD                       shi1_remark; /* char *shi1_remark; data offset */
1548 } smb_rap_share_info_1_t;
1549
1550 typedef struct smb_rap_share_info_2 {
1551     BYTE                shi2_netname[13];
1552     BYTE                shi2_pad;
1553     WORD                shi2_type;
1554     DWORD                       shi2_remark; /* char *shi2_remark; data offset */
1555     WORD                shi2_permissions;
1556     WORD                shi2_max_uses;
1557     WORD                shi2_current_uses;
1558     DWORD                       shi2_path;  /* char *shi2_path; data offset */
1559     WORD                shi2_passwd[9];
1560     WORD                shi2_pad2;
1561 } smb_rap_share_info_2_t;
1562
1563 #define SMB_RAP_MAX_SHARES 512
1564
1565 typedef struct smb_rap_share_list {
1566     int cShare;
1567     int maxShares;
1568     smb_rap_share_info_0_t * shares;
1569 } smb_rap_share_list_t;
1570
1571 #pragma pack(pop)
1572
1573 int smb_rapCollectSharesProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp) {
1574     smb_rap_share_list_t * sp;
1575
1576     if (dep->name[0] == '.' && (!dep->name[1] || (dep->name[1] == '.' && !dep->name[2])))
1577         return 0; /* skip over '.' and '..' */
1578
1579     sp = (smb_rap_share_list_t *) vrockp;
1580
1581     strncpy(sp->shares[sp->cShare].shi0_netname, dep->name, 12);
1582     sp->shares[sp->cShare].shi0_netname[12] = 0;
1583
1584     sp->cShare++;
1585
1586     if (sp->cShare >= sp->maxShares)
1587         return CM_ERROR_STOPNOW;
1588     else
1589         return 0;
1590 }       
1591
1592 /* RAP NetShareEnumRequest */
1593 long smb_ReceiveRAPNetShareEnum(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1594 {
1595     smb_tran2Packet_t *outp;
1596     unsigned short * tp;
1597     int len;
1598     int infoLevel;
1599     int bufsize;
1600     int outParmsTotal;  /* total parameter bytes */
1601     int outDataTotal;   /* total data bytes */
1602     int code = 0;
1603     DWORD rv;
1604     DWORD allSubmount = 0;
1605     USHORT nShares = 0;
1606     DWORD nRegShares = 0;
1607     DWORD nSharesRet = 0;
1608     HKEY hkParam;
1609     HKEY hkSubmount = NULL;
1610     smb_rap_share_info_1_t * shares;
1611     USHORT cshare = 0;
1612     char * cstrp;
1613     clientchar_t thisShare[AFSPATHMAX];
1614     int i,j;
1615     DWORD dw;
1616     int nonrootShares;
1617     smb_rap_share_list_t rootShares;
1618     cm_req_t req;
1619     cm_user_t * userp;
1620     osi_hyper_t thyper;
1621
1622     tp = p->parmsp + 1; /* skip over function number (always 0) */
1623
1624     {
1625         clientchar_t * cdescp;
1626
1627         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1628         if (cm_ClientStrCmp(cdescp,  _C("WrLeh")))
1629             return CM_ERROR_INVAL;
1630         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1631         if (cm_ClientStrCmp(cdescp,  _C("B13BWz")))
1632             return CM_ERROR_INVAL;
1633     }
1634
1635     infoLevel = tp[0];
1636     bufsize = tp[1];
1637
1638     if (infoLevel != 1) {
1639         return CM_ERROR_INVAL;
1640     }
1641
1642     /* We are supposed to use the same ASCII data structure even if
1643        Unicode is negotiated, which ultimately means that the share
1644        names that we return must be at most 13 characters in length,
1645        including the NULL terminator.
1646
1647        The RAP specification states that shares with names longer than
1648        12 characters should not be included in the enumeration.
1649        However, since we support prefix cell references and since many
1650        cell names are going to exceed 12 characters, we lie and send
1651        the first 12 characters.
1652     */
1653
1654     /* first figure out how many shares there are */
1655     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1656                       KEY_QUERY_VALUE, &hkParam);
1657     if (rv == ERROR_SUCCESS) {
1658         len = sizeof(allSubmount);
1659         rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1660                              (BYTE *) &allSubmount, &len);
1661         if (rv != ERROR_SUCCESS || allSubmount != 0) {
1662             allSubmount = 1;
1663         }
1664         RegCloseKey (hkParam);
1665     }
1666
1667     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1668                       0, KEY_QUERY_VALUE, &hkSubmount);
1669     if (rv == ERROR_SUCCESS) {
1670         rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1671                              NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1672         if (rv != ERROR_SUCCESS)
1673             nRegShares = 0;
1674     } else {
1675         hkSubmount = NULL;
1676     }
1677
1678     /* fetch the root shares */
1679     rootShares.maxShares = SMB_RAP_MAX_SHARES;
1680     rootShares.cShare = 0;
1681     rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1682
1683     smb_InitReq(&req);
1684
1685     userp = smb_GetTran2User(vcp,p);
1686
1687     thyper.HighPart = 0;
1688     thyper.LowPart = 0;
1689
1690     cm_HoldSCache(cm_data.rootSCachep);
1691     cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1692     cm_ReleaseSCache(cm_data.rootSCachep);
1693
1694     cm_ReleaseUser(userp);
1695
1696     nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1697
1698 #define REMARK_LEN 1
1699     outParmsTotal = 8; /* 4 dwords */
1700     outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1701     if(outDataTotal > bufsize) {
1702         nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1703         outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1704     }
1705     else {
1706         nSharesRet = nShares;
1707     }
1708     
1709     outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1710
1711     /* now for the submounts */
1712     shares = (smb_rap_share_info_1_t *) outp->datap;
1713     cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1714
1715     memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1716
1717     if (allSubmount) {
1718         StringCchCopyA(shares[cshare].shi1_netname,
1719                        lengthof(shares[cshare].shi1_netname), "all" );
1720         shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1721         /* type and pad are zero already */
1722         cshare++;
1723         cstrp+=REMARK_LEN;
1724     }
1725
1726     if (hkSubmount) {
1727         for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1728             len = sizeof(thisShare);
1729             rv = RegEnumValueW(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1730             if (rv == ERROR_SUCCESS &&
1731                 cm_ClientStrLen(thisShare) &&
1732                 (!allSubmount || cm_ClientStrCmpI(thisShare,_C("all")))) {
1733                 cm_ClientStringToUtf8(thisShare, -1, shares[cshare].shi1_netname,
1734                                       lengthof( shares[cshare].shi1_netname ));
1735                 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1736                 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1737                 cshare++;
1738                 cstrp+=REMARK_LEN;
1739             }
1740             else
1741                 nShares--; /* uncount key */
1742         }
1743
1744         RegCloseKey(hkSubmount);
1745     }
1746
1747     nonrootShares = cshare;
1748
1749     for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1750         /* in case there are collisions with submounts, submounts have
1751            higher priority */           
1752         for (j=0; j < nonrootShares; j++)
1753             if (!cm_stricmp_utf8(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1754                 break;
1755                 
1756         if (j < nonrootShares) {
1757             nShares--; /* uncount */
1758             continue;
1759         }
1760
1761         StringCchCopyA(shares[cshare].shi1_netname, lengthof(shares[cshare].shi1_netname),
1762                        rootShares.shares[i].shi0_netname);
1763         shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1764         cshare++;
1765         cstrp+=REMARK_LEN;
1766     }
1767
1768     outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1769     outp->parmsp[1] = 0;
1770     outp->parmsp[2] = cshare;
1771     outp->parmsp[3] = nShares;
1772
1773     outp->totalData = (int)(cstrp - outp->datap);
1774     outp->totalParms = outParmsTotal;
1775
1776     smb_SendTran2Packet(vcp, outp, op);
1777     smb_FreeTran2Packet(outp);
1778
1779     free(rootShares.shares);
1780
1781     return code;
1782 }
1783
1784 /* RAP NetShareGetInfo */
1785 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1786 {
1787     smb_tran2Packet_t *outp;
1788     unsigned short * tp;
1789     clientchar_t * shareName;
1790     BOOL shareFound = FALSE;
1791     unsigned short infoLevel;
1792     unsigned short bufsize;
1793     int totalData;
1794     int totalParam;
1795     DWORD len;
1796     HKEY hkParam;
1797     HKEY hkSubmount;
1798     DWORD allSubmount;
1799     LONG rv;
1800     long code = 0;
1801     cm_scache_t *scp = NULL;
1802     cm_user_t   *userp;
1803     cm_req_t    req;
1804
1805     smb_InitReq(&req);
1806
1807     tp = p->parmsp + 1; /* skip over function number (always 1) */
1808
1809     {
1810         clientchar_t * cdescp;
1811
1812         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1813         if (cm_ClientStrCmp(cdescp,  _C("zWrLh")))
1814
1815             return CM_ERROR_INVAL;
1816
1817         cdescp = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1818         if (cm_ClientStrCmp(cdescp,  _C("B13")) &&
1819             cm_ClientStrCmp(cdescp,  _C("B13BWz")) &&
1820             cm_ClientStrCmp(cdescp,  _C("B13BWzWWWzB9B")))
1821
1822             return CM_ERROR_INVAL;
1823     }
1824     shareName = smb_ParseStringT2Parm(p, (char *) tp, (char **) &tp, SMB_STRF_FORCEASCII);
1825
1826     infoLevel = *tp++;
1827     bufsize = *tp++;
1828     
1829     totalParam = 6;
1830
1831     if (infoLevel == 0)
1832         totalData = sizeof(smb_rap_share_info_0_t);
1833     else if(infoLevel == SMB_INFO_STANDARD)
1834         totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1835     else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1836         totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1837     else
1838         return CM_ERROR_INVAL;
1839
1840     if(!cm_ClientStrCmpI(shareName, _C("all")) || !cm_ClientStrCmp(shareName,_C("*."))) {
1841         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1842                           KEY_QUERY_VALUE, &hkParam);
1843         if (rv == ERROR_SUCCESS) {
1844             len = sizeof(allSubmount);
1845             rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1846                                   (BYTE *) &allSubmount, &len);
1847             if (rv != ERROR_SUCCESS || allSubmount != 0) {
1848                 allSubmount = 1;
1849             }
1850             RegCloseKey (hkParam);
1851         }
1852
1853         if (allSubmount)
1854             shareFound = TRUE;
1855
1856     } else {
1857         userp = smb_GetTran2User(vcp, p);
1858         if (!userp) {
1859             osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
1860             return CM_ERROR_BADSMB;
1861         }   
1862         code = cm_NameI(cm_data.rootSCachep, shareName,
1863                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD | CM_FLAG_DFS_REFERRAL,
1864                          userp, NULL, &req, &scp);
1865         if (code == 0) {
1866             cm_ReleaseSCache(scp);
1867             shareFound = TRUE;
1868         } else {
1869             rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1870                               KEY_QUERY_VALUE, &hkSubmount);
1871             if (rv == ERROR_SUCCESS) {
1872                 rv = RegQueryValueExW(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1873                 if (rv == ERROR_SUCCESS) {
1874                     shareFound = TRUE;
1875                 }
1876                 RegCloseKey(hkSubmount);
1877             }
1878         }
1879     }
1880
1881     if (!shareFound)
1882         return CM_ERROR_BADSHARENAME;
1883
1884     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1885     memset(outp->datap, 0, totalData);
1886
1887     outp->parmsp[0] = 0;
1888     outp->parmsp[1] = 0;
1889     outp->parmsp[2] = totalData;
1890
1891     if (infoLevel == 0) {
1892         smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1893         cm_ClientStringToUtf8(shareName, -1, info->shi0_netname,
1894                               lengthof(info->shi0_netname));
1895     } else if(infoLevel == SMB_INFO_STANDARD) {
1896         smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1897         cm_ClientStringToUtf8(shareName, -1, info->shi1_netname, lengthof(info->shi1_netname));
1898         info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1899         info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1900         /* type and pad are already zero */
1901     } else { /* infoLevel==2 */
1902         smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1903         cm_ClientStringToUtf8(shareName, -1, info->shi2_netname, lengthof(info->shi2_netname));
1904         info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1905         info->shi2_permissions = ACCESS_ALL;
1906         info->shi2_max_uses = (unsigned short) -1;
1907         info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1908     }
1909
1910     outp->totalData = totalData;
1911     outp->totalParms = totalParam;
1912
1913     smb_SendTran2Packet(vcp, outp, op);
1914     smb_FreeTran2Packet(outp);
1915
1916     return code;
1917 }
1918
1919 #pragma pack(push, 1)
1920
1921 typedef struct smb_rap_wksta_info_10 {
1922     DWORD       wki10_computername;     /*char *wki10_computername;*/
1923     DWORD       wki10_username; /* char *wki10_username; */
1924     DWORD       wki10_langroup; /* char *wki10_langroup;*/
1925     BYTE        wki10_ver_major;
1926     BYTE        wki10_ver_minor;
1927     DWORD       wki10_logon_domain;     /*char *wki10_logon_domain;*/
1928     DWORD       wki10_oth_domains; /* char *wki10_oth_domains;*/
1929 } smb_rap_wksta_info_10_t;
1930
1931 #pragma pack(pop)
1932
1933 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1934 {
1935     smb_tran2Packet_t *outp;
1936     long code = 0;
1937     int infoLevel;
1938     int bufsize;
1939     unsigned short * tp;
1940     int totalData;
1941     int totalParams;
1942     smb_rap_wksta_info_10_t * info;
1943     char * cstrp;
1944     smb_user_t *uidp;
1945
1946     tp = p->parmsp + 1; /* Skip over function number */
1947
1948     {
1949         clientchar_t * cdescp;
1950
1951         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1952                                        SMB_STRF_FORCEASCII);
1953         if (cm_ClientStrCmp(cdescp,  _C("WrLh")))
1954             return CM_ERROR_INVAL;
1955
1956         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
1957                                        SMB_STRF_FORCEASCII);
1958         if (cm_ClientStrCmp(cdescp,  _C("zzzBBzz")))
1959             return CM_ERROR_INVAL;
1960     }
1961
1962     infoLevel = *tp++;
1963     bufsize = *tp++;
1964
1965     if (infoLevel != 10) {
1966         return CM_ERROR_INVAL;
1967     }
1968
1969     totalParams = 6;
1970         
1971     /* infolevel 10 */
1972     totalData = sizeof(*info) +         /* info */
1973         MAX_COMPUTERNAME_LENGTH +       /* wki10_computername */
1974         SMB_MAX_USERNAME_LENGTH +       /* wki10_username */
1975         MAX_COMPUTERNAME_LENGTH +       /* wki10_langroup */
1976         MAX_COMPUTERNAME_LENGTH +       /* wki10_logon_domain */
1977         1;                              /* wki10_oth_domains (null)*/
1978
1979     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1980
1981     memset(outp->parmsp,0,totalParams);
1982     memset(outp->datap,0,totalData);
1983
1984     info = (smb_rap_wksta_info_10_t *) outp->datap;
1985     cstrp = (char *) (info + 1);
1986
1987     info->wki10_computername = (DWORD) (cstrp - outp->datap);
1988     StringCbCopyA(cstrp, totalData, smb_localNamep);
1989     cstrp += strlen(cstrp) + 1;
1990
1991     info->wki10_username = (DWORD) (cstrp - outp->datap);
1992     uidp = smb_FindUID(vcp, p->uid, 0);
1993     if (uidp) {
1994         lock_ObtainMutex(&uidp->mx);
1995         if(uidp->unp && uidp->unp->name)
1996             cm_ClientStringToUtf8(uidp->unp->name, -1,
1997                                   cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
1998         lock_ReleaseMutex(&uidp->mx);
1999         smb_ReleaseUID(uidp);
2000     }
2001     cstrp += strlen(cstrp) + 1;
2002
2003     info->wki10_langroup = (DWORD) (cstrp - outp->datap);
2004     StringCbCopyA(cstrp, totalData - (cstrp - outp->datap)*sizeof(char), "WORKGROUP");
2005     cstrp += strlen(cstrp) + 1;
2006
2007     /* TODO: Not sure what values these should take, but these work */
2008     info->wki10_ver_major = 5;
2009     info->wki10_ver_minor = 1;
2010
2011     info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
2012     cm_ClientStringToUtf8(smb_ServerDomainName, -1,
2013                           cstrp, totalData/sizeof(char) - (cstrp - outp->datap));
2014     cstrp += strlen(cstrp) + 1;
2015
2016     info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
2017     cstrp ++; /* no other domains */
2018
2019     outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
2020     outp->parmsp[2] = outp->totalData;
2021     outp->totalParms = totalParams;
2022
2023     smb_SendTran2Packet(vcp,outp,op);
2024     smb_FreeTran2Packet(outp);
2025
2026     return code;
2027 }
2028
2029 #pragma pack(push, 1)
2030
2031 typedef struct smb_rap_server_info_0 {
2032     BYTE    sv0_name[16];
2033 } smb_rap_server_info_0_t;
2034
2035 typedef struct smb_rap_server_info_1 {
2036     BYTE            sv1_name[16];
2037     BYTE            sv1_version_major;
2038     BYTE            sv1_version_minor;
2039     DWORD           sv1_type;
2040     DWORD           sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
2041 } smb_rap_server_info_1_t;
2042
2043 #pragma pack(pop)
2044
2045 char smb_ServerComment[] = "OpenAFS Client";
2046 int smb_ServerCommentLen = sizeof(smb_ServerComment);
2047
2048 #define SMB_SV_TYPE_SERVER              0x00000002L
2049 #define SMB_SV_TYPE_NT              0x00001000L
2050 #define SMB_SV_TYPE_SERVER_NT       0x00008000L
2051
2052 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2053 {
2054     smb_tran2Packet_t *outp;
2055     long code = 0;
2056     int infoLevel;
2057     int bufsize;
2058     unsigned short * tp;
2059     int totalData;
2060     int totalParams;
2061     smb_rap_server_info_0_t * info0;
2062     smb_rap_server_info_1_t * info1;
2063     char * cstrp;
2064
2065     tp = p->parmsp + 1; /* Skip over function number */
2066
2067     {
2068         clientchar_t * cdescp;
2069
2070         cdescp = smb_ParseStringT2Parm(p, (unsigned char *) tp, (char **) &tp,
2071                                        SMB_STRF_FORCEASCII);
2072         if (cm_ClientStrCmp(cdescp,  _C("WrLh")))
2073             return CM_ERROR_INVAL;
2074         cdescp = smb_ParseStringT2Parm(p, (unsigned char*) tp, (char **) &tp,
2075                                        SMB_STRF_FORCEASCII);
2076         if (cm_ClientStrCmp(cdescp,  _C("B16")) ||
2077             cm_ClientStrCmp(cdescp,  _C("B16BBDz")))
2078             return CM_ERROR_INVAL;
2079     }
2080
2081     infoLevel = *tp++;
2082     bufsize = *tp++;
2083
2084     if (infoLevel != 0 && infoLevel != 1) {
2085         return CM_ERROR_INVAL;
2086     }
2087
2088     totalParams = 6;
2089
2090     totalData = 
2091         (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
2092         : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
2093
2094     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
2095
2096     memset(outp->parmsp,0,totalParams);
2097     memset(outp->datap,0,totalData);
2098
2099     if (infoLevel == 0) {
2100         info0 = (smb_rap_server_info_0_t *) outp->datap;
2101         cstrp = (char *) (info0 + 1);
2102         StringCchCopyA(info0->sv0_name, lengthof(info0->sv0_name), "AFS");
2103     } else { /* infoLevel == SMB_INFO_STANDARD */
2104         info1 = (smb_rap_server_info_1_t *) outp->datap;
2105         cstrp = (char *) (info1 + 1);
2106         StringCchCopyA(info1->sv1_name, lengthof(info1->sv1_name), "AFS");
2107
2108         info1->sv1_type = 
2109             SMB_SV_TYPE_SERVER |
2110             SMB_SV_TYPE_NT |
2111             SMB_SV_TYPE_SERVER_NT;
2112
2113         info1->sv1_version_major = 5;
2114         info1->sv1_version_minor = 1;
2115         info1->sv1_comment_or_master_browser = (DWORD) (cstrp - outp->datap);
2116
2117         StringCbCopyA(cstrp, smb_ServerCommentLen, smb_ServerComment);
2118
2119         cstrp += smb_ServerCommentLen / sizeof(char);
2120     }
2121
2122     totalData = (DWORD)(cstrp - outp->datap);
2123     outp->totalData = min(bufsize,totalData); /* actual data size */
2124     outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
2125     outp->parmsp[2] = totalData;
2126     outp->totalParms = totalParams;
2127
2128     smb_SendTran2Packet(vcp,outp,op);
2129     smb_FreeTran2Packet(outp);
2130
2131     return code;
2132 }
2133
2134 /* SMB_COM_TRANSACTION2 and SMB_COM_TRANSACTION2_SECONDARY */
2135 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2136 {
2137     smb_tran2Packet_t *asp;
2138     int totalParms;
2139     int totalData;
2140     int parmDisp;
2141     int dataDisp;
2142     int parmOffset;
2143     int dataOffset;
2144     int parmCount;
2145     int dataCount;
2146     int firstPacket;
2147     long code = 0;
2148     DWORD oldTime, newTime;
2149
2150     /* We sometimes see 0 word count.  What to do? */
2151     if (*inp->wctp == 0) {
2152         osi_Log0(smb_logp, "Transaction2 word count = 0"); 
2153         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
2154
2155         smb_SetSMBDataLength(outp, 0);
2156         smb_SendPacket(vcp, outp);
2157         return 0;
2158     }
2159
2160     totalParms = smb_GetSMBParm(inp, 0);
2161     totalData = smb_GetSMBParm(inp, 1);
2162         
2163     firstPacket = (inp->inCom == 0x32);
2164         
2165     /* find the packet we're reassembling */
2166     lock_ObtainWrite(&smb_globalLock);
2167     asp = smb_FindTran2Packet(vcp, inp);
2168     if (!asp) {
2169         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
2170     }
2171     lock_ReleaseWrite(&smb_globalLock);
2172         
2173     /* now merge in this latest packet; start by looking up offsets */
2174     if (firstPacket) {
2175         parmDisp = dataDisp = 0;
2176         parmOffset = smb_GetSMBParm(inp, 10);
2177         dataOffset = smb_GetSMBParm(inp, 12);
2178         parmCount = smb_GetSMBParm(inp, 9);
2179         dataCount = smb_GetSMBParm(inp, 11);
2180         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2181         asp->maxReturnData = smb_GetSMBParm(inp, 3);
2182
2183         osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2184                  totalData, dataCount, asp->maxReturnData);
2185     }
2186     else {
2187         parmDisp = smb_GetSMBParm(inp, 4);
2188         parmOffset = smb_GetSMBParm(inp, 3);
2189         dataDisp = smb_GetSMBParm(inp, 7);
2190         dataOffset = smb_GetSMBParm(inp, 6);
2191         parmCount = smb_GetSMBParm(inp, 2);
2192         dataCount = smb_GetSMBParm(inp, 5);
2193
2194         osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2195                  parmCount, dataCount);
2196     }   
2197
2198     /* now copy the parms and data */
2199     if ( asp->totalParms > 0 && parmCount != 0 )
2200     {
2201         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2202     }
2203     if ( asp->totalData > 0 && dataCount != 0 ) {
2204         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2205     }
2206
2207     /* account for new bytes */
2208     asp->curData += dataCount;
2209     asp->curParms += parmCount;
2210
2211     /* finally, if we're done, remove the packet from the queue and dispatch it */
2212     if (asp->totalParms > 0 &&
2213         asp->curParms > 0 &&
2214         asp->totalData <= asp->curData &&
2215         asp->totalParms <= asp->curParms) {
2216         /* we've received it all */
2217         lock_ObtainWrite(&smb_globalLock);
2218         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2219         lock_ReleaseWrite(&smb_globalLock);
2220
2221         oldTime = GetTickCount();
2222
2223         /* now dispatch it */
2224         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2225             osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2226             code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2227         }
2228         else {
2229             osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2230             code = CM_ERROR_BADOP;
2231         }
2232
2233         /* if an error is returned, we're supposed to send an error packet,
2234          * otherwise the dispatched function already did the data sending.
2235          * We give dispatched proc the responsibility since it knows how much
2236          * space to allocate.
2237          */
2238         if (code != 0) {
2239             smb_SendTran2Error(vcp, asp, outp, code);
2240         }
2241
2242         newTime = GetTickCount();
2243         if (newTime - oldTime > 45000) {
2244             smb_user_t *uidp;
2245             smb_fid_t *fidp;
2246             clientchar_t *treepath = NULL;  /* do not free */
2247             clientchar_t *pathname = NULL;
2248             cm_fid_t afid = {0,0,0,0,0};
2249
2250             uidp = smb_FindUID(vcp, asp->uid, 0);
2251             smb_LookupTIDPath(vcp, asp->tid, &treepath);
2252             fidp = smb_FindFID(vcp, inp->fid, 0);
2253
2254             if (fidp) {
2255                 lock_ObtainMutex(&fidp->mx);
2256                 if (fidp->NTopen_pathp)
2257                     pathname = fidp->NTopen_pathp;
2258                 if (fidp->scp)
2259                     afid = fidp->scp->fid;
2260             } else {
2261                 if (inp->stringsp->wdata)
2262                     pathname = inp->stringsp->wdata;
2263             }
2264
2265             afsi_log("Request %s duration %d ms user %S tid \"%S\" path? \"%S\" afid (%d.%d.%d.%d)", 
2266                       myCrt_2Dispatch(asp->opcode), newTime - oldTime,
2267                       uidp ? uidp->unp->name : NULL,
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);