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