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