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