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