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