5b9fa9fa05061cee4d17f44cb5bf5ad4e9b07587
[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     DWORD dw;
1502     int nonrootShares;
1503     smb_rap_share_list_t rootShares;
1504     cm_req_t req;
1505     cm_user_t * userp;
1506     osi_hyper_t thyper;
1507
1508     tp = p->parmsp + 1; /* skip over function number (always 0) */
1509     (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over parm descriptor */
1510     (void) smb_ParseString((char *) tp, (char **) &tp); /* skip over data descriptor */
1511     infoLevel = tp[0];
1512     bufsize = tp[1];
1513
1514     if (infoLevel != 1) {
1515         return CM_ERROR_INVAL;
1516     }
1517
1518     /* first figure out how many shares there are */
1519     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1520                       KEY_QUERY_VALUE, &hkParam);
1521     if (rv == ERROR_SUCCESS) {
1522         len = sizeof(allSubmount);
1523         rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1524                              (BYTE *) &allSubmount, &len);
1525         if (rv != ERROR_SUCCESS || allSubmount != 0) {
1526             allSubmount = 1;
1527         }
1528         RegCloseKey (hkParam);
1529     }
1530
1531     rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1532                       0, KEY_QUERY_VALUE, &hkSubmount);
1533     if (rv == ERROR_SUCCESS) {
1534         rv = RegQueryInfoKey(hkSubmount, NULL, NULL, NULL, NULL,
1535                              NULL, NULL, &nRegShares, NULL, NULL, NULL, NULL);
1536         if (rv != ERROR_SUCCESS)
1537             nRegShares = 0;
1538     } else {
1539         hkSubmount = NULL;
1540     }
1541
1542     /* fetch the root shares */
1543     rootShares.maxShares = SMB_RAP_MAX_SHARES;
1544     rootShares.cShare = 0;
1545     rootShares.shares = malloc( sizeof(smb_rap_share_info_0_t) * SMB_RAP_MAX_SHARES );
1546
1547     cm_InitReq(&req);
1548
1549     userp = smb_GetTran2User(vcp,p);
1550
1551     thyper.HighPart = 0;
1552     thyper.LowPart = 0;
1553
1554     cm_HoldSCache(cm_data.rootSCachep);
1555     cm_ApplyDir(cm_data.rootSCachep, smb_rapCollectSharesProc, &rootShares, &thyper, userp, &req, NULL);
1556     cm_ReleaseSCache(cm_data.rootSCachep);
1557
1558     cm_ReleaseUser(userp);
1559
1560     nShares = (USHORT)(rootShares.cShare + nRegShares + allSubmount);
1561
1562 #define REMARK_LEN 1
1563     outParmsTotal = 8; /* 4 dwords */
1564     outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nShares ;
1565     if(outDataTotal > bufsize) {
1566         nSharesRet = bufsize / (sizeof(smb_rap_share_info_1_t) + REMARK_LEN);
1567         outDataTotal = (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet;
1568     }
1569     else {
1570         nSharesRet = nShares;
1571     }
1572     
1573     outp = smb_GetTran2ResponsePacket(vcp, p, op, outParmsTotal, outDataTotal);
1574
1575     /* now for the submounts */
1576     shares = (smb_rap_share_info_1_t *) outp->datap;
1577     cstrp = outp->datap + sizeof(smb_rap_share_info_1_t) * nSharesRet;
1578
1579     memset(outp->datap, 0, (sizeof(smb_rap_share_info_1_t) + REMARK_LEN) * nSharesRet);
1580
1581     if (allSubmount) {
1582         strcpy( shares[cshare].shi1_netname, "all" );
1583         shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1584         /* type and pad are zero already */
1585         cshare++;
1586         cstrp+=REMARK_LEN;
1587     }
1588
1589     if (hkSubmount) {
1590         for (dw=0; dw < nRegShares && cshare < nSharesRet; dw++) {
1591             len = sizeof(thisShare);
1592             rv = RegEnumValue(hkSubmount, dw, thisShare, &len, NULL, NULL, NULL, NULL);
1593             if (rv == ERROR_SUCCESS && strlen(thisShare) && (!allSubmount || stricmp(thisShare,"all"))) {
1594                 strncpy(shares[cshare].shi1_netname, thisShare, sizeof(shares->shi1_netname)-1);
1595                 shares[cshare].shi1_netname[sizeof(shares->shi1_netname)-1] = 0; /* unfortunate truncation */
1596                 shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1597                 cshare++;
1598                 cstrp+=REMARK_LEN;
1599             }
1600             else
1601                 nShares--; /* uncount key */
1602         }
1603
1604         RegCloseKey(hkSubmount);
1605     }
1606
1607     nonrootShares = cshare;
1608
1609     for (i=0; i < rootShares.cShare && cshare < nSharesRet; i++) {
1610         /* in case there are collisions with submounts, submounts have higher priority */               
1611         for (j=0; j < nonrootShares; j++)
1612             if (!stricmp(shares[j].shi1_netname, rootShares.shares[i].shi0_netname))
1613                 break;
1614                 
1615         if (j < nonrootShares) {
1616             nShares--; /* uncount */
1617             continue;
1618         }
1619
1620         strcpy(shares[cshare].shi1_netname, rootShares.shares[i].shi0_netname);
1621         shares[cshare].shi1_remark = (DWORD)(cstrp - outp->datap);
1622         cshare++;
1623         cstrp+=REMARK_LEN;
1624     }
1625
1626     outp->parmsp[0] = ((cshare == nShares)? ERROR_SUCCESS : ERROR_MORE_DATA);
1627     outp->parmsp[1] = 0;
1628     outp->parmsp[2] = cshare;
1629     outp->parmsp[3] = nShares;
1630
1631     outp->totalData = (int)(cstrp - outp->datap);
1632     outp->totalParms = outParmsTotal;
1633
1634     smb_SendTran2Packet(vcp, outp, op);
1635     smb_FreeTran2Packet(outp);
1636
1637     free(rootShares.shares);
1638
1639     return code;
1640 }
1641
1642 long smb_ReceiveRAPNetShareGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1643 {
1644     smb_tran2Packet_t *outp;
1645     unsigned short * tp;
1646     char * shareName;
1647     BOOL shareFound = FALSE;
1648     unsigned short infoLevel;
1649     unsigned short bufsize;
1650     int totalData;
1651     int totalParam;
1652     DWORD len;
1653     HKEY hkParam;
1654     HKEY hkSubmount;
1655     DWORD allSubmount;
1656     LONG rv;
1657     long code = 0;
1658
1659     tp = p->parmsp + 1; /* skip over function number (always 1) */
1660     (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over param descriptor */
1661     (void) smb_ParseString( (char *) tp, (char **) &tp); /* skip over data descriptor */
1662     shareName = smb_ParseString( (char *) tp, (char **) &tp);
1663     infoLevel = *tp++;
1664     bufsize = *tp++;
1665     
1666     totalParam = 6;
1667
1668     if (infoLevel == 0)
1669         totalData = sizeof(smb_rap_share_info_0_t);
1670     else if(infoLevel == SMB_INFO_STANDARD)
1671         totalData = sizeof(smb_rap_share_info_1_t) + 1; /* + empty string */
1672     else if(infoLevel == SMB_INFO_QUERY_EA_SIZE)
1673         totalData = sizeof(smb_rap_share_info_2_t) + 2; /* + two empty strings */
1674     else
1675         return CM_ERROR_INVAL;
1676
1677     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParam, totalData);
1678
1679     if(!stricmp(shareName,"all") || !strcmp(shareName,"*.")) {
1680         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0,
1681                           KEY_QUERY_VALUE, &hkParam);
1682         if (rv == ERROR_SUCCESS) {
1683             len = sizeof(allSubmount);
1684             rv = RegQueryValueEx(hkParam, "AllSubmount", NULL, NULL,
1685                                   (BYTE *) &allSubmount, &len);
1686             if (rv != ERROR_SUCCESS || allSubmount != 0) {
1687                 allSubmount = 1;
1688             }
1689             RegCloseKey (hkParam);
1690         }
1691
1692         if (allSubmount)
1693             shareFound = TRUE;
1694
1695     } else {
1696         rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY "\\Submounts", 0,
1697                           KEY_QUERY_VALUE, &hkSubmount);
1698         if (rv == ERROR_SUCCESS) {
1699             rv = RegQueryValueEx(hkSubmount, shareName, NULL, NULL, NULL, NULL);
1700             if (rv == ERROR_SUCCESS) {
1701                 shareFound = TRUE;
1702             }
1703             RegCloseKey(hkSubmount);
1704         }
1705     }
1706
1707     if (!shareFound) {
1708         smb_FreeTran2Packet(outp);
1709         return CM_ERROR_BADSHARENAME;
1710     }
1711
1712     memset(outp->datap, 0, totalData);
1713
1714     outp->parmsp[0] = 0;
1715     outp->parmsp[1] = 0;
1716     outp->parmsp[2] = totalData;
1717
1718     if (infoLevel == 0) {
1719         smb_rap_share_info_0_t * info = (smb_rap_share_info_0_t *) outp->datap;
1720         strncpy(info->shi0_netname, shareName, sizeof(info->shi0_netname)-1);
1721         info->shi0_netname[sizeof(info->shi0_netname)-1] = 0;
1722     } else if(infoLevel == SMB_INFO_STANDARD) {
1723         smb_rap_share_info_1_t * info = (smb_rap_share_info_1_t *) outp->datap;
1724         strncpy(info->shi1_netname, shareName, sizeof(info->shi1_netname)-1);
1725         info->shi1_netname[sizeof(info->shi1_netname)-1] = 0;
1726         info->shi1_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1727         /* type and pad are already zero */
1728     } else { /* infoLevel==2 */
1729         smb_rap_share_info_2_t * info = (smb_rap_share_info_2_t *) outp->datap;
1730         strncpy(info->shi2_netname, shareName, sizeof(info->shi2_netname)-1);
1731         info->shi2_netname[sizeof(info->shi2_netname)-1] = 0;
1732         info->shi2_remark = (DWORD)(((unsigned char *) (info + 1)) - outp->datap);
1733         info->shi2_permissions = ACCESS_ALL;
1734         info->shi2_max_uses = (unsigned short) -1;
1735         info->shi2_path = (DWORD)(1 + (((unsigned char *) (info + 1)) - outp->datap));
1736     }
1737
1738     outp->totalData = totalData;
1739     outp->totalParms = totalParam;
1740
1741     smb_SendTran2Packet(vcp, outp, op);
1742     smb_FreeTran2Packet(outp);
1743
1744     return code;
1745 }
1746
1747 typedef struct smb_rap_wksta_info_10 {
1748     DWORD       wki10_computername;     /*char *wki10_computername;*/
1749     DWORD       wki10_username; /* char *wki10_username; */
1750     DWORD       wki10_langroup; /* char *wki10_langroup;*/
1751     unsigned char       wki10_ver_major;
1752     unsigned char       wki10_ver_minor;
1753     DWORD       wki10_logon_domain;     /*char *wki10_logon_domain;*/
1754     DWORD       wki10_oth_domains; /* char *wki10_oth_domains;*/
1755 } smb_rap_wksta_info_10_t;
1756
1757
1758 long smb_ReceiveRAPNetWkstaGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1759 {
1760     smb_tran2Packet_t *outp;
1761     long code = 0;
1762     int infoLevel;
1763     int bufsize;
1764     unsigned short * tp;
1765     int totalData;
1766     int totalParams;
1767     smb_rap_wksta_info_10_t * info;
1768     char * cstrp;
1769     smb_user_t *uidp;
1770
1771     tp = p->parmsp + 1; /* Skip over function number */
1772     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1773     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1774     infoLevel = *tp++;
1775     bufsize = *tp++;
1776
1777     if (infoLevel != 10) {
1778         return CM_ERROR_INVAL;
1779     }
1780
1781     totalParams = 6;
1782         
1783     /* infolevel 10 */
1784     totalData = sizeof(*info) +         /* info */
1785         MAX_COMPUTERNAME_LENGTH +       /* wki10_computername */
1786         SMB_MAX_USERNAME_LENGTH +       /* wki10_username */
1787         MAX_COMPUTERNAME_LENGTH +       /* wki10_langroup */
1788         MAX_COMPUTERNAME_LENGTH +       /* wki10_logon_domain */
1789         1;                              /* wki10_oth_domains (null)*/
1790
1791     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1792
1793     memset(outp->parmsp,0,totalParams);
1794     memset(outp->datap,0,totalData);
1795
1796     info = (smb_rap_wksta_info_10_t *) outp->datap;
1797     cstrp = (char *) (info + 1);
1798
1799     info->wki10_computername = (DWORD) (cstrp - outp->datap);
1800     strcpy(cstrp, smb_localNamep);
1801     cstrp += strlen(cstrp) + 1;
1802
1803     info->wki10_username = (DWORD) (cstrp - outp->datap);
1804     uidp = smb_FindUID(vcp, p->uid, 0);
1805     if (uidp) {
1806         lock_ObtainMutex(&uidp->mx);
1807         if(uidp->unp && uidp->unp->name)
1808             strcpy(cstrp, uidp->unp->name);
1809         lock_ReleaseMutex(&uidp->mx);
1810         smb_ReleaseUID(uidp);
1811     }
1812     cstrp += strlen(cstrp) + 1;
1813
1814     info->wki10_langroup = (DWORD) (cstrp - outp->datap);
1815     strcpy(cstrp, "WORKGROUP");
1816     cstrp += strlen(cstrp) + 1;
1817
1818     /* TODO: Not sure what values these should take, but these work */
1819     info->wki10_ver_major = 5;
1820     info->wki10_ver_minor = 1;
1821
1822     info->wki10_logon_domain = (DWORD) (cstrp - outp->datap);
1823     strcpy(cstrp, smb_ServerDomainName);
1824     cstrp += strlen(cstrp) + 1;
1825
1826     info->wki10_oth_domains = (DWORD) (cstrp - outp->datap);
1827     cstrp ++; /* no other domains */
1828
1829     outp->totalData = (unsigned short) (cstrp - outp->datap); /* actual data size */
1830     outp->parmsp[2] = outp->totalData;
1831     outp->totalParms = totalParams;
1832
1833     smb_SendTran2Packet(vcp,outp,op);
1834     smb_FreeTran2Packet(outp);
1835
1836     return code;
1837 }
1838
1839 typedef struct smb_rap_server_info_0 {
1840     char    sv0_name[16];
1841 } smb_rap_server_info_0_t;
1842
1843 typedef struct smb_rap_server_info_1 {
1844     char            sv1_name[16];
1845     char            sv1_version_major;
1846     char            sv1_version_minor;
1847     unsigned long   sv1_type;
1848     DWORD           *sv1_comment_or_master_browser; /* char *sv1_comment_or_master_browser;*/
1849 } smb_rap_server_info_1_t;
1850
1851 char smb_ServerComment[] = "OpenAFS Client";
1852 int smb_ServerCommentLen = sizeof(smb_ServerComment);
1853
1854 #define SMB_SV_TYPE_SERVER              0x00000002L
1855 #define SMB_SV_TYPE_NT              0x00001000L
1856 #define SMB_SV_TYPE_SERVER_NT       0x00008000L
1857
1858 long smb_ReceiveRAPNetServerGetInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
1859 {
1860     smb_tran2Packet_t *outp;
1861     long code = 0;
1862     int infoLevel;
1863     int bufsize;
1864     unsigned short * tp;
1865     int totalData;
1866     int totalParams;
1867     smb_rap_server_info_0_t * info0;
1868     smb_rap_server_info_1_t * info1;
1869     char * cstrp;
1870
1871     tp = p->parmsp + 1; /* Skip over function number */
1872     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over param descriptor */
1873     (void) smb_ParseString((unsigned char*) tp, (char **) &tp); /* skip over data descriptor */
1874     infoLevel = *tp++;
1875     bufsize = *tp++;
1876
1877     if (infoLevel != 0 && infoLevel != 1) {
1878         return CM_ERROR_INVAL;
1879     }
1880
1881     totalParams = 6;
1882
1883     totalData = 
1884         (infoLevel == 0) ? sizeof(smb_rap_server_info_0_t)
1885         : (sizeof(smb_rap_server_info_1_t) + smb_ServerCommentLen);
1886
1887     outp = smb_GetTran2ResponsePacket(vcp, p, op, totalParams, totalData);
1888
1889     memset(outp->parmsp,0,totalParams);
1890     memset(outp->datap,0,totalData);
1891
1892     if (infoLevel == 0) {
1893         info0 = (smb_rap_server_info_0_t *) outp->datap;
1894         cstrp = (char *) (info0 + 1);
1895         strcpy(info0->sv0_name, "AFS");
1896     } else { /* infoLevel == SMB_INFO_STANDARD */
1897         info1 = (smb_rap_server_info_1_t *) outp->datap;
1898         cstrp = (char *) (info1 + 1);
1899         strcpy(info1->sv1_name, "AFS");
1900
1901         info1->sv1_type = 
1902             SMB_SV_TYPE_SERVER |
1903             SMB_SV_TYPE_NT |
1904             SMB_SV_TYPE_SERVER_NT;
1905
1906         info1->sv1_version_major = 5;
1907         info1->sv1_version_minor = 1;
1908         info1->sv1_comment_or_master_browser = (DWORD *) (cstrp - outp->datap);
1909
1910         strcpy(cstrp, smb_ServerComment);
1911
1912         cstrp += smb_ServerCommentLen;
1913     }
1914
1915     totalData = (DWORD)(cstrp - outp->datap);
1916     outp->totalData = min(bufsize,totalData); /* actual data size */
1917     outp->parmsp[0] = (outp->totalData == totalData)? 0 : ERROR_MORE_DATA;
1918     outp->parmsp[2] = totalData;
1919     outp->totalParms = totalParams;
1920
1921     smb_SendTran2Packet(vcp,outp,op);
1922     smb_FreeTran2Packet(outp);
1923
1924     return code;
1925 }
1926
1927 long smb_ReceiveV3Tran2A(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1928 {
1929     smb_tran2Packet_t *asp;
1930     int totalParms;
1931     int totalData;
1932     int parmDisp;
1933     int dataDisp;
1934     int parmOffset;
1935     int dataOffset;
1936     int parmCount;
1937     int dataCount;
1938     int firstPacket;
1939     long code = 0;
1940
1941     /* We sometimes see 0 word count.  What to do? */
1942     if (*inp->wctp == 0) {
1943         osi_Log0(smb_logp, "Transaction2 word count = 0"); 
1944         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_ZERO_TRANSACTION_COUNT);
1945
1946         smb_SetSMBDataLength(outp, 0);
1947         smb_SendPacket(vcp, outp);
1948         return 0;
1949     }
1950
1951     totalParms = smb_GetSMBParm(inp, 0);
1952     totalData = smb_GetSMBParm(inp, 1);
1953         
1954     firstPacket = (inp->inCom == 0x32);
1955         
1956     /* find the packet we're reassembling */
1957     lock_ObtainWrite(&smb_globalLock);
1958     asp = smb_FindTran2Packet(vcp, inp);
1959     if (!asp) {
1960         asp = smb_NewTran2Packet(vcp, inp, totalParms, totalData);
1961     }
1962     lock_ReleaseWrite(&smb_globalLock);
1963         
1964     /* now merge in this latest packet; start by looking up offsets */
1965     if (firstPacket) {
1966         parmDisp = dataDisp = 0;
1967         parmOffset = smb_GetSMBParm(inp, 10);
1968         dataOffset = smb_GetSMBParm(inp, 12);
1969         parmCount = smb_GetSMBParm(inp, 9);
1970         dataCount = smb_GetSMBParm(inp, 11);
1971         asp->maxReturnParms = smb_GetSMBParm(inp, 2);
1972         asp->maxReturnData = smb_GetSMBParm(inp, 3);
1973
1974         osi_Log3(smb_logp, "SMB3 received T2 init packet total data %d, cur data %d, max return data %d",
1975                  totalData, dataCount, asp->maxReturnData);
1976     }
1977     else {
1978         parmDisp = smb_GetSMBParm(inp, 4);
1979         parmOffset = smb_GetSMBParm(inp, 3);
1980         dataDisp = smb_GetSMBParm(inp, 7);
1981         dataOffset = smb_GetSMBParm(inp, 6);
1982         parmCount = smb_GetSMBParm(inp, 2);
1983         dataCount = smb_GetSMBParm(inp, 5);
1984
1985         osi_Log2(smb_logp, "SMB3 received T2 aux packet parms %d, data %d",
1986                  parmCount, dataCount);
1987     }   
1988
1989     /* now copy the parms and data */
1990     if ( asp->totalParms > 0 && parmCount != 0 )
1991     {
1992         memcpy(((char *)asp->parmsp) + parmDisp, inp->data + parmOffset, parmCount);
1993     }
1994     if ( asp->totalData > 0 && dataCount != 0 ) {
1995         memcpy(asp->datap + dataDisp, inp->data + dataOffset, dataCount);
1996     }
1997
1998     /* account for new bytes */
1999     asp->curData += dataCount;
2000     asp->curParms += parmCount;
2001
2002     /* finally, if we're done, remove the packet from the queue and dispatch it */
2003     if (asp->totalParms > 0 &&
2004         asp->curParms > 0 &&
2005         asp->totalData <= asp->curData &&
2006         asp->totalParms <= asp->curParms) {
2007         /* we've received it all */
2008         lock_ObtainWrite(&smb_globalLock);
2009         osi_QRemove((osi_queue_t **) &smb_tran2AssemblyQueuep, &asp->q);
2010         lock_ReleaseWrite(&smb_globalLock);
2011
2012         /* now dispatch it */
2013         if ( asp->opcode >= 0 && asp->opcode < 20 && smb_tran2DispatchTable[asp->opcode].procp) {
2014             osi_Log4(smb_logp,"AFS Server - Dispatch-2 %s vcp[%p] lana[%d] lsn[%d]",myCrt_2Dispatch(asp->opcode),vcp,vcp->lana,vcp->lsn);
2015             code = (*smb_tran2DispatchTable[asp->opcode].procp)(vcp, asp, outp);
2016         }
2017         else {
2018             osi_Log4(smb_logp,"AFS Server - Dispatch-2 [INVALID] op[%x] vcp[%p] lana[%d] lsn[%d]", asp->opcode, vcp, vcp->lana, vcp->lsn);
2019             code = CM_ERROR_BADOP;
2020         }
2021
2022         /* if an error is returned, we're supposed to send an error packet,
2023          * otherwise the dispatched function already did the data sending.
2024          * We give dispatched proc the responsibility since it knows how much
2025          * space to allocate.
2026          */
2027         if (code != 0) {
2028             smb_SendTran2Error(vcp, asp, outp, code);
2029         }
2030
2031         /* free the input tran 2 packet */
2032         smb_FreeTran2Packet(asp);
2033     }
2034     else if (firstPacket) {
2035         /* the first packet in a multi-packet request, we need to send an
2036          * ack to get more data.
2037          */
2038         smb_SetSMBDataLength(outp, 0);
2039         smb_SendPacket(vcp, outp);
2040     }
2041
2042     return 0;
2043 }
2044
2045 long smb_ReceiveTran2Open(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2046 {
2047     char *pathp;
2048     smb_tran2Packet_t *outp;
2049     long code = 0;
2050     cm_space_t *spacep;
2051     int excl;
2052     cm_user_t *userp;
2053     cm_scache_t *dscp;          /* dir we're dealing with */
2054     cm_scache_t *scp;           /* file we're creating */
2055     cm_attr_t setAttr;
2056     int initialModeBits;
2057     smb_fid_t *fidp;
2058     int attributes;
2059     char *lastNamep;
2060     afs_uint32 dosTime;
2061     int openFun;
2062     int trunc;
2063     int openMode;
2064     int extraInfo;
2065     int openAction;
2066     int parmSlot;                       /* which parm we're dealing with */
2067     long returnEALength;
2068     char *tidPathp;
2069     cm_req_t req;
2070     int created = 0;
2071
2072     cm_InitReq(&req);
2073
2074     scp = NULL;
2075         
2076     extraInfo = (p->parmsp[0] & 1);     /* return extra info */
2077     returnEALength = (p->parmsp[0] & 8);        /* return extended attr length */
2078
2079     openFun = p->parmsp[6];             /* open function */
2080     excl = ((openFun & 3) == 0);
2081     trunc = ((openFun & 3) == 2);       /* truncate it */
2082     openMode = (p->parmsp[1] & 0x7);
2083     openAction = 0;                     /* tracks what we did */
2084
2085     attributes = p->parmsp[3];
2086     dosTime = p->parmsp[4] | (p->parmsp[5] << 16);
2087         
2088     /* compute initial mode bits based on read-only flag in attributes */
2089     initialModeBits = 0666;
2090     if (attributes & SMB_ATTR_READONLY) 
2091         initialModeBits &= ~0222;
2092         
2093     pathp = (char *) (&p->parmsp[14]);
2094     if (smb_StoreAnsiFilenames)
2095         OemToChar(pathp,pathp);
2096     
2097     outp = smb_GetTran2ResponsePacket(vcp, p, op, 40, 0);
2098
2099     spacep = cm_GetSpace();
2100     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2101
2102     if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
2103         /* special case magic file name for receiving IOCTL requests
2104          * (since IOCTL calls themselves aren't getting through).
2105          */
2106         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2107         smb_SetupIoctlFid(fidp, spacep);
2108
2109         /* copy out remainder of the parms */
2110         parmSlot = 0;
2111         outp->parmsp[parmSlot++] = fidp->fid;
2112         if (extraInfo) {
2113             outp->parmsp[parmSlot++] = 0;       /* attrs */
2114             outp->parmsp[parmSlot++] = 0;       /* mod time */
2115             outp->parmsp[parmSlot++] = 0; 
2116             outp->parmsp[parmSlot++] = 0;       /* len */
2117             outp->parmsp[parmSlot++] = 0x7fff;
2118             outp->parmsp[parmSlot++] = openMode;
2119             outp->parmsp[parmSlot++] = 0;       /* file type 0 ==> normal file or dir */
2120             outp->parmsp[parmSlot++] = 0;       /* IPC junk */
2121         }   
2122         /* and the final "always present" stuff */
2123         outp->parmsp[parmSlot++] = 1;           /* openAction found existing file */
2124         /* next write out the "unique" ID */
2125         outp->parmsp[parmSlot++] = 0x1234;
2126         outp->parmsp[parmSlot++] = 0x5678;
2127         outp->parmsp[parmSlot++] = 0;
2128         if (returnEALength) {
2129             outp->parmsp[parmSlot++] = 0;
2130             outp->parmsp[parmSlot++] = 0;
2131         }       
2132                 
2133         outp->totalData = 0;
2134         outp->totalParms = parmSlot * 2;
2135                 
2136         smb_SendTran2Packet(vcp, outp, op);
2137                 
2138         smb_FreeTran2Packet(outp);
2139
2140         /* and clean up fid reference */
2141         smb_ReleaseFID(fidp);
2142         return 0;
2143     }
2144
2145 #ifdef DEBUG_VERBOSE
2146     {
2147         char *hexp, *asciip;
2148         asciip = (lastNamep ? lastNamep : pathp);
2149         hexp = osi_HexifyString( asciip );
2150         DEBUG_EVENT2("AFS","T2Open H[%s] A[%s]", hexp, asciip);
2151         free(hexp);
2152     }       
2153 #endif
2154
2155     userp = smb_GetTran2User(vcp, p);
2156     /* In the off chance that userp is NULL, we log and abandon */
2157     if (!userp) {
2158         osi_Log1(smb_logp, "ReceiveTran2Open user [%d] not resolvable", p->uid);
2159         smb_FreeTran2Packet(outp);
2160         return CM_ERROR_BADSMB;
2161     }
2162
2163     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2164     if (code == CM_ERROR_TIDIPC) {
2165         /* Attempt to use a TID allocated for IPC.  The client
2166          * is probably looking for DCE RPC end points which we
2167          * don't support OR it could be looking to make a DFS
2168          * referral request. 
2169          */
2170         osi_Log0(smb_logp, "Tran2Open received IPC TID");
2171 #ifndef DFS_SUPPORT
2172         cm_ReleaseUser(userp);
2173         smb_FreeTran2Packet(outp);
2174         return CM_ERROR_NOSUCHPATH;
2175 #endif
2176     }
2177
2178     dscp = NULL;
2179     code = cm_NameI(cm_data.rootSCachep, pathp,
2180                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2181                      userp, tidPathp, &req, &scp);
2182     if (code != 0) {
2183         code = cm_NameI(cm_data.rootSCachep, spacep->data,
2184                          CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD,
2185                          userp, tidPathp, &req, &dscp);
2186         cm_FreeSpace(spacep);
2187
2188         if (code) {
2189             cm_ReleaseUser(userp);
2190             smb_FreeTran2Packet(outp);
2191             return code;
2192         }
2193         
2194 #ifdef DFS_SUPPORT
2195         if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2196             cm_ReleaseSCache(dscp);
2197             cm_ReleaseUser(userp);
2198             smb_FreeTran2Packet(outp);
2199             if ( WANTS_DFS_PATHNAMES(p) )
2200                 return CM_ERROR_PATH_NOT_COVERED;
2201             else
2202                 return CM_ERROR_BADSHARENAME;
2203         }
2204 #endif /* DFS_SUPPORT */
2205
2206         /* otherwise, scp points to the parent directory.  Do a lookup,
2207          * and truncate the file if we find it, otherwise we create the
2208          * file.
2209          */
2210         if (!lastNamep) 
2211             lastNamep = pathp;
2212         else 
2213             lastNamep++;
2214         code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD, userp,
2215                          &req, &scp);
2216         if (code && code != CM_ERROR_NOSUCHFILE) {
2217             cm_ReleaseSCache(dscp);
2218             cm_ReleaseUser(userp);
2219             smb_FreeTran2Packet(outp);
2220             return code;
2221         }
2222     } else {
2223 #ifdef DFS_SUPPORT
2224         if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2225             cm_ReleaseSCache(scp);
2226             cm_ReleaseUser(userp);
2227             smb_FreeTran2Packet(outp);
2228             if ( WANTS_DFS_PATHNAMES(p) )
2229                 return CM_ERROR_PATH_NOT_COVERED;
2230             else
2231                 return CM_ERROR_BADSHARENAME;
2232         }
2233 #endif /* DFS_SUPPORT */
2234
2235         /* macintosh is expensive to program for it */
2236         cm_FreeSpace(spacep);
2237     }
2238         
2239     /* if we get here, if code is 0, the file exists and is represented by
2240      * scp.  Otherwise, we have to create it.
2241      */
2242     if (code == 0) {
2243         code = cm_CheckOpen(scp, openMode, trunc, userp, &req);
2244         if (code) {
2245             if (dscp) 
2246                 cm_ReleaseSCache(dscp);
2247             cm_ReleaseSCache(scp);
2248             cm_ReleaseUser(userp);
2249             smb_FreeTran2Packet(outp);
2250             return code;
2251         }
2252
2253         if (excl) {
2254             /* oops, file shouldn't be there */
2255             if (dscp) 
2256                 cm_ReleaseSCache(dscp);
2257             cm_ReleaseSCache(scp);
2258             cm_ReleaseUser(userp);
2259             smb_FreeTran2Packet(outp);
2260             return CM_ERROR_EXISTS;
2261         }
2262
2263         if (trunc) {
2264             setAttr.mask = CM_ATTRMASK_LENGTH;
2265             setAttr.length.LowPart = 0;
2266             setAttr.length.HighPart = 0;
2267             code = cm_SetAttr(scp, &setAttr, userp, &req);
2268             openAction = 3;     /* truncated existing file */
2269         }   
2270         else 
2271             openAction = 1;     /* found existing file */
2272     }
2273     else if (!(openFun & 0x10)) {
2274         /* don't create if not found */
2275         if (dscp) 
2276             cm_ReleaseSCache(dscp);
2277         osi_assert(scp == NULL);
2278         cm_ReleaseUser(userp);
2279         smb_FreeTran2Packet(outp);
2280         return CM_ERROR_NOSUCHFILE;
2281     }
2282     else {
2283         osi_assert(dscp != NULL && scp == NULL);
2284         openAction = 2; /* created file */
2285         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
2286         smb_UnixTimeFromSearchTime(&setAttr.clientModTime, dosTime);
2287         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
2288                           &req);
2289         if (code == 0) {
2290             created = 1;
2291             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
2292                 smb_NotifyChange(FILE_ACTION_ADDED,
2293                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,  
2294                                   dscp, lastNamep, NULL, TRUE);
2295         } else if (!excl && code == CM_ERROR_EXISTS) {
2296             /* not an exclusive create, and someone else tried
2297              * creating it already, then we open it anyway.  We
2298              * don't bother retrying after this, since if this next
2299              * fails, that means that the file was deleted after we
2300              * started this call.
2301              */
2302             code = cm_Lookup(dscp, lastNamep, CM_FLAG_CASEFOLD,
2303                               userp, &req, &scp);
2304             if (code == 0) {
2305                 if (trunc) {
2306                     setAttr.mask = CM_ATTRMASK_LENGTH;
2307                     setAttr.length.LowPart = 0;
2308                     setAttr.length.HighPart = 0;
2309                     code = cm_SetAttr(scp, &setAttr, userp,
2310                                        &req);
2311                 }   
2312             }   /* lookup succeeded */
2313         }
2314     }
2315         
2316     /* we don't need this any longer */
2317     if (dscp) 
2318         cm_ReleaseSCache(dscp);
2319
2320     if (code) {
2321         /* something went wrong creating or truncating the file */
2322         if (scp) 
2323             cm_ReleaseSCache(scp);
2324         cm_ReleaseUser(userp);
2325         smb_FreeTran2Packet(outp);
2326         return code;
2327     }
2328         
2329     /* make sure we're about to open a file */
2330     if (scp->fileType != CM_SCACHETYPE_FILE) {
2331         code = 0;
2332         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
2333             cm_scache_t * targetScp = 0;
2334             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, &req);
2335             if (code == 0) {
2336                 /* we have a more accurate file to use (the
2337                  * target of the symbolic link).  Otherwise,
2338                  * we'll just use the symlink anyway.
2339                  */
2340                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
2341                           scp, targetScp);
2342                 cm_ReleaseSCache(scp);
2343                 scp = targetScp;
2344             }
2345         }
2346         if (scp->fileType != CM_SCACHETYPE_FILE) {
2347             cm_ReleaseSCache(scp);
2348             cm_ReleaseUser(userp);
2349             smb_FreeTran2Packet(outp);
2350             return CM_ERROR_ISDIR;
2351         }
2352     }
2353
2354     /* now all we have to do is open the file itself */
2355     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
2356     osi_assert(fidp);
2357         
2358     cm_HoldUser(userp);
2359     lock_ObtainMutex(&fidp->mx);
2360     /* save a pointer to the vnode */
2361     osi_Log2(smb_logp,"smb_ReceiveTran2Open fidp 0x%p scp 0x%p", fidp, scp);
2362     fidp->scp = scp;
2363     lock_ObtainMutex(&scp->mx);
2364     scp->flags |= CM_SCACHEFLAG_SMB_FID;
2365     lock_ReleaseMutex(&scp->mx);
2366     
2367     /* and the user */
2368     fidp->userp = userp;
2369         
2370     /* compute open mode */
2371     if (openMode != 1) 
2372         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
2373     if (openMode == 1 || openMode == 2)
2374         fidp->flags |= SMB_FID_OPENWRITE;
2375
2376     /* remember that the file was newly created */
2377     if (created)
2378         fidp->flags |= SMB_FID_CREATED;
2379
2380     lock_ReleaseMutex(&fidp->mx);
2381
2382     smb_ReleaseFID(fidp);
2383         
2384     cm_Open(scp, 0, userp);
2385
2386     /* copy out remainder of the parms */
2387     parmSlot = 0;
2388     outp->parmsp[parmSlot++] = fidp->fid;
2389     lock_ObtainMutex(&scp->mx);
2390     if (extraInfo) {
2391         outp->parmsp[parmSlot++] = smb_Attributes(scp);
2392         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2393         outp->parmsp[parmSlot++] = (unsigned short)(dosTime & 0xffff);
2394         outp->parmsp[parmSlot++] = (unsigned short)((dosTime>>16) & 0xffff);
2395         outp->parmsp[parmSlot++] = (unsigned short) (scp->length.LowPart & 0xffff);
2396         outp->parmsp[parmSlot++] = (unsigned short) ((scp->length.LowPart >> 16) & 0xffff);
2397         outp->parmsp[parmSlot++] = openMode;
2398         outp->parmsp[parmSlot++] = 0;   /* file type 0 ==> normal file or dir */
2399         outp->parmsp[parmSlot++] = 0;   /* IPC junk */
2400     }   
2401     /* and the final "always present" stuff */
2402     outp->parmsp[parmSlot++] = openAction;
2403     /* next write out the "unique" ID */
2404     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.vnode & 0xffff); 
2405     outp->parmsp[parmSlot++] = (unsigned short) (scp->fid.volume & 0xffff); 
2406     outp->parmsp[parmSlot++] = 0; 
2407     if (returnEALength) {
2408         outp->parmsp[parmSlot++] = 0; 
2409         outp->parmsp[parmSlot++] = 0; 
2410     }   
2411     lock_ReleaseMutex(&scp->mx);
2412     outp->totalData = 0;                /* total # of data bytes */
2413     outp->totalParms = parmSlot * 2;    /* shorts are two bytes */
2414
2415     smb_SendTran2Packet(vcp, outp, op);
2416
2417     smb_FreeTran2Packet(outp);
2418
2419     cm_ReleaseUser(userp);
2420     /* leave scp held since we put it in fidp->scp */
2421     return 0;
2422 }   
2423
2424 long smb_ReceiveTran2QFSInfoFid(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2425 {
2426     unsigned short fid;
2427     unsigned short infolevel;
2428
2429     infolevel = p->parmsp[0];
2430     fid = p->parmsp[1];
2431     osi_Log2(smb_logp, "T2 QFSInfoFid InfoLevel 0x%x fid 0x%x - NOT_SUPPORTED", infolevel, fid);
2432     
2433     return CM_ERROR_BAD_LEVEL;
2434 }
2435
2436 long smb_ReceiveTran2QFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
2437 {
2438     smb_tran2Packet_t *outp;
2439     smb_tran2QFSInfo_t qi;
2440     int responseSize;
2441     static char FSname[8] = {'A', 0, 'F', 0, 'S', 0, 0, 0};
2442         
2443     osi_Log1(smb_logp, "T2 QFSInfo type 0x%x", p->parmsp[0]);
2444
2445     switch (p->parmsp[0]) {
2446     case SMB_INFO_ALLOCATION: 
2447         responseSize = sizeof(qi.u.allocInfo); 
2448         break;
2449     case SMB_INFO_VOLUME: 
2450         responseSize = sizeof(qi.u.volumeInfo); 
2451         break;
2452     case SMB_QUERY_FS_VOLUME_INFO: 
2453         responseSize = sizeof(qi.u.FSvolumeInfo); 
2454         break;
2455     case SMB_QUERY_FS_SIZE_INFO: 
2456         responseSize = sizeof(qi.u.FSsizeInfo); 
2457         break;
2458     case SMB_QUERY_FS_DEVICE_INFO: 
2459         responseSize = sizeof(qi.u.FSdeviceInfo); 
2460         break;
2461     case SMB_QUERY_FS_ATTRIBUTE_INFO: 
2462         responseSize = sizeof(qi.u.FSattributeInfo); 
2463         break;
2464     case SMB_INFO_UNIX:         /* CIFS Unix Info */
2465     case SMB_INFO_MACOS:        /* Mac FS Info */
2466     default: 
2467         return CM_ERROR_BADOP;
2468     }
2469
2470     outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, responseSize);
2471     switch (p->parmsp[0]) {
2472     case SMB_INFO_ALLOCATION: 
2473         /* alloc info */
2474         qi.u.allocInfo.FSID = 0;
2475         qi.u.allocInfo.sectorsPerAllocUnit = 1;
2476         qi.u.allocInfo.totalAllocUnits = 0x7fffffff;
2477         qi.u.allocInfo.availAllocUnits = 0x3fffffff;
2478         qi.u.allocInfo.bytesPerSector = 1024;
2479         break;
2480
2481     case SMB_INFO_VOLUME: 
2482         /* volume info */
2483         qi.u.volumeInfo.vsn = 1234;
2484         qi.u.volumeInfo.vnCount = 4;
2485         /* we're supposed to pad it out with zeroes to the end */
2486         memset(&qi.u.volumeInfo.label, 0, sizeof(qi.u.volumeInfo.label));
2487         memcpy(qi.u.volumeInfo.label, "AFS", 4);
2488         break;
2489
2490     case SMB_QUERY_FS_VOLUME_INFO: 
2491         /* FS volume info */
2492         memset((char *)&qi.u.FSvolumeInfo.vct, 0, 4);
2493         qi.u.FSvolumeInfo.vsn = 1234;
2494         qi.u.FSvolumeInfo.vnCount = 8;
2495         memcpy(qi.u.FSvolumeInfo.label, "A\0F\0S\0\0\0", 8);
2496         break;
2497
2498     case SMB_QUERY_FS_SIZE_INFO: 
2499         /* FS size info */
2500         qi.u.FSsizeInfo.totalAllocUnits.HighPart = 0;
2501         qi.u.FSsizeInfo.totalAllocUnits.LowPart= 0x7fffffff;
2502         qi.u.FSsizeInfo.availAllocUnits.HighPart = 0;
2503         qi.u.FSsizeInfo.availAllocUnits.LowPart= 0x3fffffff;
2504         qi.u.FSsizeInfo.sectorsPerAllocUnit = 1;
2505         qi.u.FSsizeInfo.bytesPerSector = 1024;
2506         break;
2507
2508     case SMB_QUERY_FS_DEVICE_INFO: 
2509         /* FS device info */
2510         qi.u.FSdeviceInfo.devType = 0x14; /* network file system */
2511         qi.u.FSdeviceInfo.characteristics = 0x50; /* remote, virtual */
2512         break;
2513
2514     case SMB_QUERY_FS_ATTRIBUTE_INFO: 
2515         /* FS attribute info */
2516         /* attributes, defined in WINNT.H:
2517          *      FILE_CASE_SENSITIVE_SEARCH      0x1
2518          *      FILE_CASE_PRESERVED_NAMES       0x2
2519          *      FILE_VOLUME_QUOTAS              0x10
2520          *      <no name defined>               0x4000
2521          *         If bit 0x4000 is not set, Windows 95 thinks
2522          *         we can't handle long (non-8.3) names,
2523          *         despite our protestations to the contrary.
2524          */
2525         qi.u.FSattributeInfo.attributes = 0x4003;
2526         qi.u.FSattributeInfo.maxCompLength = MAX_PATH;
2527         qi.u.FSattributeInfo.FSnameLength = sizeof(FSname);
2528         memcpy(qi.u.FSattributeInfo.FSname, FSname, sizeof(FSname));
2529         break;
2530     }   
2531         
2532     /* copy out return data, and set corresponding sizes */
2533     outp->totalParms = 0;
2534     outp->totalData = responseSize;
2535     memcpy(outp->datap, &qi, responseSize);
2536
2537     /* send and free the packets */
2538     smb_SendTran2Packet(vcp, outp, op);
2539     smb_FreeTran2Packet(outp);
2540
2541     return 0;
2542 }
2543
2544 long smb_ReceiveTran2SetFSInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
2545 {
2546     osi_Log0(smb_logp,"ReceiveTran2SetFSInfo - NOT_SUPPORTED");
2547     return CM_ERROR_BADOP;
2548 }
2549
2550 struct smb_ShortNameRock {
2551     char *maskp;
2552     unsigned int vnode;
2553     char *shortName;
2554     size_t shortNameLen;
2555 };      
2556
2557 int cm_GetShortNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *vrockp,
2558                          osi_hyper_t *offp)
2559 {       
2560     struct smb_ShortNameRock *rockp;
2561     char *shortNameEnd;
2562
2563     rockp = vrockp;
2564     /* compare both names and vnodes, though probably just comparing vnodes
2565      * would be safe enough.
2566      */
2567     if (cm_stricmp(dep->name, rockp->maskp) != 0)
2568         return 0;
2569     if (ntohl(dep->fid.vnode) != rockp->vnode)
2570         return 0;
2571     /* This is the entry */
2572     cm_Gen8Dot3Name(dep, rockp->shortName, &shortNameEnd);
2573     rockp->shortNameLen = shortNameEnd - rockp->shortName;
2574     return CM_ERROR_STOPNOW;
2575 }       
2576
2577 long cm_GetShortName(char *pathp, cm_user_t *userp, cm_req_t *reqp,
2578         char *tidPathp, int vnode, char *shortName, size_t *shortNameLenp)
2579 {
2580     struct smb_ShortNameRock rock;
2581     char *lastNamep;
2582     cm_space_t *spacep;
2583     cm_scache_t *dscp;
2584     int caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
2585     long code = 0;
2586     osi_hyper_t thyper;
2587
2588     spacep = cm_GetSpace();
2589     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
2590
2591     code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
2592                      reqp, &dscp);
2593     cm_FreeSpace(spacep);
2594     if (code) 
2595         return code;
2596
2597 #ifdef DFS_SUPPORT
2598     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2599         cm_ReleaseSCache(dscp);
2600         cm_ReleaseUser(userp);
2601         return CM_ERROR_PATH_NOT_COVERED;
2602     }
2603 #endif /* DFS_SUPPORT */
2604
2605     if (!lastNamep) lastNamep = pathp;
2606     else lastNamep++;
2607     thyper.LowPart = 0;
2608     thyper.HighPart = 0;
2609     rock.shortName = shortName;
2610     rock.vnode = vnode;
2611     rock.maskp = lastNamep;
2612     code = cm_ApplyDir(dscp, cm_GetShortNameProc, &rock, &thyper, userp, reqp, NULL);
2613
2614     cm_ReleaseSCache(dscp);
2615
2616     if (code == 0)
2617         return CM_ERROR_NOSUCHFILE;
2618     if (code == CM_ERROR_STOPNOW) {
2619         *shortNameLenp = rock.shortNameLen;
2620         return 0;
2621     }
2622     return code;
2623 }
2624
2625 long smb_ReceiveTran2QPathInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
2626 {
2627     smb_tran2Packet_t *outp;
2628     afs_uint32 dosTime;
2629     FILETIME ft;
2630     unsigned short infoLevel;
2631     smb_tran2QPathInfo_t qpi;
2632     int responseSize;
2633     unsigned short attributes;
2634     unsigned long extAttributes;
2635     char shortName[13];
2636     unsigned int len;
2637     cm_user_t *userp;
2638     cm_space_t *spacep;
2639     cm_scache_t *scp, *dscp;
2640     int scp_mx_held = 0;
2641     int delonclose = 0;
2642     long code = 0;
2643     char *pathp;
2644     char *tidPathp;
2645     char *lastComp;
2646     cm_req_t req;
2647
2648     cm_InitReq(&req);
2649
2650     infoLevel = p->parmsp[0];
2651     if (infoLevel == SMB_INFO_IS_NAME_VALID) 
2652         responseSize = 0;
2653     else if (infoLevel == SMB_INFO_STANDARD) 
2654         responseSize = sizeof(qpi.u.QPstandardInfo);
2655     else if (infoLevel == SMB_INFO_QUERY_EA_SIZE) 
2656         responseSize = sizeof(qpi.u.QPeaSizeInfo);
2657     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO)
2658         responseSize = sizeof(qpi.u.QPfileBasicInfo);
2659     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO)
2660         responseSize = sizeof(qpi.u.QPfileStandardInfo);
2661     else if (infoLevel == SMB_QUERY_FILE_EA_INFO)
2662         responseSize = sizeof(qpi.u.QPfileEaInfo);
2663     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) 
2664         responseSize = sizeof(qpi.u.QPfileNameInfo);
2665     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) 
2666         responseSize = sizeof(qpi.u.QPfileAllInfo);
2667     else if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) 
2668         responseSize = sizeof(qpi.u.QPfileAltNameInfo);
2669     else {
2670         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
2671                   p->opcode, infoLevel);
2672         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
2673         return 0;
2674     }
2675
2676     pathp = (char *)(&p->parmsp[3]);
2677     if (smb_StoreAnsiFilenames)
2678         OemToChar(pathp,pathp);
2679     osi_Log2(smb_logp, "T2 QPathInfo type 0x%x path %s", infoLevel,
2680               osi_LogSaveString(smb_logp, pathp));
2681
2682     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, responseSize);
2683
2684     if (infoLevel > 0x100)
2685         outp->totalParms = 2;
2686     else
2687         outp->totalParms = 0;
2688     outp->totalData = responseSize;
2689         
2690     /* now, if we're at infoLevel 6, we're only being asked to check
2691      * the syntax, so we just OK things now.  In particular, we're *not*
2692      * being asked to verify anything about the state of any parent dirs.
2693      */
2694     if (infoLevel == SMB_INFO_IS_NAME_VALID) {
2695         smb_SendTran2Packet(vcp, outp, opx);
2696         smb_FreeTran2Packet(outp);
2697         return 0;
2698     }   
2699         
2700     userp = smb_GetTran2User(vcp, p);
2701     if (!userp) {
2702         osi_Log1(smb_logp, "ReceiveTran2QPathInfo unable to resolve user [%d]", p->uid);
2703         smb_FreeTran2Packet(outp);
2704         return CM_ERROR_BADSMB;
2705     }
2706
2707     code = smb_LookupTIDPath(vcp, p->tid, &tidPathp);
2708     if(code) {
2709         cm_ReleaseUser(userp);
2710         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOSUCHPATH);
2711         smb_FreeTran2Packet(outp);
2712         return 0;
2713     }
2714
2715     /*
2716      * XXX Strange hack XXX
2717      *
2718      * As of Patch 7 (13 January 98), we are having the following problem:
2719      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2720      * requests to look up "desktop.ini" in all the subdirectories.
2721      * This can cause zillions of timeouts looking up non-existent cells
2722      * and volumes, especially in the top-level directory.
2723      *
2724      * We have not found any way to avoid this or work around it except
2725      * to explicitly ignore the requests for mount points that haven't
2726      * yet been evaluated and for directories that haven't yet been
2727      * fetched.
2728      */
2729     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2730         spacep = cm_GetSpace();
2731         smb_StripLastComponent(spacep->data, &lastComp, pathp);
2732 #ifndef SPECIAL_FOLDERS
2733         /* Make sure that lastComp is not NULL */
2734         if (lastComp) {
2735             if (stricmp(lastComp, "\\desktop.ini") == 0) {
2736                 code = cm_NameI(cm_data.rootSCachep, spacep->data,
2737                                  CM_FLAG_CASEFOLD
2738                                  | CM_FLAG_DIRSEARCH
2739                                  | CM_FLAG_FOLLOW,
2740                                  userp, tidPathp, &req, &dscp);
2741                 if (code == 0) {
2742 #ifdef DFS_SUPPORT
2743                     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
2744                         if ( WANTS_DFS_PATHNAMES(p) )
2745                             code = CM_ERROR_PATH_NOT_COVERED;
2746                         else
2747                             code = CM_ERROR_BADSHARENAME;
2748                     } else
2749 #endif /* DFS_SUPPORT */
2750                     if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
2751                         code = CM_ERROR_NOSUCHFILE;
2752                     else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2753                         cm_buf_t *bp = buf_Find(dscp, &hzero);
2754                         if (bp)
2755                             buf_Release(bp);
2756                         else
2757                             code = CM_ERROR_NOSUCHFILE;
2758                     }
2759                     cm_ReleaseSCache(dscp);
2760                     if (code) {
2761                         cm_FreeSpace(spacep);
2762                         cm_ReleaseUser(userp);
2763                         smb_SendTran2Error(vcp, p, opx, code);
2764                         smb_FreeTran2Packet(outp);
2765                         return 0;
2766                     }
2767                 }
2768             }
2769         }
2770 #endif /* SPECIAL_FOLDERS */
2771
2772         cm_FreeSpace(spacep);
2773     }
2774
2775     /* now do namei and stat, and copy out the info */
2776     code = cm_NameI(cm_data.rootSCachep, pathp,
2777                      CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD, userp, tidPathp, &req, &scp);
2778
2779     if (code) {
2780         cm_ReleaseUser(userp);
2781         smb_SendTran2Error(vcp, p, opx, code);
2782         smb_FreeTran2Packet(outp);
2783         return 0;
2784     }
2785
2786 #ifdef DFS_SUPPORT
2787     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
2788         cm_ReleaseSCache(scp);
2789         cm_ReleaseUser(userp);
2790         if ( WANTS_DFS_PATHNAMES(p) )
2791             code = CM_ERROR_PATH_NOT_COVERED;
2792         else
2793             code = CM_ERROR_BADSHARENAME;
2794         smb_SendTran2Error(vcp, p, opx, code);
2795         smb_FreeTran2Packet(outp);
2796         return 0;
2797     }
2798 #endif /* DFS_SUPPORT */
2799
2800     lock_ObtainMutex(&scp->mx);
2801     scp_mx_held = 1;
2802     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2803                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2804     if (code) goto done;
2805
2806     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2807         
2808     /* now we have the status in the cache entry, and everything is locked.
2809      * Marshall the output data.
2810      */
2811     /* for info level 108, figure out short name */
2812     if (infoLevel == SMB_QUERY_FILE_ALT_NAME_INFO) {
2813         code = cm_GetShortName(pathp, userp, &req,
2814                                 tidPathp, scp->fid.vnode, shortName,
2815                                 (size_t *) &len);
2816         if (code) {
2817             goto done;
2818         }
2819
2820         qpi.u.QPfileAltNameInfo.fileNameLength = (len + 1) * 2;
2821         mbstowcs((unsigned short *)qpi.u.QPfileAltNameInfo.fileName, shortName, len + 1);
2822
2823         goto done;
2824     }
2825     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
2826         len = strlen(lastComp);
2827         qpi.u.QPfileNameInfo.fileNameLength = (len + 1) * 2;
2828         mbstowcs((unsigned short *)qpi.u.QPfileNameInfo.fileName, lastComp, len + 1);
2829
2830         goto done;
2831     }
2832     else if (infoLevel == SMB_INFO_STANDARD || infoLevel == SMB_INFO_QUERY_EA_SIZE) {
2833         smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2834         qpi.u.QPstandardInfo.creationDateTime = dosTime;
2835         qpi.u.QPstandardInfo.lastAccessDateTime = dosTime;
2836         qpi.u.QPstandardInfo.lastWriteDateTime = dosTime;
2837         qpi.u.QPstandardInfo.dataSize = scp->length.LowPart;
2838         qpi.u.QPstandardInfo.allocationSize = scp->length.LowPart;
2839         attributes = smb_Attributes(scp);
2840         qpi.u.QPstandardInfo.attributes = attributes;
2841         qpi.u.QPstandardInfo.eaSize = 0;
2842     }
2843     else if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
2844         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2845         qpi.u.QPfileBasicInfo.creationTime = ft;
2846         qpi.u.QPfileBasicInfo.lastAccessTime = ft;
2847         qpi.u.QPfileBasicInfo.lastWriteTime = ft;
2848         qpi.u.QPfileBasicInfo.changeTime = ft;
2849         extAttributes = smb_ExtAttributes(scp);
2850         qpi.u.QPfileBasicInfo.attributes = extAttributes;
2851         qpi.u.QPfileBasicInfo.reserved = 0;
2852     }
2853     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
2854         smb_fid_t *fidp = smb_FindFIDByScache(vcp, scp);
2855
2856         qpi.u.QPfileStandardInfo.allocationSize = scp->length;
2857         qpi.u.QPfileStandardInfo.endOfFile = scp->length;
2858         qpi.u.QPfileStandardInfo.numberOfLinks = scp->linkCount;
2859         qpi.u.QPfileStandardInfo.directory = 
2860             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2861               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2862               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2863         qpi.u.QPfileStandardInfo.reserved = 0;
2864
2865         if (fidp) {
2866             lock_ReleaseMutex(&scp->mx);
2867             scp_mx_held = 0;
2868             lock_ObtainMutex(&fidp->mx);
2869             delonclose = fidp->flags & SMB_FID_DELONCLOSE;
2870             lock_ReleaseMutex(&fidp->mx);
2871             smb_ReleaseFID(fidp);
2872         }
2873         qpi.u.QPfileStandardInfo.deletePending = (delonclose ? 1 : 0);
2874     }
2875     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
2876         qpi.u.QPfileEaInfo.eaSize = 0;
2877     }
2878     else if (infoLevel == SMB_QUERY_FILE_ALL_INFO) {
2879         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
2880         qpi.u.QPfileAllInfo.creationTime = ft;
2881         qpi.u.QPfileAllInfo.lastAccessTime = ft;
2882         qpi.u.QPfileAllInfo.lastWriteTime = ft;
2883         qpi.u.QPfileAllInfo.changeTime = ft;
2884         extAttributes = smb_ExtAttributes(scp);
2885         qpi.u.QPfileAllInfo.attributes = extAttributes;
2886         qpi.u.QPfileAllInfo.allocationSize = scp->length;
2887         qpi.u.QPfileAllInfo.endOfFile = scp->length;
2888         qpi.u.QPfileAllInfo.numberOfLinks = scp->linkCount;
2889         qpi.u.QPfileAllInfo.deletePending = 0;
2890         qpi.u.QPfileAllInfo.directory = 
2891             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2892               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
2893               scp->fileType == CM_SCACHETYPE_INVALID) ? 1 : 0);
2894         qpi.u.QPfileAllInfo.indexNumber.HighPart = scp->fid.cell;
2895         qpi.u.QPfileAllInfo.indexNumber.LowPart  = scp->fid.volume;
2896         qpi.u.QPfileAllInfo.eaSize = 0;
2897         qpi.u.QPfileAllInfo.accessFlags = 0;
2898         qpi.u.QPfileAllInfo.indexNumber2.HighPart = scp->fid.vnode;
2899         qpi.u.QPfileAllInfo.indexNumber2.LowPart  = scp->fid.unique;
2900         qpi.u.QPfileAllInfo.currentByteOffset.HighPart = 0;
2901         qpi.u.QPfileAllInfo.currentByteOffset.LowPart = 0;
2902         qpi.u.QPfileAllInfo.mode = 0;
2903         qpi.u.QPfileAllInfo.alignmentRequirement = 0;
2904         len = strlen(lastComp);
2905         qpi.u.QPfileAllInfo.fileNameLength = (len + 1) * 2;
2906         mbstowcs((unsigned short *)qpi.u.QPfileAllInfo.fileName, lastComp, len + 1);
2907     }
2908
2909     /* send and free the packets */
2910   done:
2911     if (scp_mx_held)
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_BAD_LEVEL);
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_ReleaseSCache(scp);
3054         cm_ReleaseUser(userp);
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         cm_ReleaseSCache(scp);
3063         smb_ReleaseFID(fidp);
3064         cm_ReleaseUser(userp);
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_BAD_LEVEL);
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     osi_Log2(smb_logp,"smb_ReleaseTran2QFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3212     cm_HoldSCache(scp);
3213     lock_ReleaseMutex(&fidp->mx);
3214     lock_ObtainMutex(&scp->mx);
3215     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3216                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3217     if (code) 
3218         goto done;
3219
3220     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3221
3222     /* now we have the status in the cache entry, and everything is locked.
3223      * Marshall the output data.
3224      */
3225     if (infoLevel == SMB_QUERY_FILE_BASIC_INFO) {
3226         smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3227         qfi.u.QFbasicInfo.creationTime = ft;
3228         qfi.u.QFbasicInfo.lastAccessTime = ft;
3229         qfi.u.QFbasicInfo.lastWriteTime = ft;
3230         qfi.u.QFbasicInfo.lastChangeTime = ft;
3231         attributes = smb_ExtAttributes(scp);
3232         qfi.u.QFbasicInfo.attributes = attributes;
3233     }
3234     else if (infoLevel == SMB_QUERY_FILE_STANDARD_INFO) {
3235         qfi.u.QFstandardInfo.allocationSize = scp->length;
3236         qfi.u.QFstandardInfo.endOfFile = scp->length;
3237         qfi.u.QFstandardInfo.numberOfLinks = scp->linkCount;
3238         qfi.u.QFstandardInfo.deletePending = (delonclose ? 1 : 0);
3239         qfi.u.QFstandardInfo.directory = 
3240             ((scp->fileType == CM_SCACHETYPE_DIRECTORY ||
3241               scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
3242               scp->fileType == CM_SCACHETYPE_INVALID)? 1 : 0);
3243     }
3244     else if (infoLevel == SMB_QUERY_FILE_EA_INFO) {
3245         qfi.u.QFeaInfo.eaSize = 0;
3246     }
3247     else if (infoLevel == SMB_QUERY_FILE_NAME_INFO) {
3248         unsigned long len;
3249         char *name;
3250
3251         lock_ReleaseMutex(&scp->mx);
3252         lock_ObtainMutex(&fidp->mx);
3253         lock_ObtainMutex(&scp->mx);
3254         if (fidp->NTopen_wholepathp)
3255             name = fidp->NTopen_wholepathp;
3256         else
3257             name = "\\";        /* probably can't happen */
3258         lock_ReleaseMutex(&fidp->mx);
3259         len = (unsigned long)strlen(name);
3260         outp->totalData = ((len+1)*2) + 4;      /* this is actually what we want to return */
3261         qfi.u.QFfileNameInfo.fileNameLength = (len + 1) * 2;
3262         mbstowcs((unsigned short *)qfi.u.QFfileNameInfo.fileName, name, len + 1);
3263     }
3264
3265     /* send and free the packets */
3266   done:
3267     lock_ReleaseMutex(&scp->mx);
3268     cm_ReleaseSCache(scp);
3269     cm_ReleaseUser(userp);
3270     smb_ReleaseFID(fidp);
3271     if (code == 0) {
3272         memcpy(outp->datap, &qfi, responseSize);
3273         smb_SendTran2Packet(vcp, outp, opx);
3274     } else {
3275         smb_SendTran2Error(vcp, p, opx, code);
3276     }
3277     smb_FreeTran2Packet(outp);
3278
3279     return 0;
3280 }       
3281
3282 long smb_ReceiveTran2SetFileInfo(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
3283 {
3284     long code = 0;
3285     unsigned short fid;
3286     smb_fid_t *fidp;
3287     unsigned short infoLevel;
3288     smb_tran2Packet_t *outp;
3289     cm_user_t *userp = NULL;
3290     cm_scache_t *scp = NULL;
3291     cm_req_t req;
3292
3293     cm_InitReq(&req);
3294
3295     fid = p->parmsp[0];
3296     fidp = smb_FindFID(vcp, fid, 0);
3297
3298     if (fidp == NULL) {
3299         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BADFD);
3300         return 0;
3301     }
3302
3303     infoLevel = p->parmsp[1];
3304     osi_Log2(smb_logp,"ReceiveTran2SetFileInfo type 0x%x fid %d", infoLevel, fid);
3305     if (infoLevel > SMB_SET_FILE_END_OF_FILE_INFO || infoLevel < SMB_SET_FILE_BASIC_INFO) {
3306         osi_Log2(smb_logp, "Bad Tran2 op 0x%x infolevel 0x%x",
3307                   p->opcode, infoLevel);
3308         smb_SendTran2Error(vcp, p, opx, CM_ERROR_BAD_LEVEL);
3309         smb_ReleaseFID(fidp);
3310         return 0;
3311     }
3312
3313     lock_ObtainMutex(&fidp->mx);
3314     if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO && 
3315         !(fidp->flags & SMB_FID_OPENDELETE)) {
3316         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENDELETE fidp 0x%p scp 0x%p fidp->flags 0x%x", 
3317                   fidp, fidp->scp, fidp->flags);
3318         lock_ReleaseMutex(&fidp->mx);
3319         smb_ReleaseFID(fidp);
3320         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3321         return 0;
3322     }
3323     if ((infoLevel == SMB_SET_FILE_ALLOCATION_INFO || 
3324          infoLevel == SMB_SET_FILE_END_OF_FILE_INFO)
3325          && !(fidp->flags & SMB_FID_OPENWRITE)) {
3326         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo !SMB_FID_OPENWRITE fidp 0x%p scp 0x%p fidp->flags 0x%x", 
3327                   fidp, fidp->scp, fidp->flags);
3328         lock_ReleaseMutex(&fidp->mx);
3329         smb_ReleaseFID(fidp);
3330         smb_SendTran2Error(vcp, p, opx, CM_ERROR_NOACCESS);
3331         return 0;
3332     }
3333
3334     scp = fidp->scp;
3335     osi_Log2(smb_logp,"smb_ReceiveTran2SetFileInfo fidp 0x%p scp 0x%p", fidp, scp);
3336     cm_HoldSCache(scp);
3337     lock_ReleaseMutex(&fidp->mx);
3338
3339     outp = smb_GetTran2ResponsePacket(vcp, p, opx, 2, 0);
3340
3341     outp->totalParms = 2;
3342     outp->totalData = 0;
3343
3344     userp = smb_GetTran2User(vcp, p);
3345     if (!userp) {
3346         osi_Log1(smb_logp,"ReceiveTran2SetFileInfo unable to resolve user [%d]", p->uid);
3347         code = CM_ERROR_BADSMB;
3348         goto done;
3349     }   
3350
3351     if (infoLevel == SMB_SET_FILE_BASIC_INFO) {
3352         FILETIME lastMod;
3353         unsigned int attribute;
3354         cm_attr_t attr;
3355         smb_tran2QFileInfo_t *sfi;
3356
3357         sfi = (smb_tran2QFileInfo_t *)p->datap;
3358
3359         /* lock the vnode with a callback; we need the current status
3360          * to determine what the new status is, in some cases.
3361          */
3362         lock_ObtainMutex(&scp->mx);
3363         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3364                           CM_SCACHESYNC_GETSTATUS
3365                          | CM_SCACHESYNC_NEEDCALLBACK);
3366         if (code) {
3367             lock_ReleaseMutex(&scp->mx);
3368             goto done;
3369         }
3370
3371         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3372
3373         lock_ReleaseMutex(&scp->mx);
3374         lock_ObtainMutex(&fidp->mx);
3375         lock_ObtainMutex(&scp->mx);
3376
3377         /* prepare for setattr call */
3378         attr.mask = 0;
3379
3380         lastMod = sfi->u.QFbasicInfo.lastWriteTime;
3381         /* when called as result of move a b, lastMod is (-1, -1). 
3382          * If the check for -1 is not present, timestamp
3383          * of the resulting file will be 1969 (-1)
3384          */
3385         if (LargeIntegerNotEqualToZero(*((LARGE_INTEGER *)&lastMod)) && 
3386              lastMod.dwLowDateTime != -1 && lastMod.dwHighDateTime != -1) {
3387             attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3388             smb_UnixTimeFromLargeSearchTime(&attr.clientModTime, &lastMod);
3389             fidp->flags |= SMB_FID_MTIMESETDONE;
3390         }
3391                 
3392         attribute = sfi->u.QFbasicInfo.attributes;
3393         if (attribute != 0) {
3394             if ((scp->unixModeBits & 0222)
3395                  && (attribute & SMB_ATTR_READONLY) != 0) {
3396                 /* make a writable file read-only */
3397                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3398                 attr.unixModeBits = scp->unixModeBits & ~0222;
3399             }
3400             else if ((scp->unixModeBits & 0222) == 0
3401                       && (attribute & SMB_ATTR_READONLY) == 0) {
3402                 /* make a read-only file writable */
3403                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3404                 attr.unixModeBits = scp->unixModeBits | 0222;
3405             }
3406         }
3407         lock_ReleaseMutex(&scp->mx);
3408         lock_ReleaseMutex(&fidp->mx);
3409
3410         /* call setattr */
3411         if (attr.mask)
3412             code = cm_SetAttr(scp, &attr, userp, &req);
3413         else
3414             code = 0;
3415     }
3416     else if (infoLevel == SMB_SET_FILE_DISPOSITION_INFO) {
3417         int delflag = *((char *)(p->datap));
3418         osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo Delete? %d fidp 0x%p scp 0x%p", 
3419                  delflag, fidp, scp);
3420         if (*((char *)(p->datap))) {    /* File is Deleted */
3421             code = cm_CheckNTDelete(fidp->NTopen_dscp, scp, userp,
3422                                      &req);
3423             if (code == 0) {
3424                 lock_ObtainMutex(&fidp->mx);
3425                 fidp->flags |= SMB_FID_DELONCLOSE;
3426                 lock_ReleaseMutex(&fidp->mx);
3427             } else {
3428                 osi_Log3(smb_logp,"smb_ReceiveTran2SetFileInfo CheckNTDelete fidp 0x%p scp 0x%p code 0x%x", 
3429                          fidp, scp, code);
3430             }
3431         }               
3432         else {  
3433             code = 0;
3434             lock_ObtainMutex(&fidp->mx);
3435             fidp->flags &= ~SMB_FID_DELONCLOSE;
3436             lock_ReleaseMutex(&fidp->mx);
3437         }
3438     }       
3439     else if (infoLevel == SMB_SET_FILE_ALLOCATION_INFO ||
3440              infoLevel == SMB_SET_FILE_END_OF_FILE_INFO) {
3441         LARGE_INTEGER size = *((LARGE_INTEGER *)(p->datap));
3442         cm_attr_t attr;
3443
3444         attr.mask = CM_ATTRMASK_LENGTH;
3445         attr.length.LowPart = size.LowPart;
3446         attr.length.HighPart = size.HighPart;
3447         code = cm_SetAttr(scp, &attr, userp, &req);
3448     }       
3449
3450   done:
3451     cm_ReleaseSCache(scp);
3452     cm_ReleaseUser(userp);
3453     smb_ReleaseFID(fidp);
3454     if (code == 0) 
3455         smb_SendTran2Packet(vcp, outp, opx);
3456     else 
3457         smb_SendTran2Error(vcp, p, opx, code);
3458     smb_FreeTran2Packet(outp);
3459
3460     return 0;
3461 }
3462
3463 long 
3464 smb_ReceiveTran2FSCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3465 {
3466     osi_Log0(smb_logp,"ReceiveTran2FSCTL - NOT_SUPPORTED");
3467     return CM_ERROR_BADOP;
3468 }
3469
3470 long 
3471 smb_ReceiveTran2IOCTL(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3472 {
3473     osi_Log0(smb_logp,"ReceiveTran2IOCTL - NOT_SUPPORTED");
3474     return CM_ERROR_BADOP;
3475 }
3476
3477 long 
3478 smb_ReceiveTran2FindNotifyFirst(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3479 {
3480     osi_Log0(smb_logp,"ReceiveTran2FindNotifyFirst - NOT_SUPPORTED");
3481     return CM_ERROR_BADOP;
3482 }
3483
3484 long 
3485 smb_ReceiveTran2FindNotifyNext(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3486 {
3487     osi_Log0(smb_logp,"ReceiveTran2FindNotifyNext - NOT_SUPPORTED");
3488     return CM_ERROR_BADOP;
3489 }
3490
3491 long 
3492 smb_ReceiveTran2CreateDirectory(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3493 {
3494     osi_Log0(smb_logp,"ReceiveTran2CreateDirectory - NOT_SUPPORTED");
3495     return CM_ERROR_BADOP;
3496 }
3497
3498 long 
3499 smb_ReceiveTran2SessionSetup(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3500 {
3501     osi_Log0(smb_logp,"ReceiveTran2SessionSetup - NOT_SUPPORTED");
3502     return CM_ERROR_BADOP;
3503 }
3504
3505 struct smb_v2_referral {
3506     USHORT ServerType;
3507     USHORT ReferralFlags;
3508     ULONG  Proximity;
3509     ULONG  TimeToLive;
3510     USHORT DfsPathOffset;
3511     USHORT DfsAlternativePathOffset;
3512     USHORT NetworkAddressOffset;
3513 };
3514
3515 long 
3516 smb_ReceiveTran2GetDFSReferral(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *op)
3517 {
3518     /* This is a UNICODE only request (bit15 of Flags2) */
3519     /* The TID must be IPC$ */
3520
3521     /* The documentation for the Flags response field is contradictory */
3522
3523     /* Use Version 1 Referral Element Format */
3524     /* ServerType = 0; indicates the next server should be queried for the file */
3525     /* ReferralFlags = 0x01; PathConsumed characters should be stripped */
3526     /* Node = UnicodeString of UNC path of the next share name */
3527 #ifdef DFS_SUPPORT
3528     long code = 0;
3529     int maxReferralLevel = 0;
3530     char requestFileName[1024] = "";
3531     smb_tran2Packet_t *outp = 0;
3532     cm_user_t *userp = 0;
3533     cm_req_t req;
3534     CPINFO CodePageInfo;
3535     int i, nbnLen, reqLen;
3536     int idx;
3537
3538     cm_InitReq(&req);
3539
3540     maxReferralLevel = p->parmsp[0];
3541
3542     GetCPInfo(CP_ACP, &CodePageInfo);
3543     WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) &p->parmsp[1], -1, 
3544                         requestFileName, 1024, NULL, NULL);
3545
3546     osi_Log2(smb_logp,"ReceiveTran2GetDfsReferral [%d][%s]", 
3547              maxReferralLevel, osi_LogSaveString(smb_logp, requestFileName));
3548
3549     nbnLen = strlen(cm_NetbiosName);
3550     reqLen = strlen(requestFileName);
3551
3552     if (reqLen == nbnLen + 5 &&
3553         requestFileName[0] == '\\' &&
3554         !_strnicmp(cm_NetbiosName,&requestFileName[1],nbnLen) &&
3555         requestFileName[nbnLen+1] == '\\' &&
3556         (!_strnicmp("all",&requestFileName[nbnLen+2],3) || 
3557           !_strnicmp("*.",&requestFileName[nbnLen+2],2)))
3558     {
3559         USHORT * sp;
3560         struct smb_v2_referral * v2ref;
3561         outp = smb_GetTran2ResponsePacket(vcp, p, op, 0, 2 * (reqLen + 8));
3562
3563         sp = (USHORT *)outp->datap;
3564         idx = 0;
3565         sp[idx++] = reqLen;   /* path consumed */
3566         sp[idx++] = 1;        /* number of referrals */
3567         sp[idx++] = 0x03;     /* flags */
3568 #ifdef DFS_VERSION_1
3569         sp[idx++] = 1;        /* Version Number */
3570         sp[idx++] = reqLen + 4;  /* Referral Size */ 
3571         sp[idx++] = 1;        /* Type = SMB Server */
3572         sp[idx++] = 0;        /* Do not strip path consumed */
3573         for ( i=0;i<=reqLen; i++ )
3574             sp[i+idx] = requestFileName[i];
3575 #else /* DFS_VERSION_2 */
3576         sp[idx++] = 2;      /* Version Number */
3577         sp[idx++] = sizeof(struct smb_v2_referral);     /* Referral Size */
3578         idx += (sizeof(struct smb_v2_referral) / 2);
3579         v2ref = (struct smb_v2_referral *) &sp[5];
3580         v2ref->ServerType = 1;  /* SMB Server */
3581         v2ref->ReferralFlags = 0x03;
3582         v2ref->Proximity = 0;   /* closest */
3583         v2ref->TimeToLive = 3600; /* seconds */
3584         v2ref->DfsPathOffset = idx * 2;
3585         v2ref->DfsAlternativePathOffset = idx * 2;
3586         v2ref->NetworkAddressOffset = 0;
3587         for ( i=0;i<=reqLen; i++ )
3588             sp[i+idx] = requestFileName[i];
3589 #endif
3590     } else {
3591         userp = smb_GetTran2User(vcp, p);
3592         if (!userp) {
3593             osi_Log1(smb_logp,"ReceiveTran2GetDfsReferral unable to resolve user [%d]", p->uid);
3594             code = CM_ERROR_BADSMB;
3595             goto done;
3596         }   
3597
3598                 /* not done yet */
3599         code = CM_ERROR_NOSUCHPATH;
3600     }
3601
3602   done:
3603     if (userp)
3604         cm_ReleaseUser(userp);
3605     if (code == 0) 
3606         smb_SendTran2Packet(vcp, outp, op);
3607     else 
3608         smb_SendTran2Error(vcp, p, op, code);
3609     if (outp)
3610         smb_FreeTran2Packet(outp);
3611  
3612     return 0;
3613 #else /* DFS_SUPPORT */
3614     osi_Log0(smb_logp,"ReceiveTran2GetDfsReferral - NOT_SUPPORTED"); 
3615     return CM_ERROR_BADOP;
3616 #endif /* DFS_SUPPORT */
3617 }
3618
3619 long 
3620 smb_ReceiveTran2ReportDFSInconsistency(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *outp)
3621 {
3622     /* This is a UNICODE only request (bit15 of Flags2) */
3623
3624     /* There is nothing we can do about this operation.  The client is going to
3625      * tell us that there is a Version 1 Referral Element for which there is a DFS Error.
3626      * Unfortunately, there is really nothing we can do about it other then log it 
3627      * somewhere.  Even then I don't think there is anything for us to do.
3628      * So let's return an error value.
3629      */
3630
3631     osi_Log0(smb_logp,"ReceiveTran2ReportDFSInconsistency - NOT_SUPPORTED");
3632     return CM_ERROR_BADOP;
3633 }
3634
3635 long 
3636 smb_ApplyV3DirListPatches(cm_scache_t *dscp,
3637         smb_dirListPatch_t **dirPatchespp, int infoLevel, cm_user_t *userp,
3638         cm_req_t *reqp)
3639 {
3640     long code = 0;
3641     cm_scache_t *scp;
3642     cm_scache_t *targetScp;                     /* target if scp is a symlink */
3643     char *dptr;
3644     afs_uint32 dosTime;
3645     FILETIME ft;
3646     int shortTemp;
3647     unsigned short attr;
3648     unsigned long lattr;
3649     smb_dirListPatch_t *patchp;
3650     smb_dirListPatch_t *npatchp;
3651     afs_uint32 rights;
3652     afs_int32 mustFake = 0;
3653
3654     code = cm_FindACLCache(dscp, userp, &rights);
3655     if (code == 0 && !(rights & PRSFS_READ))
3656         mustFake = 1;
3657     else if (code == -1) {
3658         lock_ObtainMutex(&dscp->mx);
3659         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
3660                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3661         lock_ReleaseMutex(&dscp->mx);
3662         if (code == CM_ERROR_NOACCESS) {
3663             mustFake = 1;
3664             code = 0;
3665         }
3666     }
3667     if (code)
3668         return code;
3669
3670     for(patchp = *dirPatchespp; patchp; patchp =
3671          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3672         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3673         if (code) 
3674             continue;
3675
3676         lock_ObtainMutex(&scp->mx);
3677         if (mustFake == 0)
3678             code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3679                              CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3680         if (mustFake || code) { 
3681             lock_ReleaseMutex(&scp->mx);
3682
3683             dptr = patchp->dptr;
3684
3685             /* Plug in fake timestamps. A time stamp of 0 causes 'invalid parameter'
3686                errors in the client. */
3687             if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3688                 /* 1969-12-31 23:59:59 +00 */
3689                 ft.dwHighDateTime = 0x19DB200;
3690                 ft.dwLowDateTime = 0x5BB78980;
3691
3692                 /* copy to Creation Time */
3693                 *((FILETIME *)dptr) = ft;
3694                 dptr += 8;
3695
3696                 /* copy to Last Access Time */
3697                 *((FILETIME *)dptr) = ft;
3698                 dptr += 8;
3699
3700                 /* copy to Last Write Time */
3701                 *((FILETIME *)dptr) = ft;
3702                 dptr += 8;
3703
3704                 /* copy to Change Time */
3705                 *((FILETIME *)dptr) = ft;
3706                 dptr += 24;
3707
3708                 switch (scp->fileType) {
3709                 case CM_SCACHETYPE_DIRECTORY:
3710                 case CM_SCACHETYPE_MOUNTPOINT:
3711                 case CM_SCACHETYPE_SYMLINK:
3712                 case CM_SCACHETYPE_INVALID:
3713                     *((u_long *)dptr) = SMB_ATTR_DIRECTORY;
3714                     break;
3715                 default:
3716                     *((u_long *)dptr) = SMB_ATTR_NORMAL;
3717                         
3718                 }
3719                 /* merge in hidden attribute */
3720                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3721                     *((u_long *)dptr) |= SMB_ATTR_HIDDEN;
3722                 }
3723                 dptr += 4;
3724             } else {
3725                 /* 1969-12-31 23:59:58 +00*/
3726                 dosTime = 0xEBBFBF7D;
3727
3728                 /* and copy out date */
3729                 shortTemp = (dosTime>>16) & 0xffff;
3730                 *((u_short *)dptr) = shortTemp;
3731                 dptr += 2;
3732
3733                 /* copy out creation time */
3734                 shortTemp = dosTime & 0xffff;
3735                 *((u_short *)dptr) = shortTemp;
3736                 dptr += 2;
3737
3738                 /* and copy out date */
3739                 shortTemp = (dosTime>>16) & 0xffff;
3740                 *((u_short *)dptr) = shortTemp;
3741                 dptr += 2;
3742                         
3743                 /* copy out access time */
3744                 shortTemp = dosTime & 0xffff;
3745                 *((u_short *)dptr) = shortTemp;
3746                 dptr += 2;
3747
3748                 /* and copy out date */
3749                 shortTemp = (dosTime>>16) & 0xffff;
3750                 *((u_short *)dptr) = shortTemp;
3751                 dptr += 2;
3752                         
3753                 /* copy out mod time */
3754                 shortTemp = dosTime & 0xffff;
3755                 *((u_short *)dptr) = shortTemp;
3756                 dptr += 10;
3757
3758                 /* set the attribute */
3759                 switch (scp->fileType) {
3760                 case CM_SCACHETYPE_DIRECTORY:
3761                 case CM_SCACHETYPE_MOUNTPOINT:
3762                 case CM_SCACHETYPE_SYMLINK:
3763                 case CM_SCACHETYPE_INVALID:
3764                     attr = SMB_ATTR_DIRECTORY;
3765                 default:
3766                     attr = SMB_ATTR_NORMAL;
3767                 }
3768                 /* merge in hidden (dot file) attribute */
3769                 if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3770                     attr |= SMB_ATTR_HIDDEN;
3771                 }       
3772                 *dptr++ = attr & 0xff;
3773                 *dptr++ = (attr >> 8) & 0xff;
3774             }
3775             
3776             cm_ReleaseSCache(scp);
3777             continue;
3778         }
3779         
3780         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3781
3782         /* now watch for a symlink */
3783         code = 0;
3784         while (code == 0 && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3785             lock_ReleaseMutex(&scp->mx);
3786             code = cm_EvaluateSymLink(dscp, scp, &targetScp, userp, reqp);
3787             if (code == 0) {
3788                 /* we have a more accurate file to use (the
3789                  * target of the symbolic link).  Otherwise,
3790                  * we'll just use the symlink anyway.
3791                  */
3792                 osi_Log2(smb_logp, "symlink vp %x to vp %x",
3793                           scp, targetScp);
3794                 cm_ReleaseSCache(scp);
3795                 scp = targetScp;
3796             }
3797             lock_ObtainMutex(&scp->mx);
3798         }
3799
3800         dptr = patchp->dptr;
3801
3802         if (infoLevel >= SMB_FIND_FILE_DIRECTORY_INFO) {
3803             /* get filetime */
3804             smb_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
3805
3806             /* copy to Creation Time */
3807             *((FILETIME *)dptr) = ft;
3808             dptr += 8;
3809
3810             /* copy to Last Access Time */
3811             *((FILETIME *)dptr) = ft;
3812             dptr += 8;
3813
3814             /* copy to Last Write Time */
3815             *((FILETIME *)dptr) = ft;
3816             dptr += 8;
3817
3818             /* copy to Change Time */
3819             *((FILETIME *)dptr) = ft;
3820             dptr += 8;
3821
3822             /* Use length for both file length and alloc length */
3823             *((LARGE_INTEGER *)dptr) = scp->length;
3824             dptr += 8;
3825             *((LARGE_INTEGER *)dptr) = scp->length;
3826             dptr += 8;
3827
3828             /* Copy attributes */
3829             lattr = smb_ExtAttributes(scp);
3830             if (code == CM_ERROR_NOSUCHPATH && scp->fileType == CM_SCACHETYPE_SYMLINK) {
3831                 if (lattr == SMB_ATTR_NORMAL)
3832                     lattr = SMB_ATTR_DIRECTORY;
3833                 else
3834                     lattr |= SMB_ATTR_DIRECTORY;
3835             }
3836             /* merge in hidden (dot file) attribute */
3837             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3838                 if (lattr == SMB_ATTR_NORMAL)
3839                     lattr = SMB_ATTR_HIDDEN;
3840                 else
3841                     lattr |= SMB_ATTR_HIDDEN;
3842             }
3843             *((u_long *)dptr) = lattr;
3844             dptr += 4;
3845         } else {
3846             /* get dos time */
3847             smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3848
3849             /* and copy out date */
3850             shortTemp = (dosTime>>16) & 0xffff;
3851             *((u_short *)dptr) = shortTemp;
3852             dptr += 2;
3853
3854             /* copy out creation time */
3855             shortTemp = dosTime & 0xffff;
3856             *((u_short *)dptr) = shortTemp;
3857             dptr += 2;
3858
3859             /* and copy out date */
3860             shortTemp = (dosTime>>16) & 0xffff;
3861             *((u_short *)dptr) = shortTemp;
3862             dptr += 2;
3863
3864             /* copy out access time */
3865             shortTemp = dosTime & 0xffff;
3866             *((u_short *)dptr) = shortTemp;
3867             dptr += 2;
3868
3869             /* and copy out date */
3870             shortTemp = (dosTime>>16) & 0xffff;
3871             *((u_short *)dptr) = shortTemp;
3872             dptr += 2;
3873
3874             /* copy out mod time */
3875             shortTemp = dosTime & 0xffff;
3876             *((u_short *)dptr) = shortTemp;
3877             dptr += 2;
3878
3879             /* copy out file length and alloc length,
3880              * using the same for both
3881              */
3882             *((u_long *)dptr) = scp->length.LowPart;
3883             dptr += 4;
3884             *((u_long *)dptr) = scp->length.LowPart;
3885             dptr += 4;
3886
3887             /* finally copy out attributes as short */
3888             attr = smb_Attributes(scp);
3889             /* merge in hidden (dot file) attribute */
3890             if ( patchp->flags & SMB_DIRLISTPATCH_DOTFILE ) {
3891                 if (lattr == SMB_ATTR_NORMAL)
3892                     lattr = SMB_ATTR_HIDDEN;
3893                 else
3894                     lattr |= SMB_ATTR_HIDDEN;
3895             }
3896             *dptr++ = attr & 0xff;
3897             *dptr++ = (attr >> 8) & 0xff;
3898         }
3899
3900         lock_ReleaseMutex(&scp->mx);
3901         cm_ReleaseSCache(scp);
3902     }
3903         
3904     /* now free the patches */
3905     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3906         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3907         free(patchp);
3908     }
3909         
3910     /* and mark the list as empty */
3911     *dirPatchespp = NULL;
3912
3913     return code;
3914 }
3915
3916 #ifndef USE_OLD_MATCHING
3917 // char table for case insensitive comparison
3918 char mapCaseTable[256];
3919
3920 VOID initUpperCaseTable(VOID) 
3921 {
3922     int i;
3923     for (i = 0; i < 256; ++i) 
3924        mapCaseTable[i] = toupper(i);
3925     // make '"' match '.' 
3926     mapCaseTable[(int)'"'] = toupper('.');
3927     // make '<' match '*' 
3928     mapCaseTable[(int)'<'] = toupper('*');
3929     // make '>' match '?' 
3930     mapCaseTable[(int)'>'] = toupper('?');    
3931 }
3932
3933 // Compare 'pattern' (containing metacharacters '*' and '?') with the file
3934 // name 'name'.
3935 // Note : this procedure works recursively calling itself.
3936 // Parameters
3937 // PSZ pattern    : string containing metacharacters.
3938 // PSZ name       : file name to be compared with 'pattern'.
3939 // Return value
3940 // BOOL : TRUE/FALSE (match/mistmatch)
3941
3942 BOOL 
3943 szWildCardMatchFileName(PSZ pattern, PSZ name, int casefold) 
3944 {
3945     PSZ pename;         // points to the last 'name' character
3946     PSZ p;
3947     pename = name + strlen(name) - 1;
3948     while (*name) {
3949         switch (*pattern) {
3950         case '?':
3951             ++pattern;
3952             if (*name == '.')
3953                 continue;
3954             ++name;
3955             break;
3956          case '*':
3957             ++pattern;
3958             if (*pattern == '\0')
3959                 return TRUE;
3960             for (p = pename; p >= name; --p) {
3961                 if ((casefold && (mapCaseTable[*p] == mapCaseTable[*pattern]) ||
3962                      !casefold && (*p == *pattern)) &&
3963                      szWildCardMatchFileName(pattern + 1, p + 1, casefold))
3964                     return TRUE;
3965             } /* endfor */
3966             return FALSE;
3967         default:
3968             if ((casefold && mapCaseTable[*name] != mapCaseTable[*pattern]) ||
3969                 (!casefold && *name != *pattern))
3970                 return FALSE;
3971             ++pattern, ++name;
3972             break;
3973         } /* endswitch */
3974     } /* endwhile */ 
3975
3976     /* if all we have left are wildcards, then we match */
3977     for (;*pattern; pattern++) {
3978         if (*pattern != '*' && *pattern != '?')
3979             return FALSE;
3980     }
3981     return TRUE;
3982 }
3983
3984 /* do a case-folding search of the star name mask with the name in namep.
3985  * Return 1 if we match, otherwise 0.
3986  */
3987 int smb_V3MatchMask(char *namep, char *maskp, int flags) 
3988 {
3989     char * newmask;
3990     int    i, j, star, qmark, casefold, retval;
3991
3992     /* make sure we only match 8.3 names, if requested */
3993     if ((flags & CM_FLAG_8DOT3) && !cm_Is8Dot3(namep)) 
3994         return 0;
3995     
3996     casefold = (flags & CM_FLAG_CASEFOLD) ? 1 : 0;
3997
3998     /* optimize the pattern:
3999      * if there is a mixture of '?' and '*',
4000      * for example  the sequence "*?*?*?*"
4001      * must be turned into the form "*"
4002      */
4003     newmask = (char *)malloc(strlen(maskp)+1);
4004     for ( i=0, j=0, star=0, qmark=0; maskp[i]; i++) {
4005         switch ( maskp[i] ) {
4006         case '?':
4007         case '>':
4008             qmark++;
4009             break;
4010         case '<':
4011         case '*':
4012             star++;
4013             break;
4014         default:
4015             if ( star ) {
4016                 newmask[j++] = '*';
4017             } else if ( qmark ) {
4018                 while ( qmark-- )
4019                     newmask[j++] = '?';
4020             }
4021             newmask[j++] = maskp[i];
4022             star = 0;
4023             qmark = 0;
4024         }
4025     }
4026     if ( star ) {
4027         newmask[j++] = '*';
4028     } else if ( qmark ) {
4029         while ( qmark-- )
4030             newmask[j++] = '?';
4031     }
4032     newmask[j++] = '\0';
4033
4034     retval = szWildCardMatchFileName(newmask, namep, casefold) ? 1:0;
4035
4036     free(newmask);
4037     return retval;
4038 }
4039
4040 #else /* USE_OLD_MATCHING */
4041 /* do a case-folding search of the star name mask with the name in namep.
4042  * Return 1 if we match, otherwise 0.
4043  */
4044 int smb_V3MatchMask(char *namep, char *maskp, int flags)
4045 {
4046     unsigned char tcp1, tcp2;   /* Pattern characters */
4047     unsigned char tcn1;         /* Name characters */
4048     int sawDot = 0, sawStar = 0, req8dot3 = 0;
4049     char *starNamep, *starMaskp;
4050     static char nullCharp[] = {0};
4051     int casefold = flags & CM_FLAG_CASEFOLD;
4052
4053     /* make sure we only match 8.3 names, if requested */
4054     req8dot3 = (flags & CM_FLAG_8DOT3);
4055     if (req8dot3 && !cm_Is8Dot3(namep)) 
4056         return 0;
4057
4058     /* loop */
4059     while (1) {
4060         /* Next pattern character */
4061         tcp1 = *maskp++;
4062
4063         /* Next name character */
4064         tcn1 = *namep;
4065
4066         if (tcp1 == 0) {
4067             /* 0 - end of pattern */
4068             if (tcn1 == 0)
4069                 return 1;
4070             else
4071                 return 0;
4072         }
4073         else if (tcp1 == '.' || tcp1 == '"') {
4074             if (sawDot) {
4075                 if (tcn1 == '.') {
4076                     namep++;
4077                     continue;
4078                 } else
4079                     return 0;
4080             }
4081             else {
4082                 /*
4083                  * first dot in pattern;
4084                  * must match dot or end of name
4085                  */
4086                 sawDot = 1;
4087                 if (tcn1 == 0)
4088                     continue;
4089                 else if (tcn1 == '.') {
4090                     sawStar = 0;
4091                     namep++;
4092                     continue;
4093                 }
4094                 else
4095                     return 0;
4096             }
4097         }
4098         else if (tcp1 == '?') {
4099             if (tcn1 == 0 || tcn1 == '.')
4100                 return 0;
4101             namep++;
4102             continue;
4103         }
4104         else if (tcp1 == '>') {
4105             if (tcn1 != 0 && tcn1 != '.')
4106                 namep++;
4107             continue;
4108         }
4109         else if (tcp1 == '*' || tcp1 == '<') {
4110             tcp2 = *maskp++;
4111             if (tcp2 == 0)
4112                 return 1;
4113             else if ((req8dot3 && tcp2 == '.') || tcp2 == '"') {
4114                 while (req8dot3 && tcn1 != '.' && tcn1 != 0)
4115                     tcn1 = *++namep;
4116                 if (tcn1 == 0) {
4117                     if (sawDot)
4118                         return 0;
4119                     else
4120                         continue;
4121                 }
4122                 else {
4123                     namep++;
4124                     continue;
4125                 }
4126             }
4127             else {
4128                 /*
4129                  * pattern character after '*' is not null or
4130                  * period.  If it is '?' or '>', we are not
4131                  * going to understand it.  If it is '*' or
4132                  * '<', we are going to skip over it.  None of
4133                  * these are likely, I hope.
4134                  */
4135                 /* skip over '*' and '<' */
4136                 while (tcp2 == '*' || tcp2 == '<')
4137                     tcp2 = *maskp++;
4138
4139                 /* skip over characters that don't match tcp2 */
4140                 while (req8dot3 && tcn1 != '.' && tcn1 != 0 && 
4141                         ((casefold && cm_foldUpper[tcn1] != cm_foldUpper[tcp2]) || 
4142                           (!casefold && tcn1 != tcp2)))
4143                     tcn1 = *++namep;
4144
4145                 /* No match */
4146                 if ((req8dot3 && tcn1 == '.') || tcn1 == 0)
4147                     return 0;
4148
4149                 /* Remember where we are */
4150                 sawStar = 1;
4151                 starMaskp = maskp;
4152                 starNamep = namep;
4153
4154                 namep++;
4155                 continue;
4156             }
4157         }
4158         else {
4159             /* tcp1 is not a wildcard */
4160             if ((casefold && cm_foldUpper[tcn1] == cm_foldUpper[tcp1]) || 
4161                  (!casefold && tcn1 == tcp1)) {
4162                 /* they match */
4163                 namep++;
4164                 continue;
4165             }
4166             /* if trying to match a star pattern, go back */
4167             if (sawStar) {
4168                 maskp = starMaskp - 2;
4169                 namep = starNamep + 1;
4170                 sawStar = 0;
4171                 continue;
4172             }
4173             /* that's all */
4174             return 0;
4175         }
4176     }
4177 }
4178 #endif /* USE_OLD_MATCHING */
4179
4180 /* smb_ReceiveTran2SearchDir implements both 
4181  * Tran2_Find_First and Tran2_Find_Next
4182  */
4183 #define TRAN2_FIND_FLAG_CLOSE_SEARCH            0x01
4184 #define TRAN2_FIND_FLAG_CLOSE_SEARCH_IF_END     0x02
4185 #define TRAN2_FIND_FLAG_RETURN_RESUME_KEYS      0x04
4186 #define TRAN2_FIND_FLAG_CONTINUE_SEARCH         0x08
4187 #define TRAN2_FIND_FLAG_BACKUP_INTENT           0x10
4188
4189 /* this is an optimized handler for T2SearchDir that handles the case
4190    where there are no wildcards in the search path.  I.e. an
4191    application is using FindFirst(Ex) to get information about a
4192    single file or directory.  It will attempt to do a single lookup.
4193    If that fails, then smb_ReceiveTran2SearchDir() will fall back to
4194    the usual mechanism. 
4195    
4196    This function will return either CM_ERROR_NOSUCHFILE or SUCCESS.
4197    */
4198 long smb_T2SearchDirSingle(smb_vc_t *vcp, smb_tran2Packet_t *p, smb_packet_t *opx)
4199 {
4200     int attribute;
4201     long nextCookie;
4202     long code = 0, code2 = 0;
4203     char *pathp;
4204     int maxCount;
4205     smb_dirListPatch_t *dirListPatchesp;
4206     smb_dirListPatch_t *curPatchp;
4207     long orbytes;                       /* # of bytes in this output record */
4208     long ohbytes;                       /* # of bytes, except file name */
4209     long onbytes;                       /* # of bytes in name, incl. term. null */
4210     cm_scache_t *scp = NULL;
4211     cm_scache_t *targetscp = NULL;
4212     cm_user_t *userp = NULL;
4213     char *op;                           /* output data ptr */
4214     char *origOp;                       /* original value of op */
4215     cm_space_t *spacep;                 /* for pathname buffer */
4216     long maxReturnData;                 /* max # of return data */
4217     long maxReturnParms;                /* max # of return parms */
4218     long bytesInBuffer;                 /* # data bytes in the output buffer */
4219     char *maskp;                        /* mask part of path */
4220     int infoLevel;
4221     int searchFlags;
4222     int eos;
4223     smb_tran2Packet_t *outp;            /* response packet */
4224     char *tidPathp;
4225     int align;
4226     char shortName[13];                 /* 8.3 name if needed */
4227     int NeedShortName;
4228     char *shortNameEnd;
4229     cm_req_t req;
4230     char * s;
4231
4232     cm_InitReq(&req);
4233
4234     eos = 0;
4235     osi_assert(p->opcode == 1);<