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