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