windows-printf-format-string-protection-20080108
[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 = strlen(name);
77
78     for ( i=0; smb_ExecutableExtensions[i]; i++) {
79         j = len - 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_Log0(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_Log0(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);
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);
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
1693     tp = p->parmsp + 1; /* skip over function number (always 1) */
1694     (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1695     (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1696     shareName = smb_ParseString( (char *) tp, (char **) &tp);
1697     infoLevel = *tp++;
1698     bufsize = *tp++;
1699     
1700     totalParam = 6;
1701
1702     if (infoLevel == 0)
1703         totalData = sizeof(smb_rap_share_info_0_t);
1704     else if(infoLevel == SMB_INFO_STANDARD)
1705         totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1706     else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1707         totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1708     else
1709         return CM_ERROR_INVAL;
1710
1711     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1712
1713     if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
1714         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1715                           KEY_QUERY_VALUE, &hkParam);
1716         if (rv == ERROR_SUCCESS) {
1717             len = sizeof(allSubmount);
1718             rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1719                                   (BYTE *) &allSubmount, &len);
1720             if (rv != ERROR_SUCCESS || allSubmount != 0) {
1721                 allSubmount = 1;
1722             }
1723             RegCloseKey (hkParam);
1724         }
1725
1726         if (allSubmount)
1727             shareFound = TRUE;
1728
1729     } else {
1730         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1731                           KEY_QUERY_VALUE, &hkSubmount);
1732         if (rv == ERROR_SUCCESS) {
1733             rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1734             if (rv == ERROR_SUCCESS) {
1735                 shareFound = TRUE;
1736             }
1737             RegCloseKey(hkSubmount);
1738         }
1739     }
1740
1741     if (!shareFound) {
1742         smb_FreeTran2Packet(outp);
1743         return CM_ERROR_BADSHARENAME;
1744     }
1745
1746     memset(outp->datap, 0, totalData);
1747
1748     outp->parmsp[0] = 0;
1749     outp->parmsp[1] = 0;
1750     outp->parmsp[2] = totalData;
1751
1752     if (infoLevel == 0) {
1753         smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1754         strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1755         info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1756     } else if(infoLevel == SMB_INFO_STANDARD) {
1757         smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1758         strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1759         info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1760         info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1761         /* type and pad are already zero */
1762     } else { /* infoLevel==2 */
1763         smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1764         strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1765         info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1766         info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1767         info->shi2_permissions = ACCESS_ALL;
1768         info->shi2_max_uses = (unsigned short) -1;
1769         info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1770     }
1771
1772     outp->totalData = totalData;
1773     outp->totalParms = totalParam;
1774
1775     smb_SendTran2Packet(vcp, outp, op);
1776     smb_FreeTran2Packet(outp);
1777
1778     return code;
1779 }
1780
1781 typedef struct smb_rap_wksta_info_10 {
1782     DWORD       wki10_computername;     /*char *wki10_computername;*/
1783     DWORD       wki10_username; /* char *wki10_username; */
1784     DWORD       wki10_langroup; /* char *wki10_langroup;*/
1785     unsigned char       wki10_ver_major;
1786     unsigned char       wki10_ver_minor;
1787     DWORD       wki10_logon_domain;     /*char *wki10_logon_domain;*/
1788     DWORD       wki10_oth_domains; /* char *wki10_oth_domains;*/
1789 } smb_rap_wksta_info_10_t;
1790
1791
1792 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1793 {
1794     smb_tran2Packet_t *outp;
1795     long code = 0;
1796     int infoLevel;
1797     int bufsize;
1798     unsigned short * tp;
1799     int totalData;
1800     int totalParams;
1801     smb_rap_wksta_info_10_t * info;
1802     char * cstrp;
1803     smb_user_t *uidp;
1804
1805     tp = p->parmsp + 1; /* Skip over function number */
1806     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1807     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1808     infoLevel = *tp++;
1809     bufsize = *tp++;
1810
1811     if (infoLevel != 10) {
1812         return CM_ERROR_INVAL;
1813     }
1814
1815     totalParams = 6;
1816         
1817     /* infolevel 10 */
1818     totalData = sizeof(*info) +         /* info */
1819         MAX_COMPUTERNAME_LENGTH +       /* wki10_computername */
1820         SMB_MAX_USERNAME_LENGTH +       /* wki10_username */
1821         MAX_COMPUTERNAME_LENGTH +       /* wki10_langroup */
1822         MAX_COMPUTERNAME_LENGTH +       /* wki10_logon_domain */
1823         1;                              /* wki10_oth_domains (null)*/
1824
1825     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1826
1827     memset(outp->parmsp,0,totalParams);
1828     memset(outp->datap,0,totalData);
1829
1830     info = (smb_rap_wksta_info_10_t *) outp->datap;
1831     cstrp = (char *) (info + 1);
1832
1833     info->wki10_computername = (DWORD) (cstrp - outp->datap);
1834     strcpy(cstrp, smb_localNamep);
1835     cstrp += strlen(cstrp) + 1;
1836
1837     info->wki10_username = (DWORD) (cstrp - outp->datap);
1838     uidp = smb_FindUID(vcp, p->uid, 0);
1839     if (uidp) {
1840         lock_ObtainMutex(&uidp->mx);
1841         if(uidp->unp && uidp->unp->name)
1842             strcpy(cstrp, uidp->unp->name);
1843         lock_ReleaseMutex(&uidp->mx);
1844         smb_ReleaseUID(uidp);
1845     }
1846     cstrp += strlen(cstrp) + 1;
1847
1848     info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1849     strcpy(cstrp, "WORKGROUP");
1850     cstrp += strlen(cstrp) + 1;
1851
1852     /* TODO: Not sure what values these should take, but these work */
1853     info->wki10_ver_major = 5;
1854     info->wki10_ver_minor = 1;
1855
1856     info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1857     strcpy(cstrp, smb_ServerDomainName);
1858     cstrp += strlen(cstrp) + 1;
1859
1860     info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1861     cstrp ++; /* no other domains */
1862
1863     outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1864     outp->parmsp[2] = outp->totalData;
1865     outp->totalParms = totalParams;
1866
1867     smb_SendTran2Packet(vcp,outp,op);
1868     smb_FreeTran2Packet(outp);
1869
1870     return code;
1871 }
1872
1873 typedef struct smb_rap_server_info_0 {
1874     char    sv0_name[16];
1875 } smb_rap_server_info_0_t;
1876
1877 typedef struct smb_rap_server_info_1 {
1878     char            sv1_name[16];
1879     char            sv1_version_major;
1880     char            sv1_version_minor;
1881     unsigned long   sv1_type;
1882     DWORD           *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1883 } smb_rap_server_info_1_t;
1884
1885 char smb_ServerComment[] = "OpenAFS Client";
1886 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1887
1888 #define SMB_SV_TYPE_SERVER              0x00000002L
1889 #define SMB_SV_TYPE_NT              0x00001000L
1890 #define SMB_SV_TYPE_SERVER_NT       0x00008000L
1891
1892 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1893 {
1894     smb_tran2Packet_t *outp;
1895     long code = 0;
1896     int infoLevel;
1897     int bufsize;
1898     unsigned short * tp;
1899     int totalData;
1900     int totalParams;
1901     smb_rap_server_info_0_t * info0;
1902     smb_rap_server_info_1_t * info1;
1903     char * cstrp;
1904
1905     tp = p->parmsp + 1; /* Skip over function number */
1906     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1907     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1908     infoLevel = *tp++;
1909     bufsize = *tp++;
1910
1911     if (infoLevel != 0 && infoLevel != 1) {
1912         return CM_ERROR_INVAL;
1913     }
1914
1915     totalParams = 6;
1916
1917     totalData = 
1918         (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1919         : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1920
1921     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1922
1923     memset(outp->parmsp,0,totalParams);
1924     memset(outp->datap,0,totalData);
1925
1926     if (infoLevel == 0) {
1927         info0 = (smb_rap_server_info_0_t *) outp->datap;
1928         cstrp = (char *) (info0 + 1);
1929         strcpy(info0->sv0_name, "AFS");
1930     } else { /* infoLevel == SMB_INFO_STANDARD */
1931         info1 = (smb_rap_server_info_1_t *) outp->datap;
1932         cstrp = (char *) (info1 + 1);
1933         strcpy(info1->sv1_name, "AFS");
1934
1935         info1->sv1_type = 
1936             SMB_SV_TYPE_SERVER |
1937             SMB_SV_TYPE_NT |
1938             SMB_SV_TYPE_SERVER_NT;
1939
1940         info1->sv1_version_major = 5;
1941         info1->sv1_version_minor = 1;
1942         info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1943
1944         strcpy(cstrp, smb_ServerComment);
1945
1946         cstrp += smb_ServerCommentLen;
1947     }
1948
1949     totalData = (DWORD)(cstrp - outp->datap);
1950     outp->totalData = min(bufsize,totalData); /* actual data size */
1951     outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1952     outp->parmsp[2] = totalData;
1953     outp->totalParms = totalParams;
1954
1955     smb_SendTran2Packet(vcp,outp,op);
1956     smb_FreeTran2Packet(outp);
1957
1958     return code;
1959 }
1960
1961 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1962 {
1963     smb_tran2Packet_t *asp;
1964     int totalParms;
1965     int totalData;
1966     int parmDisp;
1967     int dataDisp;
1968     int parmOffset;
1969     int dataOffset;
1970     int parmCount;
1971     int dataCount;
1972     int firstPacket;
1973     long code = 0;
1974
1975     /* We sometimes see 0 word count.  What to do? */
1976     if (*inp->wctp == 0) {
1977         osi_Log0(smb_logp, "Transaction2 word count = 0"); 
1978         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1979
1980         smb_SetSMBDataLength(outp, 0);
1981         smb_SendPacket(vcp, outp);
1982         return 0;
1983     }
1984
1985     totalParms = smb_GetSMBParm(inp, 0);
1986     totalData = smb_GetSMBParm(inp, 1);
1987         
1988     firstPacket = (inp->inCom == 0x32);
1989         
1990     /* find the packet we're reassembling */
1991     lock_ObtainWrite(&smb_globalLock);
1992     asp = smb_FindTran2Packet(vcp, inp);
1993     if (!asp) {
1994         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1995     }
1996     lock_ReleaseWrite(&smb_globalLock);
1997         
1998     /* now merge in this latest packet; start by looking up offsets */
1999     if (firstPacket) {
2000         parmDisp = dataDisp = 0;
2001         parmOffset = smb_GetSMBParm(inp, 10);
2002         dataOffset = smb_GetSMBParm(inp, 12);
2003         parmCount = smb_GetSMBParm(inp, 9);
2004         dataCount = smb_GetSMBParm(inp, 11);
2005         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
2006         asp->maxReturnData = smb_GetSMBParm(inp, 3);
2007
2008         osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
2009                  totalData, dataCount, asp->maxReturnData);
2010     }
2011     else {
2012         parmDisp = smb_GetSMBParm(inp, 4);
2013         parmOffset = smb_GetSMBParm(inp, 3);
2014         dataDisp = smb_GetSMBParm(inp, 7);
2015         dataOffset = smb_GetSMBParm(inp, 6);
2016         parmCount = smb_GetSMBParm(inp, 2);
2017         dataCount = smb_GetSMBParm(inp, 5);
2018
2019         osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
2020                  parmCount, dataCount);
2021     }   
2022
2023     /* now copy the parms and data */
2024     if ( asp->totalParms > 0 && parmCount != 0 )
2025     {
2026         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
2027     }
2028     if ( asp->totalData > 0 && dataCount != 0 ) {
2029         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
2030     }
2031
2032     /* account for new bytes */
2033     asp->curData += dataCount;
2034     asp->curParms += parmCount;
2035
2036     /* finally, if we're done, remove the packet from the queue and dispatch it */
2037     if (asp->totalParms > 0 &&
2038         asp->curParms > 0 &&
2039         asp->totalData <= asp->curData &&
2040         asp->totalParms <= asp->curParms) {
2041         /* we've received it all */
2042         lock_ObtainWrite(&smb_globalLock);
2043         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2044         lock_ReleaseWrite(&smb_globalLock);
2045
2046         /* now dispatch it */
2047         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2048             osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2049             code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2050         }
2051         else {
2052             osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2053             code = CM_ERROR_BADOP;
2054         }
2055
2056         /* if an error is returned, we're supposed to send an error packet,
2057          * otherwise the dispatched function already did the data sending.
2058          * We give dispatched proc the responsibility since it knows how much
2059          * space to allocate.
2060          */
2061         if (code != 0) {
2062             smb_SendTran2Error(vcp, asp, outp, code);
2063         }
2064
2065         /* free the input tran 2 packet */
2066         smb_FreeTran2Packet(asp);
2067     }
2068     else if (firstPacket) {
2069         /* the first packet in a multi-packet request, we need to send an
2070          * ack to get more data.
2071          */
2072         smb_SetSMBDataLength(outp, 0);
2073         smb_SendPacket(vcp, outp);
2074     }
2075
2076     return 0;
2077 }
2078
2079 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2080 {
2081     char *pathp;
2082     smb_tran2Packet_t *outp;
2083     long code = 0;
2084     cm_space_t *spacep;
2085     int excl;
2086     cm_user_t *userp;
2087     cm_scache_t *dscp;          /* dir we're dealing with */
2088     cm_scache_t *scp;           /* file we're creating */
2089     cm_attr_t setAttr;
2090     int initialModeBits;
2091     smb_fid_t *fidp;
2092     int attributes;
2093     char *lastNamep;
2094     afs_uint32 dosTime;
2095     int openFun;
2096     int trunc;
2097     int openMode;
2098     int extraInfo;
2099     int openAction;
2100     int parmSlot;                       /* which parm we're dealing with */
2101     long returnEALength;
2102     char *tidPathp;
2103     cm_req_t req;
2104     int created = 0;
2105
2106     cm_InitReq(&req);
2107
2108     scp = NULL;
2109         
2110     extraInfo = (p->parmsp[0] & 1);     /* return extra info */
2111     returnEALength = (p->parmsp[0] & 8);        /* return extended attr length */
2112
2113     openFun = p->parmsp[6];             /* open function */
2114     excl = ((openFun & 3) == 0);
2115     trunc = ((openFun & 3) == 2);       /* truncate it */
2116     openMode = (p->parmsp[1] & 0x7);
2117     openAction = 0;                     /* tracks what we did */
2118
2119     attributes = p->parmsp[3];
2120     dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2121         
2122     /* compute initial mode bits based on read-only flag in attributes */
2123     initialModeBits = 0666;
2124     if (attributes & SMB_ATTR_READONLY) 
2125         initialModeBits &= ~0222;
2126         
2127     pathp = (char *) (&p->parmsp[14]);
2128     if (smb_StoreAnsiFilenames)
2129         OemToChar(pathp,pathp);
2130     
2131     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2132
2133     spacep = cm_GetSpace();
2134     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2135
2136     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2137         /* special case magic file name for receiving IOCTL requests
2138          * (since IOCTL calls themselves aren't getting through).
2139          */
2140         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2141         smb_SetupIoctlFid(fidp, spacep);
2142
2143         /* copy out remainder of the parms */
2144         parmSlot = 0;
2145         outp->parmsp[parmSlot++] = fidp->fid;
2146         if (extraInfo) {
2147             outp->parmsp[parmSlot++] = 0;       /* attrs */
2148             outp->parmsp[parmSlot++] = 0;       /* mod time */
2149             outp->parmsp[parmSlot++] = 0; 
2150             outp->parmsp[parmSlot++] = 0;       /* len */
2151             outp->parmsp[parmSlot++] = 0x7fff;
2152             outp->parmsp[parmSlot++] = openMode;
2153             outp->parmsp[parmSlot++] = 0;       /* file type 0 ==> normal file or dir */
2154             outp->parmsp[parmSlot++] = 0;       /* IPC junk */
2155         }   
2156         /* and the final "always present" stuff */
2157         outp->parmsp[parmSlot++] = 1;           /* openAction found existing file */
2158         /* next write out the "unique" ID */
2159         outp->parmsp[parmSlot++] = 0x1234;
2160         outp->parmsp[parmSlot++] = 0x5678;
2161         outp->parmsp[parmSlot++] = 0;
2162         if (returnEALength) {
2163             outp->parmsp[parmSlot++] = 0;
2164             outp->parmsp[parmSlot++] = 0;
2165         }       
2166                 
2167         outp->totalData = 0;
2168         outp->totalParms = parmSlot * 2;
2169                 
2170         smb_SendTran2Packet(vcp, outp, op);
2171                 
2172         smb_FreeTran2Packet(outp);
2173
2174         /* and clean up fid reference */
2175         smb_ReleaseFID(fidp);
2176         return 0;
2177     }
2178
2179 #ifdef DEBUG_VERBOSE
2180     {
2181         char *hexp, *asciip;
2182         asciip = (lastNamep ? lastNamep : pathp);
2183         hexp = osi_HexifyString( asciip );
2184         DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2185         free(hexp);
2186     }       
2187 #endif
2188
2189     userp = smb_GetTran2User(vcp, p);
2190     /* In the off chance that userp is NULL, we log and abandon */
2191     if (!userp) {
2192         osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2193         smb_FreeTran2Packet(outp);
2194         return CM_ERROR_BADSMB;
2195     }
2196
2197     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2198     if (code == CM_ERROR_TIDIPC) {
2199         /* Attempt to use a TID allocated for IPC.  The client
2200          * is probably looking for DCE RPC end points which we
2201          * don't support OR it could be looking to make a DFS
2202          * referral request. 
2203          */
2204         osi_Log0(smb_logp, "Tran2Open received IPC TID");
2205 #ifndef DFS_SUPPORT
2206         cm_ReleaseUser(userp);
2207         smb_FreeTran2Packet(outp);
2208         return CM_ERROR_NOSUCHPATH;
2209 #endif
2210     }
2211
2212     dscp = NULL;
2213     code = cm_NameI(cm_data.rootSCachep, pathp,
2214                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2215                      userp, tidPathp, &req, &scp);
2216     if (code != 0) {
2217         code = cm_NameI(cm_data.rootSCachep, spacep->data,
2218                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2219                          userp, tidPathp, &req, &dscp);
2220         cm_FreeSpace(spacep);
2221
2222         if (code) {
2223             cm_ReleaseUser(userp);
2224             smb_FreeTran2Packet(outp);
2225             return code;
2226         }
2227         
2228 #ifdef DFS_SUPPORT
2229         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2230             int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
2231             cm_ReleaseSCache(dscp);
2232             cm_ReleaseUser(userp);
2233             smb_FreeTran2Packet(outp);
2234             if ( WANTS_DFS_PATHNAMES(p) || pnc )
2235                 return CM_ERROR_PATH_NOT_COVERED;
2236             else
2237                 return CM_ERROR_BADSHARENAME;
2238         }
2239 #endif /* DFS_SUPPORT */
2240
2241         /* otherwise, scp points to the parent directory.  Do a lookup,
2242          * and truncate the file if we find it, otherwise we create the
2243          * file.
2244          */
2245         if (!lastNamep) 
2246             lastNamep = pathp;
2247         else 
2248             lastNamep++;
2249         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2250                          &req, &scp);
2251         if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
2252             cm_ReleaseSCache(dscp);
2253             cm_ReleaseUser(userp);
2254             smb_FreeTran2Packet(outp);
2255             return code;
2256         }
2257     } else {
2258 #ifdef DFS_SUPPORT
2259         if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2260             int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, lastNamep);
2261             cm_ReleaseSCache(scp);
2262             cm_ReleaseUser(userp);
2263             smb_FreeTran2Packet(outp);
2264             if ( WANTS_DFS_PATHNAMES(p) || pnc )
2265                 return CM_ERROR_PATH_NOT_COVERED;
2266             else
2267                 return CM_ERROR_BADSHARENAME;
2268         }
2269 #endif /* DFS_SUPPORT */
2270
2271         /* macintosh is expensive to program for it */
2272         cm_FreeSpace(spacep);
2273     }
2274         
2275     /* if we get here, if code is 0, the file exists and is represented by
2276      * scp.  Otherwise, we have to create it.
2277      */
2278     if (code == 0) {
2279         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2280         if (code) {
2281             if (dscp) 
2282                 cm_ReleaseSCache(dscp);
2283             cm_ReleaseSCache(scp);
2284             cm_ReleaseUser(userp);
2285             smb_FreeTran2Packet(outp);
2286             return code;
2287         }
2288
2289         if (excl) {
2290             /* oops, file shouldn't be there */
2291             if (dscp) 
2292                 cm_ReleaseSCache(dscp);
2293             cm_ReleaseSCache(scp);
2294             cm_ReleaseUser(userp);
2295             smb_FreeTran2Packet(outp);
2296             return CM_ERROR_EXISTS;
2297         }
2298
2299         if (trunc) {
2300             setAttr.mask = CM_ATTRMASK_LENGTH;
2301             setAttr.length.LowPart = 0;
2302             setAttr.length.HighPart = 0;
2303             code = cm_SetAttr(scp, &setAttr, userp, &req);
2304             openAction = 3;     /* truncated existing file */
2305         }   
2306         else 
2307             openAction = 1;     /* found existing file */
2308     }
2309     else if (!(openFun & 0x10)) {
2310         /* don't create if not found */
2311         if (dscp) 
2312             cm_ReleaseSCache(dscp);
2313         osi_assertx(scp == NULL, "null cm_scache_t");
2314         cm_ReleaseUser(userp);
2315         smb_FreeTran2Packet(outp);
2316         return CM_ERROR_NOSUCHFILE;
2317     }
2318     else {
2319         osi_assertx(dscp != NULL && scp == NULL, "null dsc || non-null sc");
2320         openAction = 2; /* created file */
2321         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2322         smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2323         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2324                           &req);
2325         if (code == 0) {
2326             created = 1;
2327             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2328                 smb_NotifyChange(FILE_ACTION_ADDED,
2329                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,  
2330                                   dscp, lastNamep, NULL, TRUE);
2331         } else if (!excl && code == CM_ERROR_EXISTS) {
2332             /* not an exclusive create, and someone else tried
2333              * creating it already, then we open it anyway.  We
2334              * don't bother retrying after this, since if this next
2335              * fails, that means that the file was deleted after we
2336              * started this call.
2337              */
2338             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2339                               userp, &req, &scp);
2340             if (code == 0) {
2341                 if (trunc) {
2342                     setAttr.mask = CM_ATTRMASK_LENGTH;
2343                     setAttr.length.LowPart = 0;
2344                     setAttr.length.HighPart = 0;
2345                     code = cm_SetAttr(scp, &setAttr, userp,
2346                                        &req);
2347                 }   
2348             }   /* lookup succeeded */
2349         }
2350     }
2351         
2352     /* we don't need this any longer */
2353     if (dscp) 
2354         cm_ReleaseSCache(dscp);
2355
2356     if (code) {
2357         /* something went wrong creating or truncating the file */
2358         if (scp) 
2359             cm_ReleaseSCache(scp);
2360         cm_ReleaseUser(userp);
2361         smb_FreeTran2Packet(outp);
2362         return code;
2363     }
2364         
2365     /* make sure we're about to open a file */
2366     if (scp->fileType != CM_SCACHETYPE_FILE) {
2367         code = 0;
2368         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2369             cm_scache_t * targetScp = 0;
2370             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2371             if (code == 0) {
2372                 /* we have a more accurate file to use (the
2373                  * target of the symbolic link).  Otherwise,
2374                  * we'll just use the symlink anyway.
2375                  */
2376                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2377                           scp, targetScp);
2378                 cm_ReleaseSCache(scp);
2379                 scp = targetScp;
2380             }
2381         }
2382         if (scp->fileType != CM_SCACHETYPE_FILE) {
2383             cm_ReleaseSCache(scp);
2384             cm_ReleaseUser(userp);
2385             smb_FreeTran2Packet(outp);
2386             return CM_ERROR_ISDIR;
2387         }
2388     }
2389
2390     /* now all we have to do is open the file itself */
2391     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2392     osi_assertx(fidp, "null smb_fid_t");
2393         
2394     cm_HoldUser(userp);
2395     lock_ObtainMutex(&fidp->mx);
2396     /* save a pointer to the vnode */
2397     osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2398     fidp->scp = scp;
2399     lock_ObtainMutex(&scp->mx);
2400     scp->flags |= CM_SCACHEFLAG_SMB_FID;
2401     lock_ReleaseMutex(&scp->mx);
2402     
2403     /* and the user */
2404     fidp->userp = userp;
2405         
2406     /* compute open mode */
2407     if (openMode != 1) 
2408         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2409     if (openMode == 1 || openMode == 2)
2410         fidp->flags |= SMB_FID_OPENWRITE;
2411
2412     /* remember that the file was newly created */
2413     if (created)
2414         fidp->flags |= SMB_FID_CREATED;
2415
2416     lock_ReleaseMutex(&fidp->mx);
2417
2418     smb_ReleaseFID(fidp);
2419         
2420     cm_Open(scp, 0, userp);
2421
2422     /* copy out remainder of the parms */
2423     parmSlot = 0;
2424     outp->parmsp[parmSlot++] = fidp->fid;
2425     lock_ObtainMutex(&scp->mx);
2426     if (extraInfo) {
2427         outp->parmsp[parmSlot++] = smb_Attributes(scp);
2428         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2429         outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2430         outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2431         outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2432         outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2433         outp->parmsp[parmSlot++] = openMode;
2434         outp->parmsp[parmSlot++] = 0;   /* file type 0 ==> normal file or dir */
2435         outp->parmsp[parmSlot++] = 0;   /* IPC junk */
2436     }   
2437     /* and the final "always present" stuff */
2438     outp->parmsp[parmSlot++] = openAction;
2439     /* next write out the "unique" ID */
2440     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff); 
2441     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff); 
2442     outp->parmsp[parmSlot++] = 0; 
2443     if (returnEALength) {
2444         outp->parmsp[parmSlot++] = 0; 
2445         outp->parmsp[parmSlot++] = 0; 
2446     }   
2447     lock_ReleaseMutex(&scp->mx);
2448     outp->totalData = 0;                /* total # of data bytes */
2449     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
2450
2451     smb_SendTran2Packet(vcp, outp, op);
2452
2453     smb_FreeTran2Packet(outp);
2454
2455     cm_ReleaseUser(userp);
2456     /* leave scp held since we put it in fidp->scp */
2457     return 0;
2458 }   
2459
2460 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2461 {
2462     unsigned short fid;
2463     unsigned short infolevel;
2464
2465     infolevel = p->parmsp[0];
2466     fid = p->parmsp[1];
2467     osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2468     
2469     return CM_ERROR_BAD_LEVEL;
2470 }
2471
2472 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2473 {
2474     smb_tran2Packet_t *outp;
2475     smb_tran2QFSInfo_t qi;
2476     int responseSize;
2477     static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2478         
2479     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2480
2481     switch (p->parmsp[0]) {
2482     case SMB_INFO_ALLOCATION: 
2483         responseSize = sizeof(qi.u.allocInfo); 
2484         break;
2485     case SMB_INFO_VOLUME: 
2486         responseSize = sizeof(qi.u.volumeInfo); 
2487         break;
2488     case SMB_QUERY_FS_VOLUME_INFO: 
2489         responseSize = sizeof(qi.u.FSvolumeInfo); 
2490         break;
2491     case SMB_QUERY_FS_SIZE_INFO: 
2492         responseSize = sizeof(qi.u.FSsizeInfo); 
2493         break;
2494     case SMB_QUERY_FS_DEVICE_INFO: 
2495         responseSize = sizeof(qi.u.FSdeviceInfo); 
2496         break;
2497     case SMB_QUERY_FS_ATTRIBUTE_INFO: 
2498         responseSize = sizeof(qi.u.FSattributeInfo); 
2499         break;
2500     case SMB_INFO_UNIX:         /* CIFS Unix Info */
2501     case SMB_INFO_MACOS:        /* Mac FS Info */
2502     default: 
2503         return CM_ERROR_BADOP;
2504     }
2505
2506     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2507     switch (p->parmsp[0]) {
2508     case SMB_INFO_ALLOCATION: 
2509         /* alloc info */
2510         qi.u.allocInfo.FSID = 0;
2511         qi.u.allocInfo.sectorsPerAllocUnit = 1;
2512         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2513         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2514         qi.u.allocInfo.bytesPerSector = 1024;
2515         break;
2516
2517     case SMB_INFO_VOLUME: 
2518         /* volume info */
2519         qi.u.volumeInfo.vsn = 1234;
2520         qi.u.volumeInfo.vnCount = 4;
2521         /* we're supposed to pad it out with zeroes to the end */
2522         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2523         memcpy(qi.u.volumeInfo.label, "AFS", 4);
2524         break;
2525
2526     case SMB_QUERY_FS_VOLUME_INFO: 
2527         /* FS volume info */
2528         memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2529         qi.u.FSvolumeInfo.vsn = 1234;
2530         qi.u.FSvolumeInfo.vnCount = 8;
2531         memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2532         break;
2533
2534     case SMB_QUERY_FS_SIZE_INFO: 
2535         /* FS size info */
2536         qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2537         qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2538         qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2539         qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2540         qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2541         qi.u.FSsizeInfo.bytesPerSector = 1024;
2542         break;
2543
2544     case SMB_QUERY_FS_DEVICE_INFO: 
2545         /* FS device info */
2546         qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2547         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2548         break;
2549
2550     case SMB_QUERY_FS_ATTRIBUTE_INFO: 
2551         /* FS attribute info */
2552         /* attributes, defined in WINNT.H:
2553          *      FILE_CASE_SENSITIVE_SEARCH      0x1
2554          *      FILE_CASE_PRESERVED_NAMES       0x2
2555          *      FILE_VOLUME_QUOTAS              0x10
2556          *      <no name defined>               0x4000
2557          *         If bit 0x4000 is not set, Windows 95 thinks
2558          *         we can't handle long (non-8.3) names,
2559          *         despite our protestations to the contrary.
2560          */
2561         qi.u.FSattributeInfo.attributes = 0x4003;
2562         qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2563         qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2564         memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2565         break;
2566     }   
2567         
2568     /* copy out return data, and set corresponding sizes */
2569     outp->totalParms = 0;
2570     outp->totalData = responseSize;
2571     memcpy(outp->datap, &qi, responseSize);
2572
2573     /* send and free the packets */
2574     smb_SendTran2Packet(vcp, outp, op);
2575     smb_FreeTran2Packet(outp);
2576
2577     return 0;
2578 }
2579
2580 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2581 {
2582     osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2583     return CM_ERROR_BADOP;
2584 }
2585
2586 struct smb_ShortNameRock {
2587     char *maskp;
2588     unsigned int vnode;
2589     char *shortName;
2590     size_t shortNameLen;
2591 };      
2592
2593 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2594                          osi_hyper_t *offp)
2595 {       
2596     struct smb_ShortNameRock *rockp;
2597     char *shortNameEnd;
2598
2599     rockp = vrockp;
2600     /* compare both names and vnodes, though probably just comparing vnodes
2601      * would be safe enough.
2602      */
2603     if (cm_stricmp(dep->name, rockp->maskp) != 0)
2604         return 0;
2605     if (ntohl(dep->fid.vnode) != rockp->vnode)
2606         return 0;
2607     /* This is the entry */
2608     cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2609     rockp->shortNameLen = shortNameEnd - rockp->shortName;
2610     return CM_ERROR_STOPNOW;
2611 }       
2612
2613 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2614         char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2615 {
2616     struct smb_ShortNameRock rock;
2617     char *lastNamep;
2618     cm_space_t *spacep;
2619     cm_scache_t *dscp;
2620     int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2621     long code = 0;
2622     osi_hyper_t thyper;
2623
2624     spacep = cm_GetSpace();
2625     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2626
2627     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2628                      reqp, &dscp);
2629     cm_FreeSpace(spacep);
2630     if (code) 
2631         return code;
2632
2633 #ifdef DFS_SUPPORT
2634     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2635         cm_ReleaseSCache(dscp);
2636         cm_ReleaseUser(userp);
2637         DebugBreak();
2638         return CM_ERROR_PATH_NOT_COVERED;
2639     }
2640 #endif /* DFS_SUPPORT */
2641
2642     if (!lastNamep) lastNamep = pathp;
2643     else lastNamep++;
2644     thyper.LowPart = 0;
2645     thyper.HighPart = 0;
2646     rock.shortName = shortName;
2647     rock.vnode = vnode;
2648     rock.maskp = lastNamep;
2649     code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2650
2651     cm_ReleaseSCache(dscp);
2652
2653     if (code == 0)
2654         return CM_ERROR_NOSUCHFILE;
2655     if (code == CM_ERROR_STOPNOW) {
2656         *shortNameLenp = rock.shortNameLen;
2657         return 0;
2658     }
2659     return code;
2660 }
2661
2662 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2663 {
2664     smb_tran2Packet_t *outp;
2665     afs_uint32 dosTime;
2666     FILETIME ft;
2667     unsigned short infoLevel;
2668     smb_tran2QPathInfo_t qpi;
2669     int responseSize;
2670     unsigned short attributes;
2671     unsigned long extAttributes;
2672     char shortName[13];
2673     unsigned int len;
2674     cm_user_t *userp;
2675     cm_space_t *spacep;
2676     cm_scache_t *scp, *dscp;
2677     int scp_mx_held = 0;
2678     int delonclose = 0;
2679     long code = 0;
2680     char *pathp;
2681     char *tidPathp;
2682     char *lastComp;
2683     cm_req_t req;
2684
2685     cm_InitReq(&req);
2686
2687     infoLevel = p->parmsp[0];
2688     if (infoLevel == SMB_INFO_IS_NAME_VALID) 
2689         responseSize = 0;
2690     else if (infoLevel == SMB_INFO_STANDARD) 
2691         responseSize = sizeof(qpi.u.QPstandardInfo);
2692     else if (infoLevel == SMB_INFO_QUERY_EA_SIZE) 
2693         responseSize = sizeof(qpi.u.QPeaSizeInfo);
2694     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2695         responseSize = sizeof(qpi.u.QPfileBasicInfo);
2696     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2697         responseSize = sizeof(qpi.u.QPfileStandardInfo);
2698     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2699         responseSize = sizeof(qpi.u.QPfileEaInfo);
2700     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
2701         responseSize = sizeof(qpi.u.QPfileNameInfo);
2702     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) 
2703         responseSize = sizeof(qpi.u.QPfileAllInfo);
2704     else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) 
2705         responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2706     else {
2707         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2708                   p->opcode, infoLevel);
2709         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2710         return 0;
2711     }
2712
2713     pathp = (char *)(&p->parmsp[3]);
2714     if (smb_StoreAnsiFilenames)
2715         OemToChar(pathp,pathp);
2716     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2717               osi_LogSaveString(smb_logp, pathp));
2718
2719     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2720
2721     if (infoLevel > 0x100)
2722         outp->totalParms = 2;
2723     else
2724         outp->totalParms = 0;
2725     outp->totalData = responseSize;
2726         
2727     /* now, if we're at infoLevel 6, we're only being asked to check
2728      * the syntax, so we just OK things now.  In particular, we're *not*
2729      * being asked to verify anything about the state of any parent dirs.
2730      */
2731     if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2732         smb_SendTran2Packet(vcp, outp, opx);
2733         smb_FreeTran2Packet(outp);
2734         return 0;
2735     }   
2736         
2737     userp = smb_GetTran2User(vcp, p);
2738     if (!userp) {
2739         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2740         smb_FreeTran2Packet(outp);
2741         return CM_ERROR_BADSMB;
2742     }
2743
2744     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2745     if(code) {
2746         cm_ReleaseUser(userp);
2747         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2748         smb_FreeTran2Packet(outp);
2749         return 0;
2750     }
2751
2752     /*
2753      * XXX Strange hack XXX
2754      *
2755      * As of Patch 7 (13 January 98), we are having the following problem:
2756      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2757      * requests to look up "desktop.ini" in all the subdirectories.
2758      * This can cause zillions of timeouts looking up non-existent cells
2759      * and volumes, especially in the top-level directory.
2760      *
2761      * We have not found any way to avoid this or work around it except
2762      * to explicitly ignore the requests for mount points that haven't
2763      * yet been evaluated and for directories that haven't yet been
2764      * fetched.
2765      */
2766     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2767         spacep = cm_GetSpace();
2768         smb_StripLastComponent(spacep->data, &lastComp, pathp);
2769 #ifndef SPECIAL_FOLDERS
2770         /* Make sure that lastComp is not NULL */
2771         if (lastComp) {
2772             if (stricmp(lastComp, "\\desktop.ini") == 0) {
2773                 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2774                                  CM_FLAG_CASEFOLD
2775                                  | CM_FLAG_DIRSEARCH
2776                                  | CM_FLAG_FOLLOW,
2777                                  userp, tidPathp, &req, &dscp);
2778                 if (code == 0) {
2779 #ifdef DFS_SUPPORT
2780                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2781                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
2782                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
2783                             code = CM_ERROR_PATH_NOT_COVERED;
2784                         else
2785                             code = CM_ERROR_BADSHARENAME;
2786                     } else
2787 #endif /* DFS_SUPPORT */
2788                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2789                         code = CM_ERROR_NOSUCHFILE;
2790                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2791                         cm_buf_t *bp = buf_Find(dscp, &hzero);
2792                         if (bp) {
2793                             buf_Release(bp);
2794                             bp = NULL;
2795                         }
2796                         else
2797                             code = CM_ERROR_NOSUCHFILE;
2798                     }
2799                     cm_ReleaseSCache(dscp);
2800                     if (code) {
2801                         cm_FreeSpace(spacep);
2802                         cm_ReleaseUser(userp);
2803                         smb_SendTran2Error(vcp, p, opx, code);
2804                         smb_FreeTran2Packet(outp);
2805                         return 0;
2806                     }
2807                 }
2808             }
2809         }
2810 #endif /* SPECIAL_FOLDERS */
2811
2812         cm_FreeSpace(spacep);
2813     }
2814
2815     /* now do namei and stat, and copy out the info */
2816     code = cm_NameI(cm_data.rootSCachep, pathp,
2817                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2818
2819     if (code) {
2820         cm_ReleaseUser(userp);
2821         smb_SendTran2Error(vcp, p, opx, code);
2822         smb_FreeTran2Packet(outp);
2823         return 0;
2824     }
2825
2826 #ifdef DFS_SUPPORT
2827     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2828         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
2829         cm_ReleaseSCache(scp);
2830         cm_ReleaseUser(userp);
2831         if ( WANTS_DFS_PATHNAMES(p) || pnc )
2832             code = CM_ERROR_PATH_NOT_COVERED;
2833         else
2834             code = CM_ERROR_BADSHARENAME;
2835         smb_SendTran2Error(vcp, p, opx, code);
2836         smb_FreeTran2Packet(outp);
2837         return 0;
2838     }
2839 #endif /* DFS_SUPPORT */
2840
2841     lock_ObtainMutex(&scp->mx);
2842     scp_mx_held = 1;
2843     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2844                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2845     if (code) goto done;
2846
2847     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2848         
2849     /* now we have the status in the cache entry, and everything is locked.
2850      * Marshall the output data.
2851      */
2852     /* for info level 108, figure out short name */
2853     if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2854         code = cm_GetShortName(pathp, userp, &req,
2855                                 tidPathp, scp->fid.vnode, shortName,
2856                                 (size_t *) &len);
2857         if (code) {
2858             goto done;
2859         }
2860
2861         qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2862         mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2863
2864         goto done;
2865     }
2866     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2867         len = strlen(lastComp);
2868         qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2869         mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2870
2871         goto done;
2872     }
2873     else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2874         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2875         qpi.u.QPstandardInfo.creationDateTime = dosTime;
2876         qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2877         qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2878         qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2879         qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2880         attributes = smb_Attributes(scp);
2881         qpi.u.QPstandardInfo.attributes = attributes;
2882         qpi.u.QPstandardInfo.eaSize = 0;
2883     }
2884     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2885         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2886         qpi.u.QPfileBasicInfo.creationTime = ft;
2887         qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2888         qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2889         qpi.u.QPfileBasicInfo.changeTime = ft;
2890         extAttributes = smb_ExtAttributes(scp);
2891         qpi.u.QPfileBasicInfo.attributes = extAttributes;
2892         qpi.u.QPfileBasicInfo.reserved = 0;
2893     }
2894     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2895         smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2896
2897         qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2898         qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2899         qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2900         qpi.u.QPfileStandardInfo.directory = 
2901             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2902               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2903               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2904         qpi.u.QPfileStandardInfo.reserved = 0;
2905
2906         if (fidp) {
2907             lock_ReleaseMutex(&scp->mx);
2908             scp_mx_held = 0;
2909             lock_ObtainMutex(&fidp->mx);
2910             delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2911             lock_ReleaseMutex(&fidp->mx);
2912             smb_ReleaseFID(fidp);
2913         }
2914         qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2915     }
2916     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2917         qpi.u.QPfileEaInfo.eaSize = 0;
2918     }
2919     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2920         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2921         qpi.u.QPfileAllInfo.creationTime = ft;
2922         qpi.u.QPfileAllInfo.lastAccessTime = ft;
2923         qpi.u.QPfileAllInfo.lastWriteTime = ft;
2924         qpi.u.QPfileAllInfo.changeTime = ft;
2925         extAttributes = smb_ExtAttributes(scp);
2926         qpi.u.QPfileAllInfo.attributes = extAttributes;
2927         qpi.u.QPfileAllInfo.allocationSize = scp->length;
2928         qpi.u.QPfileAllInfo.endOfFile = scp->length;
2929         qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2930         qpi.u.QPfileAllInfo.deletePending = 0;
2931         qpi.u.QPfileAllInfo.directory = 
2932             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2933               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2934               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2935         qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2936         qpi.u.QPfileAllInfo.indexNumber.LowPart  = scp->fid.volume;
2937         qpi.u.QPfileAllInfo.eaSize = 0;
2938         qpi.u.QPfileAllInfo.accessFlags = 0;
2939         qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2940         qpi.u.QPfileAllInfo.indexNumber2.LowPart  = scp->fid.unique;
2941         qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2942         qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2943         qpi.u.QPfileAllInfo.mode = 0;
2944         qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2945         len = strlen(lastComp);
2946         qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2947         mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2948     }
2949
2950     /* send and free the packets */
2951   done:
2952     if (scp_mx_held)
2953         lock_ReleaseMutex(&scp->mx);
2954     cm_ReleaseSCache(scp);
2955     cm_ReleaseUser(userp);
2956     if (code == 0) {
2957         memcpy(outp->datap, &qpi, responseSize);
2958         smb_SendTran2Packet(vcp, outp, opx);
2959     } else {
2960         smb_SendTran2Error(vcp, p, opx, code);
2961     }
2962     smb_FreeTran2Packet(outp);
2963
2964     return 0;
2965 }
2966
2967 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2968 {
2969 #if 0
2970     osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2971     return CM_ERROR_BADOP;
2972 #else
2973     long code = 0;
2974     smb_fid_t *fidp;
2975     unsigned short infoLevel;
2976     char * pathp;
2977     smb_tran2Packet_t *outp;
2978     smb_tran2QPathInfo_t *spi;
2979     cm_user_t *userp;
2980     cm_scache_t *scp, *dscp;
2981     cm_req_t req;
2982     cm_space_t *spacep;
2983     char *tidPathp;
2984     char *lastComp;
2985
2986     cm_InitReq(&req);
2987
2988     infoLevel = p->parmsp[0];
2989     osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2990     if (infoLevel != SMB_INFO_STANDARD && 
2991         infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2992         infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2993         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2994                   p->opcode, infoLevel);
2995         smb_SendTran2Error(vcp, p, opx, 
2996                            infoLevel == SMB_INFO_QUERY_ALL_EAS ? CM_ERROR_EAS_NOT_SUPPORTED : CM_ERROR_BAD_LEVEL);
2997         return 0;
2998     }
2999
3000     pathp = (char *)(&p->parmsp[3]);
3001     if (smb_StoreAnsiFilenames)
3002         OemToChar(pathp,pathp);
3003     osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
3004               osi_LogSaveString(smb_logp, pathp));
3005
3006     userp = smb_GetTran2User(vcp, p);
3007     if (!userp) {
3008         osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
3009         code = CM_ERROR_BADSMB;
3010         goto done;
3011     }   
3012
3013     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
3014     if (code == CM_ERROR_TIDIPC) {
3015         /* Attempt to use a TID allocated for IPC.  The client
3016          * is probably looking for DCE RPC end points which we
3017          * don't support OR it could be looking to make a DFS
3018          * referral request. 
3019          */
3020         osi_Log0(smb_logp, "Tran2Open received IPC TID");
3021         cm_ReleaseUser(userp);
3022         return CM_ERROR_NOSUCHPATH;
3023     }
3024
3025     /*
3026     * XXX Strange hack XXX
3027     *
3028     * As of Patch 7 (13 January 98), we are having the following problem:
3029     * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3030     * requests to look up "desktop.ini" in all the subdirectories.
3031     * This can cause zillions of timeouts looking up non-existent cells
3032     * and volumes, especially in the top-level directory.
3033     *
3034     * We have not found any way to avoid this or work around it except
3035     * to explicitly ignore the requests for mount points that haven't
3036     * yet been evaluated and for directories that haven't yet been
3037     * fetched.
3038     */
3039     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3040         spacep = cm_GetSpace();
3041         smb_StripLastComponent(spacep->data, &lastComp, pathp);
3042 #ifndef SPECIAL_FOLDERS
3043         /* Make sure that lastComp is not NULL */
3044         if (lastComp) {
3045             if (stricmp(lastComp, "\\desktop.ini") == 0) {
3046                 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3047                                  CM_FLAG_CASEFOLD
3048                                  | CM_FLAG_DIRSEARCH
3049                                  | CM_FLAG_FOLLOW,
3050                                  userp, tidPathp, &req, &dscp);
3051                 if (code == 0) {
3052 #ifdef DFS_SUPPORT
3053                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3054                         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
3055                         if ( WANTS_DFS_PATHNAMES(p) || pnc )
3056                             code = CM_ERROR_PATH_NOT_COVERED;
3057                         else
3058                             code = CM_ERROR_BADSHARENAME;
3059                     } else
3060 #endif /* DFS_SUPPORT */
3061                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3062                         code = CM_ERROR_NOSUCHFILE;
3063                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3064                         cm_buf_t *bp = buf_Find(dscp, &hzero);
3065                         if (bp) {
3066                             buf_Release(bp);
3067                             bp = NULL;
3068                         }
3069                         else
3070                             code = CM_ERROR_NOSUCHFILE;
3071                     }
3072                     cm_ReleaseSCache(dscp);
3073                     if (code) {
3074                         cm_FreeSpace(spacep);
3075                         cm_ReleaseUser(userp);
3076                         smb_SendTran2Error(vcp, p, opx, code);
3077                         return 0;
3078                     }
3079                 }
3080             }
3081         }
3082 #endif /* SPECIAL_FOLDERS */
3083
3084         cm_FreeSpace(spacep);
3085     }
3086
3087     /* now do namei and stat, and copy out the info */
3088     code = cm_NameI(cm_data.rootSCachep, pathp,
3089                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3090     if (code) {
3091         cm_ReleaseUser(userp);
3092         smb_SendTran2Error(vcp, p, opx, code);
3093         return 0;
3094     }
3095
3096     fidp = smb_FindFIDByScache(vcp, scp);
3097     if (!fidp) {
3098         cm_ReleaseSCache(scp);
3099         cm_ReleaseUser(userp);
3100         smb_SendTran2Error(vcp, p, opx, code);
3101         return 0;
3102     }
3103
3104     lock_ObtainMutex(&fidp->mx);
3105     if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3106         lock_ReleaseMutex(&fidp->mx);
3107         cm_ReleaseSCache(scp);
3108         smb_ReleaseFID(fidp);
3109         cm_ReleaseUser(userp);
3110         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3111         return 0;
3112     }
3113     lock_ReleaseMutex(&fidp->mx);
3114
3115     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3116
3117     outp->totalParms = 2;
3118     outp->totalData = 0;
3119
3120     spi = (smb_tran2QPathInfo_t *)p->datap;
3121     if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3122         cm_attr_t attr;
3123
3124         /* lock the vnode with a callback; we need the current status
3125          * to determine what the new status is, in some cases.
3126          */
3127         lock_ObtainMutex(&scp->mx);
3128         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3129                           CM_SCACHESYNC_GETSTATUS
3130                          | CM_SCACHESYNC_NEEDCALLBACK);
3131         if (code) {
3132             lock_ReleaseMutex(&scp->mx);
3133             goto done;
3134         }
3135         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3136
3137         lock_ReleaseMutex(&scp->mx);
3138         lock_ObtainMutex(&fidp->mx);
3139         lock_ObtainMutex(&scp->mx);
3140
3141         /* prepare for setattr call */
3142         attr.mask = CM_ATTRMASK_LENGTH;
3143         attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3144         attr.length.HighPart = 0;
3145
3146         if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3147             smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3148             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3149             fidp->flags |= SMB_FID_MTIMESETDONE;
3150         }
3151                 
3152         if (spi->u.QPstandardInfo.attributes != 0) {
3153             if ((scp->unixModeBits & 0222)
3154                  && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3155                 /* make a writable file read-only */
3156                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3157                 attr.unixModeBits = scp->unixModeBits & ~0222;
3158             }
3159             else if ((scp->unixModeBits & 0222) == 0
3160                       && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3161                 /* make a read-only file writable */
3162                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3163                 attr.unixModeBits = scp->unixModeBits | 0222;
3164             }
3165         }
3166         lock_ReleaseMutex(&scp->mx);
3167         lock_ReleaseMutex(&fidp->mx);
3168
3169         /* call setattr */
3170         if (attr.mask)
3171             code = cm_SetAttr(scp, &attr, userp, &req);
3172         else
3173             code = 0;
3174     }               
3175     else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3176         /* we don't support EAs */
3177         code = CM_ERROR_EAS_NOT_SUPPORTED;
3178     }       
3179
3180   done:
3181     cm_ReleaseSCache(scp);
3182     cm_ReleaseUser(userp);
3183     smb_ReleaseFID(fidp);
3184     if (code == 0) 
3185         smb_SendTran2Packet(vcp, outp, opx);
3186     else 
3187         smb_SendTran2Error(vcp, p, opx, code);
3188     smb_FreeTran2Packet(outp);
3189
3190     return 0;
3191 #endif
3192 }
3193
3194 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3195 {
3196     smb_tran2Packet_t *outp;
3197     FILETIME ft;
3198     unsigned long attributes;
3199     unsigned short infoLevel;
3200     int responseSize;
3201     unsigned short fid;
3202     int delonclose = 0;
3203     cm_user_t *userp;
3204     smb_fid_t *fidp;
3205     cm_scache_t *scp;
3206     smb_tran2QFileInfo_t qfi;
3207     long code = 0;
3208     cm_req_t req;
3209
3210     cm_InitReq(&req);
3211
3212     fid = p->parmsp[0];
3213     fidp = smb_FindFID(vcp, fid, 0);
3214
3215     if (fidp == NULL) {
3216         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3217         return 0;
3218     }
3219
3220     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3221         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3222         smb_CloseFID(vcp, fidp, NULL, 0);
3223         smb_ReleaseFID(fidp);
3224         return 0;
3225     }
3226
3227     infoLevel = p->parmsp[1];
3228     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) 
3229         responseSize = sizeof(qfi.u.QFbasicInfo);
3230     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) 
3231         responseSize = sizeof(qfi.u.QFstandardInfo);
3232     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3233         responseSize = sizeof(qfi.u.QFeaInfo);
3234     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
3235         responseSize = sizeof(qfi.u.QFfileNameInfo);
3236     else {
3237         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3238                   p->opcode, infoLevel);
3239         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3240         smb_ReleaseFID(fidp);
3241         return 0;
3242     }
3243     osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3244
3245     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3246
3247     if (infoLevel > 0x100)
3248         outp->totalParms = 2;
3249     else
3250         outp->totalParms = 0;
3251     outp->totalData = responseSize;
3252
3253     userp = smb_GetTran2User(vcp, p);
3254     if (!userp) {
3255         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3256         code = CM_ERROR_BADSMB;
3257         goto done;
3258     }   
3259
3260     lock_ObtainMutex(&fidp->mx);
3261     delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3262     scp = fidp->scp;
3263     osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3264     cm_HoldSCache(scp);
3265     lock_ReleaseMutex(&fidp->mx);
3266     lock_ObtainMutex(&scp->mx);
3267     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3268                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3269     if (code) 
3270         goto done;
3271
3272     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3273
3274     /* now we have the status in the cache entry, and everything is locked.
3275      * Marshall the output data.
3276      */
3277     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3278         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3279         qfi.u.QFbasicInfo.creationTime = ft;
3280         qfi.u.QFbasicInfo.lastAccessTime = ft;
3281         qfi.u.QFbasicInfo.lastWriteTime = ft;
3282         qfi.u.QFbasicInfo.lastChangeTime = ft;
3283         attributes = smb_ExtAttributes(scp);
3284         qfi.u.QFbasicInfo.attributes = attributes;
3285     }
3286     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3287         qfi.u.QFstandardInfo.allocationSize = scp->length;
3288         qfi.u.QFstandardInfo.endOfFile = scp->length;
3289         qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3290         qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3291         qfi.u.QFstandardInfo.directory = 
3292             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3293               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3294               scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3295     }
3296     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3297         qfi.u.QFeaInfo.eaSize = 0;
3298     }
3299     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3300         unsigned long len;
3301         char *name;
3302
3303         lock_ReleaseMutex(&scp->mx);
3304         lock_ObtainMutex(&fidp->mx);
3305         lock_ObtainMutex(&scp->mx);
3306         if (fidp->NTopen_wholepathp)
3307             name = fidp->NTopen_wholepathp;
3308         else
3309             name = "\\";        /* probably can't happen */
3310         lock_ReleaseMutex(&fidp->mx);
3311         len = (unsigned long)strlen(name);
3312         outp->totalData = ((len+1)*2) + 4;      /* this is actually what we want to return */
3313         qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3314         mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3315     }
3316
3317     /* send and free the packets */
3318   done:
3319     lock_ReleaseMutex(&scp->mx);
3320     cm_ReleaseSCache(scp);
3321     cm_ReleaseUser(userp);
3322     smb_ReleaseFID(fidp);
3323     if (code == 0) {
3324         memcpy(outp->datap, &qfi, responseSize);
3325         smb_SendTran2Packet(vcp, outp, opx);
3326     } else {
3327         smb_SendTran2Error(vcp, p, opx, code);
3328     }
3329     smb_FreeTran2Packet(outp);
3330
3331     return 0;
3332 }       
3333
3334 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3335 {
3336     long code = 0;
3337     unsigned short fid;
3338     smb_fid_t *fidp;
3339     unsigned short infoLevel;
3340     smb_tran2Packet_t *outp;
3341     cm_user_t *userp = NULL;
3342     cm_scache_t *scp = NULL;
3343     cm_req_t req;
3344
3345     cm_InitReq(&req);
3346
3347     fid = p->parmsp[0];
3348     fidp = smb_FindFID(vcp, fid, 0);
3349
3350     if (fidp == NULL) {
3351         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3352         return 0;
3353     }
3354
3355     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3356         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHFILE);
3357         smb_CloseFID(vcp, fidp, NULL, 0);
3358         smb_ReleaseFID(fidp);
3359         return 0;
3360     }
3361
3362     infoLevel = p->parmsp[1];
3363     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3364     if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3365         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3366                   p->opcode, infoLevel);
3367         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3368         smb_ReleaseFID(fidp);
3369         return 0;
3370     }
3371
3372     lock_ObtainMutex(&fidp->mx);
3373     if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && 
3374         !(fidp->flags & SMB_FID_OPENDELETE)) {
3375         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x", 
3376                   fidp, fidp->scp, fidp->flags);
3377         lock_ReleaseMutex(&fidp->mx);
3378         smb_ReleaseFID(fidp);
3379         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3380         return 0;
3381     }
3382     if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO || 
3383          infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3384          && !(fidp->flags & SMB_FID_OPENWRITE)) {
3385         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x", 
3386                   fidp, fidp->scp, fidp->flags);
3387         lock_ReleaseMutex(&fidp->mx);
3388         smb_ReleaseFID(fidp);
3389         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3390         return 0;
3391     }
3392
3393     scp = fidp->scp;
3394     osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3395     cm_HoldSCache(scp);
3396     lock_ReleaseMutex(&fidp->mx);
3397
3398     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3399
3400     outp->totalParms = 2;
3401     outp->totalData = 0;
3402
3403     userp = smb_GetTran2User(vcp, p);
3404     if (!userp) {
3405         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3406         code = CM_ERROR_BADSMB;
3407         goto done;
3408     }   
3409
3410     if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3411         FILETIME lastMod;
3412         unsigned int attribute;
3413         cm_attr_t attr;
3414         smb_tran2QFileInfo_t *sfi;
3415
3416         sfi = (smb_tran2QFileInfo_t *)p->datap;
3417
3418         /* lock the vnode with a callback; we need the current status
3419          * to determine what the new status is, in some cases.
3420          */
3421         lock_ObtainMutex(&scp->mx);
3422         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3423                           CM_SCACHESYNC_GETSTATUS
3424                          | CM_SCACHESYNC_NEEDCALLBACK);
3425         if (code) {
3426             lock_ReleaseMutex(&scp->mx);
3427             goto done;
3428         }
3429
3430         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3431
3432         lock_ReleaseMutex(&scp->mx);
3433         lock_ObtainMutex(&fidp->mx);
3434         lock_ObtainMutex(&scp->mx);
3435
3436         /* prepare for setattr call */
3437         attr.mask = 0;
3438
3439         lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3440         /* when called as result of move a b, lastMod is (-1, -1). 
3441          * If the check for -1 is not present, timestamp
3442          * of the resulting file will be 1969 (-1)
3443          */
3444         if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
3445              lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3446             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3447             smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3448             fidp->flags |= SMB_FID_MTIMESETDONE;
3449         }
3450                 
3451         attribute = sfi->u.QFbasicInfo.attributes;
3452         if (attribute != 0) {
3453             if ((scp->unixModeBits & 0222)
3454                  && (attribute & SMB_ATTR_READONLY) != 0) {
3455                 /* make a writable file read-only */
3456                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3457                 attr.unixModeBits = scp->unixModeBits & ~0222;
3458             }
3459             else if ((scp->unixModeBits & 0222) == 0
3460                       && (attribute & SMB_ATTR_READONLY) == 0) {
3461                 /* make a read-only file writable */
3462                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3463                 attr.unixModeBits = scp->unixModeBits | 0222;
3464             }
3465         }
3466         lock_ReleaseMutex(&scp->mx);
3467         lock_ReleaseMutex(&fidp->mx);
3468
3469         /* call setattr */
3470         if (attr.mask)
3471             code = cm_SetAttr(scp, &attr, userp, &req);
3472         else
3473             code = 0;
3474     }
3475     else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3476         int delflag = *((char *)(p->datap));
3477         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p", 
3478                  delflag, fidp, scp);
3479         if (*((char *)(p->datap))) {    /* File is Deleted */
3480             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3481                                      &req);
3482             if (code == 0) {
3483                 lock_ObtainMutex(&fidp->mx);
3484                 fidp->flags |= SMB_FID_DELONCLOSE;
3485                 lock_ReleaseMutex(&fidp->mx);
3486             } else {
3487                 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x", 
3488                          fidp, scp, code);
3489             }
3490         }               
3491         else {  
3492             code = 0;
3493             lock_ObtainMutex(&fidp->mx);
3494             fidp->flags &= ~SMB_FID_DELONCLOSE;
3495             lock_ReleaseMutex(&fidp->mx);
3496         }
3497     }       
3498     else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3499              infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3500         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3501         cm_attr_t attr;
3502
3503         attr.mask = CM_ATTRMASK_LENGTH;
3504         attr.length.LowPart = size.LowPart;
3505         attr.length.HighPart = size.HighPart;
3506         code = cm_SetAttr(scp, &attr, userp, &req);
3507     }       
3508
3509   done:
3510     cm_ReleaseSCache(scp);
3511     cm_ReleaseUser(userp);
3512     smb_ReleaseFID(fidp);
3513     if (code == 0) 
3514         smb_SendTran2Packet(vcp, outp, opx);
3515     else 
3516         smb_SendTran2Error(vcp, p, opx, code);
3517     smb_FreeTran2Packet(outp);
3518
3519     return 0;
3520 }
3521
3522 long 
3523 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3524 {
3525     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3526     return CM_ERROR_BADOP;
3527 }
3528
3529 long 
3530 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3531 {
3532     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3533     return CM_ERROR_BADOP;
3534 }
3535
3536 long 
3537 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3538 {
3539     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3540     return CM_ERROR_BADOP;
3541 }
3542
3543 long 
3544 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3545 {
3546     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3547     return CM_ERROR_BADOP;
3548 }
3549
3550 long 
3551 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3552 {
3553     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3554     return CM_ERROR_BADOP;
3555 }
3556
3557 long 
3558 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3559 {
3560     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3561     return CM_ERROR_BADOP;
3562 }
3563
3564 struct smb_v2_referral {
3565     USHORT ServerType;
3566     USHORT ReferralFlags;
3567     ULONG  Proximity;
3568     ULONG  TimeToLive;
3569     USHORT DfsPathOffset;
3570     USHORT DfsAlternativePathOffset;
3571     USHORT NetworkAddressOffset;
3572 };
3573
3574 long 
3575 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3576 {
3577     /* This is a UNICODE only request (bit15 of Flags2) */
3578     /* The TID must be IPC$ */
3579
3580     /* The documentation for the Flags response field is contradictory */
3581
3582     /* Use Version 1 Referral Element Format */
3583     /* ServerType = 0; indicates the next server should be queried for the file */
3584     /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3585     /* Node = UnicodeString of UNC path of the next share name */
3586 #ifdef DFS_SUPPORT
3587     long code = 0;
3588     int maxReferralLevel = 0;
3589     char requestFileName[1024] = "";
3590     char referralPath[1024] = "";
3591     smb_tran2Packet_t *outp = 0;
3592     cm_user_t *userp = 0;
3593     cm_scache_t *scp = 0;
3594     cm_scache_t *dscp = 0;
3595     cm_req_t req;
3596     CPINFO CodePageInfo;
3597     int i, nbnLen, reqLen, refLen;
3598     int idx;
3599
3600     cm_InitReq(&req);
3601
3602     maxReferralLevel = p->parmsp[0];
3603
3604     GetCPInfo(CP_ACP, &CodePageInfo);
3605     WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1, 
3606                         requestFileName, 1024, NULL, NULL);
3607
3608     osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]", 
3609              maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3610
3611     nbnLen = strlen(cm_NetbiosName);
3612     reqLen = strlen(requestFileName);
3613
3614     if (reqLen > nbnLen + 2 && requestFileName[0] == '\\' &&
3615         !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3616         requestFileName[nbnLen+1] == '\\')