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