windows-fetchstatus-20061003
[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,  
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     fidp->scp = scp;
2361     /* and the user */
2362     fidp->userp = userp;
2363         
2364     /* compute open mode */
2365     if (openMode != 1) 
2366         fidp->flags |= SMB_FID_OPENREAD;
2367     if (openMode == 1 || openMode == 2)
2368         fidp->flags |= SMB_FID_OPENWRITE;
2369
2370     /* remember that the file was newly created */
2371     if (created)
2372         fidp->flags |= SMB_FID_CREATED;
2373
2374     lock_ReleaseMutex(&fidp->mx);
2375
2376     smb_ReleaseFID(fidp);
2377         
2378     cm_Open(scp, 0, userp);
2379
2380     /* copy out remainder of the parms */
2381     parmSlot = 0;
2382     outp->parmsp[parmSlot++] = fidp->fid;
2383     lock_ObtainMutex(&scp->mx);
2384     if (extraInfo) {
2385         outp->parmsp[parmSlot++] = smb_Attributes(scp);
2386         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2387         outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2388         outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2389         outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2390         outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2391         outp->parmsp[parmSlot++] = openMode;
2392         outp->parmsp[parmSlot++] = 0;   /* file type 0 ==> normal file or dir */
2393         outp->parmsp[parmSlot++] = 0;   /* IPC junk */
2394     }   
2395     /* and the final "always present" stuff */
2396     outp->parmsp[parmSlot++] = openAction;
2397     /* next write out the "unique" ID */
2398     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff); 
2399     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff); 
2400     outp->parmsp[parmSlot++] = 0; 
2401     if (returnEALength) {
2402         outp->parmsp[parmSlot++] = 0; 
2403         outp->parmsp[parmSlot++] = 0; 
2404     }   
2405     lock_ReleaseMutex(&scp->mx);
2406     outp->totalData = 0;                /* total # of data bytes */
2407     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
2408
2409     smb_SendTran2Packet(vcp, outp, op);
2410
2411     smb_FreeTran2Packet(outp);
2412
2413     cm_ReleaseUser(userp);
2414     /* leave scp held since we put it in fidp->scp */
2415     return 0;
2416 }   
2417
2418 long smb_ReceiveTran2FindFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2419 {
2420     osi_Log0(smb_logp,"ReceiveTran2FindFirst - NOT_SUPPORTED");
2421     return CM_ERROR_BADOP;
2422 }
2423
2424 long smb_ReceiveTran2FindNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2425 {
2426     osi_Log0(smb_logp,"ReceiveTran2FindNext - NOT_SUPPORTED");
2427     return CM_ERROR_BADOP;
2428 }
2429
2430 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2431 {
2432     unsigned short fid;
2433     unsigned short infolevel;
2434
2435     infolevel = p->parmsp[0];
2436     fid = p->parmsp[1];
2437     osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2438     
2439     return CM_ERROR_BADOP;
2440 }
2441
2442 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2443 {
2444     smb_tran2Packet_t *outp;
2445     smb_tran2QFSInfo_t qi;
2446     int responseSize;
2447     static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2448         
2449     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2450
2451     switch (p->parmsp[0]) {
2452     case SMB_INFO_ALLOCATION: 
2453         responseSize = sizeof(qi.u.allocInfo); 
2454         break;
2455     case SMB_INFO_VOLUME: 
2456         responseSize = sizeof(qi.u.volumeInfo); 
2457         break;
2458     case SMB_QUERY_FS_VOLUME_INFO: 
2459         responseSize = sizeof(qi.u.FSvolumeInfo); 
2460         break;
2461     case SMB_QUERY_FS_SIZE_INFO: 
2462         responseSize = sizeof(qi.u.FSsizeInfo); 
2463         break;
2464     case SMB_QUERY_FS_DEVICE_INFO: 
2465         responseSize = sizeof(qi.u.FSdeviceInfo); 
2466         break;
2467     case SMB_QUERY_FS_ATTRIBUTE_INFO: 
2468         responseSize = sizeof(qi.u.FSattributeInfo); 
2469         break;
2470     case SMB_INFO_UNIX:         /* CIFS Unix Info */
2471     case SMB_INFO_MACOS:        /* Mac FS Info */
2472     default: 
2473         return CM_ERROR_BADOP;
2474     }
2475
2476     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2477     switch (p->parmsp[0]) {
2478     case SMB_INFO_ALLOCATION: 
2479         /* alloc info */
2480         qi.u.allocInfo.FSID = 0;
2481         qi.u.allocInfo.sectorsPerAllocUnit = 1;
2482         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2483         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2484         qi.u.allocInfo.bytesPerSector = 1024;
2485         break;
2486
2487     case SMB_INFO_VOLUME: 
2488         /* volume info */
2489         qi.u.volumeInfo.vsn = 1234;
2490         qi.u.volumeInfo.vnCount = 4;
2491         /* we're supposed to pad it out with zeroes to the end */
2492         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2493         memcpy(qi.u.volumeInfo.label, "AFS", 4);
2494         break;
2495
2496     case SMB_QUERY_FS_VOLUME_INFO: 
2497         /* FS volume info */
2498         memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2499         qi.u.FSvolumeInfo.vsn = 1234;
2500         qi.u.FSvolumeInfo.vnCount = 8;
2501         memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2502         break;
2503
2504     case SMB_QUERY_FS_SIZE_INFO: 
2505         /* FS size info */
2506         qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2507         qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2508         qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2509         qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2510         qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2511         qi.u.FSsizeInfo.bytesPerSector = 1024;
2512         break;
2513
2514     case SMB_QUERY_FS_DEVICE_INFO: 
2515         /* FS device info */
2516         qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2517         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2518         break;
2519
2520     case SMB_QUERY_FS_ATTRIBUTE_INFO: 
2521         /* FS attribute info */
2522         /* attributes, defined in WINNT.H:
2523          *      FILE_CASE_SENSITIVE_SEARCH      0x1
2524          *      FILE_CASE_PRESERVED_NAMES       0x2
2525          *      FILE_VOLUME_QUOTAS              0x10
2526          *      <no name defined>               0x4000
2527          *         If bit 0x4000 is not set, Windows 95 thinks
2528          *         we can't handle long (non-8.3) names,
2529          *         despite our protestations to the contrary.
2530          */
2531         qi.u.FSattributeInfo.attributes = 0x4003;
2532         qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2533         qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2534         memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2535         break;
2536     }   
2537         
2538     /* copy out return data, and set corresponding sizes */
2539     outp->totalParms = 0;
2540     outp->totalData = responseSize;
2541     memcpy(outp->datap, &qi, responseSize);
2542
2543     /* send and free the packets */
2544     smb_SendTran2Packet(vcp, outp, op);
2545     smb_FreeTran2Packet(outp);
2546
2547     return 0;
2548 }
2549
2550 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2551 {
2552     osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2553     return CM_ERROR_BADOP;
2554 }
2555
2556 struct smb_ShortNameRock {
2557     char *maskp;
2558     unsigned int vnode;
2559     char *shortName;
2560     size_t shortNameLen;
2561 };      
2562
2563 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2564                          osi_hyper_t *offp)
2565 {       
2566     struct smb_ShortNameRock *rockp;
2567     char *shortNameEnd;
2568
2569     rockp = vrockp;
2570     /* compare both names and vnodes, though probably just comparing vnodes
2571      * would be safe enough.
2572      */
2573     if (cm_stricmp(dep->name, rockp->maskp) != 0)
2574         return 0;
2575     if (ntohl(dep->fid.vnode) != rockp->vnode)
2576         return 0;
2577     /* This is the entry */
2578     cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2579     rockp->shortNameLen = shortNameEnd - rockp->shortName;
2580     return CM_ERROR_STOPNOW;
2581 }       
2582
2583 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2584         char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2585 {
2586     struct smb_ShortNameRock rock;
2587     char *lastNamep;
2588     cm_space_t *spacep;
2589     cm_scache_t *dscp;
2590     int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2591     long code = 0;
2592     osi_hyper_t thyper;
2593
2594     spacep = cm_GetSpace();
2595     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2596
2597     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2598                      reqp, &dscp);
2599     cm_FreeSpace(spacep);
2600     if (code) 
2601         return code;
2602
2603 #ifdef DFS_SUPPORT
2604     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2605         cm_ReleaseSCache(dscp);
2606         cm_ReleaseUser(userp);
2607         return CM_ERROR_PATH_NOT_COVERED;
2608     }
2609 #endif /* DFS_SUPPORT */
2610
2611     if (!lastNamep) lastNamep = pathp;
2612     else lastNamep++;
2613     thyper.LowPart = 0;
2614     thyper.HighPart = 0;
2615     rock.shortName = shortName;
2616     rock.vnode = vnode;
2617     rock.maskp = lastNamep;
2618     code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2619
2620     cm_ReleaseSCache(dscp);
2621
2622     if (code == 0)
2623         return CM_ERROR_NOSUCHFILE;
2624     if (code == CM_ERROR_STOPNOW) {
2625         *shortNameLenp = rock.shortNameLen;
2626         return 0;
2627     }
2628     return code;
2629 }
2630
2631 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2632 {
2633     smb_tran2Packet_t *outp;
2634     afs_uint32 dosTime;
2635     FILETIME ft;
2636     unsigned short infoLevel;
2637     smb_tran2QPathInfo_t qpi;
2638     int responseSize;
2639     unsigned short attributes;
2640     unsigned long extAttributes;
2641     char shortName[13];
2642     unsigned int len;
2643     cm_user_t *userp;
2644     cm_space_t *spacep;
2645     cm_scache_t *scp, *dscp;
2646     int delonclose = 0;
2647     long code = 0;
2648     char *pathp;
2649     char *tidPathp;
2650     char *lastComp;
2651     cm_req_t req;
2652
2653     cm_InitReq(&req);
2654
2655     infoLevel = p->parmsp[0];
2656     if (infoLevel == SMB_INFO_IS_NAME_VALID) 
2657         responseSize = 0;
2658     else if (infoLevel == SMB_INFO_STANDARD) 
2659         responseSize = sizeof(qpi.u.QPstandardInfo);
2660     else if (infoLevel == SMB_INFO_QUERY_EA_SIZE) 
2661         responseSize = sizeof(qpi.u.QPeaSizeInfo);
2662     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2663         responseSize = sizeof(qpi.u.QPfileBasicInfo);
2664     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2665         responseSize = sizeof(qpi.u.QPfileStandardInfo);
2666     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2667         responseSize = sizeof(qpi.u.QPfileEaInfo);
2668     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
2669         responseSize = sizeof(qpi.u.QPfileNameInfo);
2670     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) 
2671         responseSize = sizeof(qpi.u.QPfileAllInfo);
2672     else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) 
2673         responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2674     else {
2675         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2676                   p->opcode, infoLevel);
2677         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
2678         return 0;
2679     }
2680
2681     pathp = (char *)(&p->parmsp[3]);
2682     if (smb_StoreAnsiFilenames)
2683         OemToChar(pathp,pathp);
2684     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2685               osi_LogSaveString(smb_logp, pathp));
2686
2687     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2688
2689     if (infoLevel > 0x100)
2690         outp->totalParms = 2;
2691     else
2692         outp->totalParms = 0;
2693     outp->totalData = responseSize;
2694         
2695     /* now, if we're at infoLevel 6, we're only being asked to check
2696      * the syntax, so we just OK things now.  In particular, we're *not*
2697      * being asked to verify anything about the state of any parent dirs.
2698      */
2699     if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2700         smb_SendTran2Packet(vcp, outp, opx);
2701         smb_FreeTran2Packet(outp);
2702         return 0;
2703     }   
2704         
2705     userp = smb_GetTran2User(vcp, p);
2706     if (!userp) {
2707         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2708         smb_FreeTran2Packet(outp);
2709         return CM_ERROR_BADSMB;
2710     }
2711
2712     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2713     if(code) {
2714         cm_ReleaseUser(userp);
2715         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2716         smb_FreeTran2Packet(outp);
2717         return 0;
2718     }
2719
2720     /*
2721      * XXX Strange hack XXX
2722      *
2723      * As of Patch 7 (13 January 98), we are having the following problem:
2724      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2725      * requests to look up "desktop.ini" in all the subdirectories.
2726      * This can cause zillions of timeouts looking up non-existent cells
2727      * and volumes, especially in the top-level directory.
2728      *
2729      * We have not found any way to avoid this or work around it except
2730      * to explicitly ignore the requests for mount points that haven't
2731      * yet been evaluated and for directories that haven't yet been
2732      * fetched.
2733      */
2734     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2735         spacep = cm_GetSpace();
2736         smb_StripLastComponent(spacep->data, &lastComp, pathp);
2737 #ifndef SPECIAL_FOLDERS
2738         /* Make sure that lastComp is not NULL */
2739         if (lastComp) {
2740             if (stricmp(lastComp, "\\desktop.ini") == 0) {
2741                 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2742                                  CM_FLAG_CASEFOLD
2743                                  | CM_FLAG_DIRSEARCH
2744                                  | CM_FLAG_FOLLOW,
2745                                  userp, tidPathp, &req, &dscp);
2746                 if (code == 0) {
2747 #ifdef DFS_SUPPORT
2748                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2749                         if ( WANTS_DFS_PATHNAMES(p) )
2750                             code = CM_ERROR_PATH_NOT_COVERED;
2751                         else
2752                             code = CM_ERROR_BADSHARENAME;
2753                     } else
2754 #endif /* DFS_SUPPORT */
2755                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2756                         code = CM_ERROR_NOSUCHFILE;
2757                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2758                         cm_buf_t *bp = buf_Find(dscp, &hzero);
2759                         if (bp)
2760                             buf_Release(bp);
2761                         else
2762                             code = CM_ERROR_NOSUCHFILE;
2763                     }
2764                     cm_ReleaseSCache(dscp);
2765                     if (code) {
2766                         cm_FreeSpace(spacep);
2767                         cm_ReleaseUser(userp);
2768                         smb_SendTran2Error(vcp, p, opx, code);
2769                         smb_FreeTran2Packet(outp);
2770                         return 0;
2771                     }
2772                 }
2773             }
2774         }
2775 #endif /* SPECIAL_FOLDERS */
2776
2777         cm_FreeSpace(spacep);
2778     }
2779
2780     /* now do namei and stat, and copy out the info */
2781     code = cm_NameI(cm_data.rootSCachep, pathp,
2782                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2783
2784     if (code) {
2785         cm_ReleaseUser(userp);
2786         smb_SendTran2Error(vcp, p, opx, code);
2787         smb_FreeTran2Packet(outp);
2788         return 0;
2789     }
2790
2791 #ifdef DFS_SUPPORT
2792     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2793         cm_ReleaseSCache(scp);
2794         cm_ReleaseUser(userp);
2795         if ( WANTS_DFS_PATHNAMES(p) )
2796             code = CM_ERROR_PATH_NOT_COVERED;
2797         else
2798             code = CM_ERROR_BADSHARENAME;
2799         smb_SendTran2Error(vcp, p, opx, code);
2800         smb_FreeTran2Packet(outp);
2801         return 0;
2802     }
2803 #endif /* DFS_SUPPORT */
2804
2805     lock_ObtainMutex(&scp->mx);
2806     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2807                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2808     if (code) goto done;
2809
2810     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2811         
2812     /* now we have the status in the cache entry, and everything is locked.
2813      * Marshall the output data.
2814      */
2815     /* for info level 108, figure out short name */
2816     if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2817         code = cm_GetShortName(pathp, userp, &req,
2818                                 tidPathp, scp->fid.vnode, shortName,
2819                                 (size_t *) &len);
2820         if (code) {
2821             goto done;
2822         }
2823
2824         qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2825         mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2826
2827         goto done;
2828     }
2829     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2830         len = strlen(lastComp);
2831         qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2832         mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2833
2834         goto done;
2835     }
2836     else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2837         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2838         qpi.u.QPstandardInfo.creationDateTime = dosTime;
2839         qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2840         qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2841         qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2842         qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2843         attributes = smb_Attributes(scp);
2844         qpi.u.QPstandardInfo.attributes = attributes;
2845         qpi.u.QPstandardInfo.eaSize = 0;
2846     }
2847     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2848         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2849         qpi.u.QPfileBasicInfo.creationTime = ft;
2850         qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2851         qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2852         qpi.u.QPfileBasicInfo.changeTime = ft;
2853         extAttributes = smb_ExtAttributes(scp);
2854         qpi.u.QPfileBasicInfo.attributes = extAttributes;
2855         qpi.u.QPfileBasicInfo.reserved = 0;
2856     }
2857     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2858         smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2859         if (fidp) {
2860             lock_ObtainMutex(&fidp->mx);
2861             delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2862             lock_ReleaseMutex(&fidp->mx);
2863             smb_ReleaseFID(fidp);
2864         }
2865
2866         qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2867         qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2868         qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2869         qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2870         qpi.u.QPfileStandardInfo.directory = 
2871             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2872               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2873               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2874         qpi.u.QPfileStandardInfo.reserved = 0;
2875     }
2876     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2877         qpi.u.QPfileEaInfo.eaSize = 0;
2878     }
2879     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2880         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2881         qpi.u.QPfileAllInfo.creationTime = ft;
2882         qpi.u.QPfileAllInfo.lastAccessTime = ft;
2883         qpi.u.QPfileAllInfo.lastWriteTime = ft;
2884         qpi.u.QPfileAllInfo.changeTime = ft;
2885         extAttributes = smb_ExtAttributes(scp);
2886         qpi.u.QPfileAllInfo.attributes = extAttributes;
2887         qpi.u.QPfileAllInfo.allocationSize = scp->length;
2888         qpi.u.QPfileAllInfo.endOfFile = scp->length;
2889         qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2890         qpi.u.QPfileAllInfo.deletePending = 0;
2891         qpi.u.QPfileAllInfo.directory = 
2892             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2893               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2894               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2895         qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2896         qpi.u.QPfileAllInfo.indexNumber.LowPart  = scp->fid.volume;
2897         qpi.u.QPfileAllInfo.eaSize = 0;
2898         qpi.u.QPfileAllInfo.accessFlags = 0;
2899         qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2900         qpi.u.QPfileAllInfo.indexNumber2.LowPart  = scp->fid.unique;
2901         qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2902         qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2903         qpi.u.QPfileAllInfo.mode = 0;
2904         qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2905         len = strlen(lastComp);
2906         qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2907         mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2908     }
2909
2910     /* send and free the packets */
2911   done:
2912     lock_ReleaseMutex(&scp->mx);
2913     cm_ReleaseSCache(scp);
2914     cm_ReleaseUser(userp);
2915     if (code == 0) {
2916         memcpy(outp->datap, &qpi, responseSize);
2917         smb_SendTran2Packet(vcp, outp, opx);
2918     } else {
2919         smb_SendTran2Error(vcp, p, opx, code);
2920     }
2921     smb_FreeTran2Packet(outp);
2922
2923     return 0;
2924 }
2925
2926 long smb_ReceiveTran2SetPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2927 {
2928 #if 0
2929     osi_Log0(smb_logp,"ReceiveTran2SetPathInfo - NOT_SUPPORTED");
2930     return CM_ERROR_BADOP;
2931 #else
2932     long code = 0;
2933     smb_fid_t *fidp;
2934     unsigned short infoLevel;
2935     char * pathp;
2936     smb_tran2Packet_t *outp;
2937     smb_tran2QPathInfo_t *spi;
2938     cm_user_t *userp;
2939     cm_scache_t *scp, *dscp;
2940     cm_req_t req;
2941     cm_space_t *spacep;
2942     char *tidPathp;
2943     char *lastComp;
2944
2945     cm_InitReq(&req);
2946
2947     infoLevel = p->parmsp[0];
2948     osi_Log1(smb_logp,"ReceiveTran2SetPathInfo type 0x%x", infoLevel);
2949     if (infoLevel != SMB_INFO_STANDARD && 
2950         infoLevel != SMB_INFO_QUERY_EA_SIZE &&
2951         infoLevel != SMB_INFO_QUERY_ALL_EAS) {
2952         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2953                   p->opcode, infoLevel);
2954         smb_SendTran2Error(vcp, p, opx, CM_ERROR_INVAL);
2955         return 0;
2956     }
2957
2958     pathp = (char *)(&p->parmsp[3]);
2959     if (smb_StoreAnsiFilenames)
2960         OemToChar(pathp,pathp);
2961     osi_Log2(smb_logp, "T2 SetPathInfo infolevel 0x%x path %s", infoLevel,
2962               osi_LogSaveString(smb_logp, pathp));
2963
2964     userp = smb_GetTran2User(vcp, p);
2965     if (!userp) {
2966         osi_Log1(smb_logp,"ReceiveTran2SetPathInfo unable to resolve user [%d]", p->uid);
2967         code = CM_ERROR_BADSMB;
2968         goto done;
2969     }   
2970
2971     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2972     if (code == CM_ERROR_TIDIPC) {
2973         /* Attempt to use a TID allocated for IPC.  The client
2974          * is probably looking for DCE RPC end points which we
2975          * don't support OR it could be looking to make a DFS
2976          * referral request. 
2977          */
2978         osi_Log0(smb_logp, "Tran2Open received IPC TID");
2979         cm_ReleaseUser(userp);
2980         return CM_ERROR_NOSUCHPATH;
2981     }
2982
2983     /*
2984     * XXX Strange hack XXX
2985     *
2986     * As of Patch 7 (13 January 98), we are having the following problem:
2987     * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2988     * requests to look up "desktop.ini" in all the subdirectories.
2989     * This can cause zillions of timeouts looking up non-existent cells
2990     * and volumes, especially in the top-level directory.
2991     *
2992     * We have not found any way to avoid this or work around it except
2993     * to explicitly ignore the requests for mount points that haven't
2994     * yet been evaluated and for directories that haven't yet been
2995     * fetched.
2996     */
2997     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2998         spacep = cm_GetSpace();
2999         smb_StripLastComponent(spacep->data, &lastComp, pathp);
3000 #ifndef SPECIAL_FOLDERS
3001         /* Make sure that lastComp is not NULL */
3002         if (lastComp) {
3003             if (stricmp(lastComp, "\\desktop.ini") == 0) {
3004                 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3005                                  CM_FLAG_CASEFOLD
3006                                  | CM_FLAG_DIRSEARCH
3007                                  | CM_FLAG_FOLLOW,
3008                                  userp, tidPathp, &req, &dscp);
3009                 if (code == 0) {
3010 #ifdef DFS_SUPPORT
3011                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
3012                         if ( WANTS_DFS_PATHNAMES(p) )
3013                             code = CM_ERROR_PATH_NOT_COVERED;
3014                         else
3015                             code = CM_ERROR_BADSHARENAME;
3016                     } else
3017 #endif /* DFS_SUPPORT */
3018                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
3019                         code = CM_ERROR_NOSUCHFILE;
3020                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3021                         cm_buf_t *bp = buf_Find(dscp, &hzero);
3022                         if (bp)
3023                             buf_Release(bp);
3024                         else
3025                             code = CM_ERROR_NOSUCHFILE;
3026                     }
3027                     cm_ReleaseSCache(dscp);
3028                     if (code) {
3029                         cm_FreeSpace(spacep);
3030                         cm_ReleaseUser(userp);
3031                         smb_SendTran2Error(vcp, p, opx, code);
3032                         return 0;
3033                     }
3034                 }
3035             }
3036         }
3037 #endif /* SPECIAL_FOLDERS */
3038
3039         cm_FreeSpace(spacep);
3040     }
3041
3042     /* now do namei and stat, and copy out the info */
3043     code = cm_NameI(cm_data.rootSCachep, pathp,
3044                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
3045     if (code) {
3046         cm_ReleaseUser(userp);
3047         smb_SendTran2Error(vcp, p, opx, code);
3048         return 0;
3049     }
3050
3051     fidp = smb_FindFIDByScache(vcp, scp);
3052     if (!fidp) {
3053         cm_ReleaseUser(userp);
3054         cm_ReleaseSCache(scp);
3055         smb_SendTran2Error(vcp, p, opx, code);
3056         return 0;
3057     }
3058
3059     lock_ObtainMutex(&fidp->mx);
3060     if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3061         lock_ReleaseMutex(&fidp->mx);
3062         smb_ReleaseFID(fidp);
3063         cm_ReleaseUser(userp);
3064         cm_ReleaseSCache(scp);
3065         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3066         return 0;
3067     }
3068     lock_ReleaseMutex(&fidp->mx);
3069
3070     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3071
3072     outp->totalParms = 2;
3073     outp->totalData = 0;
3074
3075     spi = (smb_tran2QPathInfo_t *)p->datap;
3076     if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
3077         cm_attr_t attr;
3078
3079         /* lock the vnode with a callback; we need the current status
3080          * to determine what the new status is, in some cases.
3081          */
3082         lock_ObtainMutex(&scp->mx);
3083         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3084                           CM_SCACHESYNC_GETSTATUS
3085                          | CM_SCACHESYNC_NEEDCALLBACK);
3086         if (code) {
3087             lock_ReleaseMutex(&scp->mx);
3088             goto done;
3089         }
3090         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3091
3092         lock_ReleaseMutex(&scp->mx);
3093         lock_ObtainMutex(&fidp->mx);
3094         lock_ObtainMutex(&scp->mx);
3095
3096         /* prepare for setattr call */
3097         attr.mask = CM_ATTRMASK_LENGTH;
3098         attr.length.LowPart = spi->u.QPstandardInfo.dataSize;
3099         attr.length.HighPart = 0;
3100
3101         if (spi->u.QPstandardInfo.lastWriteDateTime != 0) {
3102             smb_UnixTimeFromSearchTime(&attr.clientModTime, spi->u.QPstandardInfo.lastWriteDateTime);
3103             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3104             fidp->flags |= SMB_FID_MTIMESETDONE;
3105         }
3106                 
3107         if (spi->u.QPstandardInfo.attributes != 0) {
3108             if ((scp->unixModeBits & 0222)
3109                  && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) != 0) {
3110                 /* make a writable file read-only */
3111                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3112                 attr.unixModeBits = scp->unixModeBits & ~0222;
3113             }
3114             else if ((scp->unixModeBits & 0222) == 0
3115                       && (spi->u.QPstandardInfo.attributes & SMB_ATTR_READONLY) == 0) {
3116                 /* make a read-only file writable */
3117                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3118                 attr.unixModeBits = scp->unixModeBits | 0222;
3119             }
3120         }
3121         lock_ReleaseMutex(&scp->mx);
3122         lock_ReleaseMutex(&fidp->mx);
3123
3124         /* call setattr */
3125         if (attr.mask)
3126             code = cm_SetAttr(scp, &attr, userp, &req);
3127         else
3128             code = 0;
3129     }               
3130     else if (infoLevel == SMB_INFO_QUERY_ALL_EAS) {
3131         /* we don't support EAs */
3132         code = CM_ERROR_INVAL;
3133     }       
3134
3135   done:
3136     cm_ReleaseSCache(scp);
3137     cm_ReleaseUser(userp);
3138     smb_ReleaseFID(fidp);
3139     if (code == 0) 
3140         smb_SendTran2Packet(vcp, outp, opx);
3141     else 
3142         smb_SendTran2Error(vcp, p, opx, code);
3143     smb_FreeTran2Packet(outp);
3144
3145     return 0;
3146 #endif
3147 }
3148
3149 long smb_ReceiveTran2QFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3150 {
3151     smb_tran2Packet_t *outp;
3152     FILETIME ft;
3153     unsigned long attributes;
3154     unsigned short infoLevel;
3155     int responseSize;
3156     unsigned short fid;
3157     int delonclose = 0;
3158     cm_user_t *userp;
3159     smb_fid_t *fidp;
3160     cm_scache_t *scp;
3161     smb_tran2QFileInfo_t qfi;
3162     long code = 0;
3163     cm_req_t req;
3164
3165     cm_InitReq(&req);
3166
3167     fid = p->parmsp[0];
3168     fidp = smb_FindFID(vcp, fid, 0);
3169
3170     if (fidp == NULL) {
3171         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3172         return 0;
3173     }
3174
3175     infoLevel = p->parmsp[1];
3176     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) 
3177         responseSize = sizeof(qfi.u.QFbasicInfo);
3178     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) 
3179         responseSize = sizeof(qfi.u.QFstandardInfo);
3180     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
3181         responseSize = sizeof(qfi.u.QFeaInfo);
3182     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
3183         responseSize = sizeof(qfi.u.QFfileNameInfo);
3184     else {
3185         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3186                   p->opcode, infoLevel);
3187         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3188         smb_ReleaseFID(fidp);
3189         return 0;
3190     }
3191     osi_Log2(smb_logp, "T2 QFileInfo type 0x%x fid %d", infoLevel, fid);
3192
3193     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
3194
3195     if (infoLevel > 0x100)
3196         outp->totalParms = 2;
3197     else
3198         outp->totalParms = 0;
3199     outp->totalData = responseSize;
3200
3201     userp = smb_GetTran2User(vcp, p);
3202     if (!userp) {
3203         osi_Log1(smb_logp, "ReceiveTran2QFileInfo unable to resolve user [%d]", p->uid);
3204         code = CM_ERROR_BADSMB;
3205         goto done;
3206     }   
3207
3208     lock_ObtainMutex(&fidp->mx);
3209     delonclose = fidp->flags & SMB_FID_DELONCLOSE;
3210     scp = fidp->scp;
3211     cm_HoldSCache(scp);
3212     lock_ReleaseMutex(&fidp->mx);
3213     lock_ObtainMutex(&scp->mx);
3214     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3215                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3216     if (code) 
3217         goto done;
3218
3219     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3220
3221     /* now we have the status in the cache entry, and everything is locked.
3222      * Marshall the output data.
3223      */
3224     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3225         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3226         qfi.u.QFbasicInfo.creationTime = ft;
3227         qfi.u.QFbasicInfo.lastAccessTime = ft;
3228         qfi.u.QFbasicInfo.lastWriteTime = ft;
3229         qfi.u.QFbasicInfo.lastChangeTime = ft;
3230         attributes = smb_ExtAttributes(scp);
3231         qfi.u.QFbasicInfo.attributes = attributes;
3232     }
3233     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3234         qfi.u.QFstandardInfo.allocationSize = scp->length;
3235         qfi.u.QFstandardInfo.endOfFile = scp->length;
3236         qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3237         qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3238         qfi.u.QFstandardInfo.directory = 
3239             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3240               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3241               scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3242     }
3243     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3244         qfi.u.QFeaInfo.eaSize = 0;
3245     }
3246     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3247         unsigned long len;
3248         char *name;
3249
3250         lock_ReleaseMutex(&scp->mx);
3251         lock_ObtainMutex(&fidp->mx);
3252         lock_ObtainMutex(&scp->mx);
3253         if (fidp->NTopen_wholepathp)
3254             name = fidp->NTopen_wholepathp;
3255         else
3256             name = "\\";        /* probably can't happen */
3257         lock_ReleaseMutex(&fidp->mx);
3258         len = (unsigned long)strlen(name);
3259         outp->totalData = ((len+1)*2) + 4;      /* this is actually what we want to return */
3260         qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3261         mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3262     }
3263
3264     /* send and free the packets */
3265   done:
3266     lock_ReleaseMutex(&scp->mx);
3267     cm_ReleaseSCache(scp);
3268     cm_ReleaseUser(userp);
3269     smb_ReleaseFID(fidp);
3270     if (code == 0) {
3271         memcpy(outp->datap, &qfi, responseSize);
3272         smb_SendTran2Packet(vcp, outp, opx);
3273     } else {
3274         smb_SendTran2Error(vcp, p, opx, code);
3275     }
3276     smb_FreeTran2Packet(outp);
3277
3278     return 0;
3279 }       
3280
3281 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3282 {
3283     long code = 0;
3284     unsigned short fid;
3285     smb_fid_t *fidp;
3286     unsigned short infoLevel;
3287     smb_tran2Packet_t *outp;
3288     cm_user_t *userp;
3289     cm_scache_t *scp;
3290     cm_req_t req;
3291
3292     cm_InitReq(&req);
3293
3294     fid = p->parmsp[0];
3295     fidp = smb_FindFID(vcp, fid, 0);
3296
3297     if (fidp == NULL) {
3298         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3299         return 0;
3300     }
3301
3302     infoLevel = p->parmsp[1];
3303     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3304     if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3305         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3306                   p->opcode, infoLevel);
3307         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADOP);
3308         smb_ReleaseFID(fidp);
3309         return 0;
3310     }
3311
3312     lock_ObtainMutex(&fidp->mx);
3313     if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && !(fidp->flags & SMB_FID_OPENDELETE)) {
3314         lock_ReleaseMutex(&fidp->mx);
3315         smb_ReleaseFID(fidp);
3316         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3317         return 0;
3318     }
3319     if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO || 
3320          infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3321          && !(fidp->flags & SMB_FID_OPENWRITE)) {
3322         lock_ReleaseMutex(&fidp->mx);
3323         smb_ReleaseFID(fidp);
3324         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3325         return 0;
3326     }
3327
3328     scp = fidp->scp;
3329     cm_HoldSCache(scp);
3330     lock_ReleaseMutex(&fidp->mx);
3331
3332     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3333
3334     outp->totalParms = 2;
3335     outp->totalData = 0;
3336
3337     userp = smb_GetTran2User(vcp, p);
3338     if (!userp) {
3339         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3340         code = CM_ERROR_BADSMB;
3341         goto done;
3342     }   
3343
3344     if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3345         FILETIME lastMod;
3346         unsigned int attribute;
3347         cm_attr_t attr;
3348         smb_tran2QFileInfo_t *sfi;
3349
3350         sfi = (smb_tran2QFileInfo_t *)p->datap;
3351
3352         /* lock the vnode with a callback; we need the current status
3353          * to determine what the new status is, in some cases.
3354          */
3355         lock_ObtainMutex(&scp->mx);
3356         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3357                           CM_SCACHESYNC_GETSTATUS
3358                          | CM_SCACHESYNC_NEEDCALLBACK);
3359         if (code) {
3360             lock_ReleaseMutex(&scp->mx);
3361             goto done;
3362         }
3363
3364         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3365
3366         lock_ReleaseMutex(&scp->mx);
3367         lock_ObtainMutex(&fidp->mx);
3368         lock_ObtainMutex(&scp->mx);
3369
3370         /* prepare for setattr call */
3371         attr.mask = 0;
3372
3373         lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3374         /* when called as result of move a b, lastMod is (-1, -1). 
3375          * If the check for -1 is not present, timestamp
3376          * of the resulting file will be 1969 (-1)
3377          */
3378         if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
3379              lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3380             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3381             smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3382             fidp->flags |= SMB_FID_MTIMESETDONE;
3383         }
3384                 
3385         attribute = sfi->u.QFbasicInfo.attributes;
3386         if (attribute != 0) {
3387             if ((scp->unixModeBits & 0222)
3388                  && (attribute & SMB_ATTR_READONLY) != 0) {
3389                 /* make a writable file read-only */
3390                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3391                 attr.unixModeBits = scp->unixModeBits & ~0222;
3392             }
3393             else if ((scp->unixModeBits & 0222) == 0
3394                       && (attribute & SMB_ATTR_READONLY) == 0) {
3395                 /* make a read-only file writable */
3396                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3397                 attr.unixModeBits = scp->unixModeBits | 0222;
3398             }
3399         }
3400         lock_ReleaseMutex(&scp->mx);
3401         lock_ReleaseMutex(&fidp->mx);
3402
3403         /* call setattr */
3404         if (attr.mask)
3405             code = cm_SetAttr(scp, &attr, userp, &req);
3406         else
3407             code = 0;
3408     }
3409     else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3410         if (*((char *)(p->datap))) {    /* File is Deleted */
3411             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3412                                      &req);
3413             if (code == 0) {
3414                 lock_ObtainMutex(&fidp->mx);
3415                 fidp->flags |= SMB_FID_DELONCLOSE;
3416                 lock_ReleaseMutex(&fidp->mx);
3417             }
3418         }               
3419         else {  
3420             code = 0;
3421             lock_ObtainMutex(&fidp->mx);
3422             fidp->flags &= ~SMB_FID_DELONCLOSE;
3423             lock_ReleaseMutex(&fidp->mx);
3424         }
3425     }       
3426     else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3427              infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3428         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3429         cm_attr_t attr;
3430
3431         attr.mask = CM_ATTRMASK_LENGTH;
3432         attr.length.LowPart = size.LowPart;
3433         attr.length.HighPart = size.HighPart;
3434         code = cm_SetAttr(scp, &attr, userp, &req);
3435     }       
3436
3437   done:
3438     cm_ReleaseSCache(scp);
3439     cm_ReleaseUser(userp);
3440     smb_ReleaseFID(fidp);
3441     if (code == 0) 
3442         smb_SendTran2Packet(vcp, outp, opx);
3443     else 
3444         smb_SendTran2Error(vcp, p, opx, code);
3445     smb_FreeTran2Packet(outp);
3446
3447     return 0;
3448 }
3449
3450 long 
3451 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3452 {
3453     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3454     return CM_ERROR_BADOP;
3455 }
3456
3457 long 
3458 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3459 {
3460     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3461     return CM_ERROR_BADOP;
3462 }
3463
3464 long 
3465 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3466 {
3467     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3468     return CM_ERROR_BADOP;
3469 }
3470
3471 long 
3472 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3473 {
3474     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3475     return CM_ERROR_BADOP;
3476 }
3477
3478 long 
3479 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3480 {
3481     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3482     return CM_ERROR_BADOP;
3483 }
3484
3485 long 
3486 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3487 {
3488     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3489     return CM_ERROR_BADOP;
3490 }
3491
3492 struct smb_v2_referral {
3493     USHORT ServerType;
3494     USHORT ReferralFlags;
3495     ULONG  Proximity;
3496     ULONG  TimeToLive;
3497     USHORT DfsPathOffset;
3498     USHORT DfsAlternativePathOffset;
3499     USHORT NetworkAddressOffset;
3500 };
3501
3502 long 
3503 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3504 {
3505     /* This is a UNICODE only request (bit15 of Flags2) */
3506     /* The TID must be IPC$ */
3507
3508     /* The documentation for the Flags response field is contradictory */
3509
3510     /* Use Version 1 Referral Element Format */
3511     /* ServerType = 0; indicates the next server should be queried for the file */
3512     /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3513     /* Node = UnicodeString of UNC path of the next share name */
3514 #ifdef DFS_SUPPORT
3515     long code = 0;
3516     int maxReferralLevel = 0;
3517     char requestFileName[1024] = "";
3518     smb_tran2Packet_t *outp = 0;
3519     cm_user_t *userp = 0;
3520     cm_req_t req;
3521     CPINFO CodePageInfo;
3522     int i, nbnLen, reqLen;
3523     int idx;
3524
3525     cm_InitReq(&req);
3526
3527     maxReferralLevel = p->parmsp[0];
3528
3529     GetCPInfo(CP_ACP, &CodePageInfo);
3530     WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1, 
3531                         requestFileName, 1024, NULL, NULL);
3532
3533     osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]", 
3534              maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3535
3536     nbnLen = strlen(cm_NetbiosName);
3537     reqLen = strlen(requestFileName);
3538
3539     if (reqLen == nbnLen + 5 &&
3540         requestFileName[0] == '\\' &&
3541         !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3542         requestFileName[nbnLen+1] == '\\' &&
3543         (!_strnicmp("all",&requestFileName[nbnLen+2],3) || 
3544           !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3545     {
3546         USHORT * sp;
3547         struct smb_v2_referral * v2ref;
3548         outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3549
3550         sp = (USHORT *)outp->datap;
3551         idx = 0;
3552         sp[idx++] = reqLen;   /* path consumed */
3553         sp[idx++] = 1;        /* number of referrals */
3554         sp[idx++] = 0x03;     /* flags */
3555 #ifdef DFS_VERSION_1
3556         sp[idx++] = 1;        /* Version Number */
3557         sp[idx++] = reqLen + 4;  /* Referral Size */ 
3558         sp[idx++] = 1;        /* Type = SMB Server */
3559         sp[idx++] = 0;        /* Do not strip path consumed */
3560         for ( i=0;i<=reqLen; i++ )
3561             sp[i+idx] = requestFileName[i];
3562 #else /* DFS_VERSION_2 */
3563         sp[idx++] = 2;      /* Version Number */
3564         sp[idx++] = sizeof(struct smb_v2_referral);     /* Referral Size */
3565         idx += (sizeof(struct smb_v2_referral) / 2);
3566         v2ref = (struct smb_v2_referral *) &sp[5];
3567         v2ref->ServerType = 1;  /* SMB Server */
3568         v2ref->ReferralFlags = 0x03;
3569         v2ref->Proximity = 0;   /* closest */
3570         v2ref->TimeToLive = 3600; /* seconds */
3571         v2ref->DfsPathOffset = idx * 2;
3572         v2ref->DfsAlternativePathOffset = idx * 2;
3573         v2ref->NetworkAddressOffset = 0;
3574         for ( i=0;i<=reqLen; i++ )
3575             sp[i+idx] = requestFileName[i];
3576 #endif
3577     } else {
3578         userp = smb_GetTran2User(vcp, p);
3579         if (!userp) {
3580             osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3581             code = CM_ERROR_BADSMB;
3582             goto done;
3583         }   
3584
3585                 /* not done yet */
3586         code = CM_ERROR_NOSUCHPATH;
3587     }
3588
3589   done:
3590     if (userp)
3591         cm_ReleaseUser(userp);
3592     if (code == 0) 
3593         smb_SendTran2Packet(vcp, outp, op);
3594     else 
3595         smb_SendTran2Error(vcp, p, op, code);
3596     if (outp)
3597         smb_FreeTran2Packet(outp);
3598  
3599     return 0;
3600 #else /* DFS_SUPPORT */
3601     osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED"); 
3602     return CM_ERROR_BADOP;
3603 #endif /* DFS_SUPPORT */
3604 }
3605
3606 long 
3607 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3608 {
3609     /* This is a UNICODE only request (bit15 of Flags2) */
3610
3611     /* There is nothing we can do about this operation.  The client is going to
3612      * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3613      * Unfortunately, there is really nothing we can do about it other then log it 
3614      * somewhere.  Even then I don't think there is anything for us to do.
3615      * So let's return an error value.
3616      */
3617
3618     osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3619     return CM_ERROR_BADOP;
3620 }
3621
3622 long 
3623 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3624         smb_dirListPatch_t **dir