Windows: The unnamed stream is a synonym
[openafs.git] / src / WINNT / afsd / smb.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 #pragma warning(pop)
18 #include <stddef.h>
19 #include <stdlib.h>
20 #include <malloc.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <time.h>
24
25 #include "afsd.h"
26 #include <osi.h>
27 #include <rx\rx.h>
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
30
31 #include "smb.h"
32 #include "msrpc.h"
33 #include "lanahelper.h"
34
35 #define STRSAFE_NO_DEPRECATE
36 #include <strsafe.h>
37
38 /* These characters are illegal in Windows filenames */
39 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
40
41 static int smbShutdownFlag = 0;
42 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
43
44 int smb_LogoffTokenTransfer;
45 time_t smb_LogoffTransferTimeout;
46
47 int smb_StoreAnsiFilenames = 0;
48
49 DWORD last_msg_time = 0;
50
51 long ongoingOps = 0;
52
53 unsigned int sessionGen = 0;
54
55 extern void afsi_log(char *pattern, ...);
56 extern HANDLE afsi_file;
57 extern int powerStateSuspended;
58
59 osi_hyper_t hzero = {0, 0};
60 osi_hyper_t hones = {0xFFFFFFFF, -1};
61
62 osi_log_t *  smb_logp;
63 osi_rwlock_t smb_globalLock;
64 osi_rwlock_t smb_rctLock;
65 osi_mutex_t  smb_ListenerLock;
66 osi_mutex_t  smb_StartedLock;
67
68 unsigned char smb_LANadapter = LANA_INVALID;
69 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
70 int  smb_LanAdapterChangeDetected = 0;
71 afs_uint32    smb_AsyncStore = 1;
72 afs_uint32    smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
73
74 BOOL isGateway = FALSE;
75
76 /* for debugging */
77 long smb_maxObsConcurrentCalls=0;
78 long smb_concurrentCalls=0;
79
80 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
81
82 smb_packet_t *smb_packetFreeListp;
83 smb_ncb_t *smb_ncbFreeListp;
84
85 afs_uint32 smb_NumServerThreads;
86
87 afs_uint32 numNCBs, numSessions, numVCs;
88
89 int smb_maxVCPerServer;
90 int smb_maxMpxRequests;
91
92 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
93 HANDLE smb_lsaHandle;
94 ULONG smb_lsaSecPackage;
95 LSA_STRING smb_lsaLogonOrigin;
96
97 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
98 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
99 EVENT_HANDLE **NCBreturns;
100 EVENT_HANDLE **NCBShutdown;
101 EVENT_HANDLE *smb_ServerShutdown;
102 EVENT_HANDLE ListenerShutdown[256];
103 DWORD NCBsessions[NCB_MAX];
104 NCB *NCBs[NCB_MAX];
105 struct smb_packet *bufs[NCB_MAX];
106
107 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
108 EVENT_HANDLE SessionEvents[SESSION_MAX];
109 unsigned short LSNs[SESSION_MAX];
110 int lanas[SESSION_MAX];
111 BOOL dead_sessions[SESSION_MAX];
112 LANA_ENUM lana_list;
113 /* for raw I/O */
114 osi_mutex_t smb_RawBufLock;
115 char *smb_RawBufs;
116
117 #define SMB_MASKFLAG_TILDE 1
118 #define SMB_MASKFLAG_CASEFOLD 2
119
120 #define RAWTIMEOUT INFINITE
121
122 /* for raw write */
123 typedef struct raw_write_cont {
124     long code;
125     osi_hyper_t offset;
126     long count;
127     char *buf;
128     int writeMode;
129     long alreadyWritten;
130 } raw_write_cont_t;
131
132 /* dir search stuff */
133 long smb_dirSearchCounter = 1;
134 smb_dirSearch_t *smb_firstDirSearchp;
135 smb_dirSearch_t *smb_lastDirSearchp;
136
137 /* hide dot files? */
138 int smb_hideDotFiles;
139
140 /* Negotiate Unicode support? */
141 LONG smb_UseUnicode;
142
143 /* global state about V3 protocols */
144 int smb_useV3;          /* try to negotiate V3 */
145
146 static int showErrors = 0;
147 /* MessageBox or something like it */
148 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
149 = NULL;
150
151 /* GMT time info:
152  * Time in Unix format of midnight, 1/1/1970 local time.
153  * When added to dosUTime, gives Unix (AFS) time.
154  */
155 time_t smb_localZero = 0;
156
157 char *smb_localNamep = NULL;
158
159 smb_vc_t *smb_allVCsp;
160 smb_vc_t *smb_deadVCsp;
161
162 smb_username_t *usernamesp = NULL;
163
164 smb_waitingLockRequest_t *smb_allWaitingLocks;
165
166 /* forward decl */
167 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
168                         NCB *ncbp, raw_write_cont_t *rwcp);
169 int smb_NetbiosInit(int);
170
171 #ifdef LOG_PACKET
172 void smb_LogPacket(smb_packet_t *packet);
173 #endif /* LOG_PACKET */
174                                                          
175 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
176 int smb_ServerDomainNameLength = 0;
177 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
178 int smb_ServerOSLength = lengthof(smb_ServerOS);
179 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
180 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
181
182 /* Faux server GUID. This is never checked. */
183 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
184
185 void smb_InitReq(cm_req_t *reqp)
186 {
187     cm_InitReq(reqp);
188     reqp->flags |= CM_REQ_SOURCE_SMB;
189 }
190
191 const char * ncb_error_string(int code)
192 {
193     const char * s;
194     switch ( code ) {
195     case 0x01: s = "NRC_BUFLEN llegal buffer length";                   break; 
196     case 0x03: s = "NRC_ILLCMD illegal command";                        break; 
197     case 0x05: s = "NRC_CMDTMO command timed out";                      break; 
198     case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break; 
199     case 0x07: s = "NRC_BADDR  illegal buffer address";                 break; 
200     case 0x08: s = "NRC_SNUMOUT session number out of range";           break; 
201     case 0x09: s = "NRC_NORES no resource available";                   break; 
202     case 0x0a: s = "NRC_SCLOSED asession closed";                       break; 
203     case 0x0b: s = "NRC_CMDCAN command cancelled";                      break; 
204     case 0x0d: s = "NRC_DUPNAME duplicate name";                        break; 
205     case 0x0e: s = "NRC_NAMTFUL name table full";                       break; 
206     case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break; 
207     case 0x11: s = "NRC_LOCTFUL local session table full";              break; 
208     case 0x12: s = "NRC_REMTFUL remote session table full";             break; 
209     case 0x13: s = "NRC_ILLNN illegal name number";                     break; 
210     case 0x14: s = "NRC_NOCALL no callname";                            break; 
211     case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME";               break; 
212     case 0x16: s = "NRC_INUSE name in use on remote adapter";           break; 
213     case 0x17: s = "NRC_NAMERR name deleted";                           break; 
214     case 0x18: s = "NRC_SABORT session ended abnormally";               break; 
215     case 0x19: s = "NRC_NAMCONF name conflict detected";                break; 
216     case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying";   break; 
217     case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
218     case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid";             break; 
219     case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break; 
220     case 0x26: s = "NRC_CANCEL command not valid to cancel";            break; 
221     case 0x30: s = "NRC_DUPENV name defined by anther local process";   break; 
222     case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required";      break; 
223     case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted";    break; 
224     case 0x36: s = "NRC_MAXAPPS max number of applications exceeded";   break; 
225     case 0x37: s = "NRC_NOSAPS no saps available for netbios";          break; 
226     case 0x38: s = "NRC_NORESOURCES requested resources are not available";     break; 
227     case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment";    break; 
228     case 0x3B: s = "NRC_INVDDID invalid NCB DDID";                      break; 
229     case 0x3C: s = "NRC_LOCKFAILlock of user area failed";              break; 
230     case 0x3f: s = "NRC_OPENERR NETBIOS not loaded";                    break; 
231     case 0x40: s = "NRC_SYSTEM system error";                           break;                 
232     default:   s = "unknown error";
233     }
234     return s;
235 }
236
237
238 char * myCrt_Dispatch(int i)
239 {
240     switch (i)
241     {
242     case 0x00:
243         return "(00)ReceiveCoreMakeDir";
244     case 0x01:
245         return "(01)ReceiveCoreRemoveDir";
246     case 0x02:
247         return "(02)ReceiveCoreOpen";
248     case 0x03:
249         return "(03)ReceiveCoreCreate";
250     case 0x04:
251         return "(04)ReceiveCoreClose";
252     case 0x05:
253         return "(05)ReceiveCoreFlush";
254     case 0x06:
255         return "(06)ReceiveCoreUnlink";
256     case 0x07:
257         return "(07)ReceiveCoreRename";
258     case 0x08:
259         return "(08)ReceiveCoreGetFileAttributes";
260     case 0x09:
261         return "(09)ReceiveCoreSetFileAttributes";
262     case 0x0a:
263         return "(0a)ReceiveCoreRead";
264     case 0x0b:
265         return "(0b)ReceiveCoreWrite";
266     case 0x0c:
267         return "(0c)ReceiveCoreLockRecord";
268     case 0x0d:
269         return "(0d)ReceiveCoreUnlockRecord";
270     case 0x0e:
271         return "(0e)SendCoreBadOp";
272     case 0x0f:
273         return "(0f)ReceiveCoreCreate";
274     case 0x10:
275         return "(10)ReceiveCoreCheckPath";
276     case 0x11:
277         return "(11)SendCoreBadOp";
278     case 0x12:
279         return "(12)ReceiveCoreSeek";
280     case 0x1a:
281         return "(1a)ReceiveCoreReadRaw";
282     case 0x1d:
283         return "(1d)ReceiveCoreWriteRawDummy";
284     case 0x22:
285         return "(22)ReceiveV3SetAttributes";
286     case 0x23:
287         return "(23)ReceiveV3GetAttributes";
288     case 0x24:
289         return "(24)ReceiveV3LockingX";
290     case 0x25:
291         return "(25)ReceiveV3Trans";
292     case 0x26:
293         return "(26)ReceiveV3Trans[aux]";
294     case 0x29:
295         return "(29)SendCoreBadOp";
296     case 0x2b:
297         return "(2b)ReceiveCoreEcho";
298     case 0x2d:
299         return "(2d)ReceiveV3OpenX";
300     case 0x2e:
301         return "(2e)ReceiveV3ReadX";
302     case 0x2f:
303         return "(2f)ReceiveV3WriteX";
304     case 0x32:
305         return "(32)ReceiveV3Tran2A";
306     case 0x33:
307         return "(33)ReceiveV3Tran2A[aux]";
308     case 0x34:
309         return "(34)ReceiveV3FindClose";
310     case 0x35:
311         return "(35)ReceiveV3FindNotifyClose";
312     case 0x70:
313         return "(70)ReceiveCoreTreeConnect";
314     case 0x71:
315         return "(71)ReceiveCoreTreeDisconnect";
316     case 0x72:
317         return "(72)ReceiveNegotiate";
318     case 0x73:
319         return "(73)ReceiveV3SessionSetupX";
320     case 0x74:
321         return "(74)ReceiveV3UserLogoffX";
322     case 0x75:
323         return "(75)ReceiveV3TreeConnectX";
324     case 0x80:
325         return "(80)ReceiveCoreGetDiskAttributes";
326     case 0x81:
327         return "(81)ReceiveCoreSearchDir";
328     case 0x82:
329         return "(82)Find";
330     case 0x83:
331         return "(83)FindUnique";
332     case 0x84:
333         return "(84)FindClose";
334     case 0xA0:
335         return "(A0)ReceiveNTTransact";
336     case 0xA2:
337         return "(A2)ReceiveNTCreateX";
338     case 0xA4:
339         return "(A4)ReceiveNTCancel";
340     case 0xA5:
341         return "(A5)ReceiveNTRename";
342     case 0xc0:
343         return "(C0)OpenPrintFile";
344     case 0xc1:
345         return "(C1)WritePrintFile";
346     case 0xc2:
347         return "(C2)ClosePrintFile";
348     case 0xc3:
349         return "(C3)GetPrintQueue";
350     case 0xd8:
351         return "(D8)ReadBulk";
352     case 0xd9:
353         return "(D9)WriteBulk";
354     case 0xda:
355         return "(DA)WriteBulkData";
356     default:
357         return "unknown SMB op";
358     }
359 }       
360
361 char * myCrt_2Dispatch(int i)
362 {
363     switch (i)
364     {
365     default:
366         return "unknown SMB op-2";
367     case 0:
368         return "S(00)CreateFile_ReceiveTran2Open";
369     case 1:
370         return "S(01)FindFirst_ReceiveTran2SearchDir";
371     case 2:
372         return "S(02)FindNext_ReceiveTran2SearchDir";   /* FindNext */
373     case 3:
374         return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
375     case 4:
376         return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
377     case 5:
378         return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
379     case 6:
380         return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
381     case 7:
382         return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
383     case 8:
384         return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
385     case 9:
386         return "S(09)_ReceiveTran2FSCTL";
387     case 10:
388         return "S(0a)_ReceiveTran2IOCTL";
389     case 11:
390         return "S(0b)_ReceiveTran2FindNotifyFirst";
391     case 12:
392         return "S(0c)_ReceiveTran2FindNotifyNext";
393     case 13:
394         return "S(0d)_ReceiveTran2CreateDirectory";
395     case 14:
396         return "S(0e)_ReceiveTran2SessionSetup";
397     case 15:
398         return "S(0f)_QueryFileSystemInformationFid";
399     case 16:
400         return "S(10)_ReceiveTran2GetDfsReferral";
401     case 17:
402         return "S(11)_ReceiveTran2ReportDfsInconsistency";
403     }
404 }       
405
406 char * myCrt_RapDispatch(int i)
407 {
408     switch(i)
409     {
410     default:
411         return "unknown RAP OP";
412     case 0:
413         return "RAP(0)NetShareEnum";
414     case 1:
415         return "RAP(1)NetShareGetInfo";
416     case 13:
417         return "RAP(13)NetServerGetInfo";
418     case 63:
419         return "RAP(63)NetWkStaGetInfo";
420     }
421 }
422
423 char * myCrt_NmpipeDispatch(int i)
424 {
425     switch(i) {
426     case SMB_TRANS_SET_NMPIPE_STATE:
427         return "SET NMPIPE STATE";
428
429     case SMB_TRANS_RAW_READ_NMPIPE:
430         return "RAW READ NMPIPE";
431
432     case SMB_TRANS_QUERY_NMPIPE_STATE:
433         return "QUERY NMPIPE STATE";
434
435     case SMB_TRANS_QUERY_NMPIPE_INFO:
436         return "QUERY NMPIPE INFO";
437
438     case SMB_TRANS_PEEK_NMPIPE:
439         return "PEEK NMPIPE";
440
441     case SMB_TRANS_TRANSACT_NMPIPE:
442         return "TRANSACT NMPIPE";
443
444     case SMB_TRANS_RAW_WRITE_NMPIPE:
445         return "WRITE NMPIPE";
446
447     case SMB_TRANS_READ_NMPIPE:
448         return "READ NMPIPE";
449
450     case SMB_TRANS_WRITE_NMPIPE:
451         return "WRITE NMPIPE";
452
453     case SMB_TRANS_WAIT_NMPIPE:
454         return "WAIT NMPIPE";
455
456     case SMB_TRANS_CALL_NMPIPE:
457         return "CALL NMPIPE";
458     }
459     return "(Unknown)";
460 }
461
462 /* scache must be locked */
463 unsigned int smb_Attributes(cm_scache_t *scp)
464 {
465     unsigned int attrs;
466
467     if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
468          scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
469          scp->fileType == CM_SCACHETYPE_INVALID)
470     {
471         attrs = SMB_ATTR_DIRECTORY;
472 #ifdef SPECIAL_FOLDERS
473         attrs |= SMB_ATTR_SYSTEM;               /* FILE_ATTRIBUTE_SYSTEM */
474 #endif /* SPECIAL_FOLDERS */
475     } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
476         attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
477     } else
478         attrs = 0;
479
480     /*
481      * We used to mark a file RO if it was in an RO volume, but that
482      * turns out to be impolitic in NT.  See defect 10007.
483      */
484 #ifdef notdef
485     if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
486         attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
487 #else
488     if ((scp->unixModeBits & 0222) == 0)
489         attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
490 #endif
491
492     return attrs;
493 }
494
495 /* Check if the named file/dir is a dotfile/dotdir */
496 /* String pointed to by lastComp can have leading slashes, but otherwise should have
497    no other patch components */
498 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
499     clientchar_t *s;
500
501     if(lastComp) {
502         /* skip over slashes */
503         for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
504     }
505     else
506         return 0;
507
508     /* nulls, curdir and parent dir doesn't count */
509     if (!*s)
510         return 0;
511     if (*s == _C('.')) {
512         if (!*(s + 1)) 
513             return 0;
514         if(*(s+1) == _C('.') && !*(s + 2)) 
515             return 0;
516         return 1;
517     }
518     return 0;
519 }
520
521 static int ExtractBits(WORD bits, short start, short len)
522 {
523     int end;
524     WORD num;
525
526     end = start + len;
527         
528     num = bits << (16 - end);
529     num = num >> ((16 - end) + start);
530
531     return (int)num;
532 }
533
534 void ShowUnixTime(char *FuncName, time_t unixTime)
535 {
536     FILETIME ft;
537     WORD wDate, wTime;
538
539     cm_LargeSearchTimeFromUnixTime(&ft, unixTime);
540
541     if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
542         osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
543     else {
544         int day, month, year, sec, min, hour;
545         char msg[256];
546
547         day = ExtractBits(wDate, 0, 5);
548         month = ExtractBits(wDate, 5, 4);
549         year = ExtractBits(wDate, 9, 7) + 1980;
550
551         sec = ExtractBits(wTime, 0, 5);
552         min = ExtractBits(wTime, 5, 6);
553         hour = ExtractBits(wTime, 11, 5);
554
555         sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
556         osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
557     }
558 }       
559
560 /* Determine if we are observing daylight savings time */
561 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
562 {
563     TIME_ZONE_INFORMATION timeZoneInformation;
564     SYSTEMTIME utc, local, localDST;
565
566     /* Get the time zone info. NT uses this to calc if we are in DST. */
567     GetTimeZoneInformation(&timeZoneInformation);
568
569     /* Return the daylight bias */
570     *pDstBias = timeZoneInformation.DaylightBias;
571
572     /* Return the bias */
573     *pBias = timeZoneInformation.Bias;
574
575     /* Now determine if DST is being observed */
576
577     /* Get the UTC (GMT) time */
578     GetSystemTime(&utc);
579
580     /* Convert UTC time to local time using the time zone info.  If we are
581        observing DST, the calculated local time will include this. 
582      */
583     SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
584
585     /* Set the daylight bias to 0.  The daylight bias is the amount of change
586      * in time that we use for daylight savings time.  By setting this to 0
587      * we cause there to be no change in time during daylight savings time. 
588      */
589     timeZoneInformation.DaylightBias = 0;
590
591     /* Convert the utc time to local time again, but this time without any
592        adjustment for daylight savings time. 
593        */
594     SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
595
596     /* If the two times are different, then it means that the localDST that
597        we calculated includes the daylight bias, and therefore we are
598        observing daylight savings time.
599      */
600     *pDST = localDST.wHour != local.wHour;
601 }       
602  
603
604 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
605 {
606     BOOL dst;       /* Will be TRUE if observing DST */
607     LONG dstBias;   /* Offset from local time if observing DST */
608     LONG bias;      /* Offset from GMT for local time */
609
610     /*
611      * This function will adjust the last write time to compensate
612      * for two bugs in the smb client:
613      *
614      *    1) During Daylight Savings Time, the LastWriteTime is ahead
615      *       in time by the DaylightBias (ignoring the sign - the
616      *       DaylightBias is always stored as a negative number).  If
617      *       the DaylightBias is -60, then the LastWriteTime will be
618      *       ahead by 60 minutes.
619      *
620      *    2) If the local time zone is a positive offset from GMT, then
621      *       the LastWriteTime will be the correct local time plus the
622      *       Bias (ignoring the sign - a positive offset from GMT is
623      *       always stored as a negative Bias).  If the Bias is -120,
624      *       then the LastWriteTime will be ahead by 120 minutes.
625      *
626      *    These bugs can occur at the same time.
627      */
628
629     GetTimeZoneInfo(&dst, &dstBias, &bias);
630
631     /* First adjust for DST */
632     if (dst)
633         *pLastWriteTime -= (-dstBias * 60);     /* Convert dstBias to seconds */
634
635     /* Now adjust for a positive offset from GMT (a negative bias). */
636     if (bias < 0)
637         *pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
638 }                       
639
640 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
641 {
642     time_t diff_t = unixTime - smb_localZero;
643 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
644     osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
645 #endif
646     *dosUTimep = (afs_uint32)diff_t;
647 }
648
649 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
650 {
651     *unixTimep = dosTime + smb_localZero;
652 }
653
654 void smb_MarkAllVCsDead(smb_vc_t * exclude)
655 {
656     smb_vc_t *vcp;
657     smb_vc_t **vcp_to_cleanup = NULL;
658     int n_to_cleanup = 0;
659     int i;
660
661     osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
662
663     lock_ObtainWrite(&smb_globalLock);  /* for dead_sessions[] */
664     lock_ObtainWrite(&smb_rctLock);
665     for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
666
667         if (vcp->magic != SMB_VC_MAGIC)
668             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
669                       __FILE__, __LINE__);
670
671         if (vcp == exclude)
672             continue;
673
674         lock_ObtainMutex(&vcp->mx);
675         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
676             vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
677             lock_ReleaseMutex(&vcp->mx);
678             dead_sessions[vcp->session] = TRUE;
679         } else {
680             lock_ReleaseMutex(&vcp->mx);
681         }
682         n_to_cleanup ++;
683     }
684
685     vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
686     i = 0;
687     for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
688         if (vcp == exclude)
689             continue;
690
691         vcp_to_cleanup[i++] = vcp;
692         smb_HoldVCNoLock(vcp);
693     }
694
695     osi_assert(i == n_to_cleanup);
696
697     lock_ReleaseWrite(&smb_rctLock);
698     lock_ReleaseWrite(&smb_globalLock);
699
700     for (i=0; i < n_to_cleanup; i++) {
701         smb_CleanupDeadVC(vcp_to_cleanup[i]);
702         smb_ReleaseVC(vcp_to_cleanup[i]);
703         vcp_to_cleanup[i] = 0;
704     }
705
706     free(vcp_to_cleanup);
707 }
708
709 #ifdef DEBUG_SMB_REFCOUNT
710 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
711 #else
712 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
713 #endif
714 {
715     smb_vc_t *vcp;
716
717     lock_ObtainWrite(&smb_globalLock);  /* for numVCs */
718     lock_ObtainWrite(&smb_rctLock);
719     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
720         if (vcp->magic != SMB_VC_MAGIC)
721             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
722                        __FILE__, __LINE__);
723
724         lock_ObtainMutex(&vcp->mx);
725         if (lsn == vcp->lsn && lana == vcp->lana &&
726             !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
727             lock_ReleaseMutex(&vcp->mx);
728             smb_HoldVCNoLock(vcp);
729             break;
730         }
731         lock_ReleaseMutex(&vcp->mx);
732     }
733     if (!vcp && (flags & SMB_FLAG_CREATE)) {
734         vcp = malloc(sizeof(*vcp));
735         memset(vcp, 0, sizeof(*vcp));
736         vcp->vcID = ++numVCs;
737         vcp->magic = SMB_VC_MAGIC;
738         vcp->refCount = 2;      /* smb_allVCsp and caller */
739         vcp->tidCounter = 1;
740         vcp->fidCounter = 1;
741         vcp->uidCounter = 1;    /* UID 0 is reserved for blank user */
742         vcp->nextp = smb_allVCsp;
743         smb_allVCsp = vcp;
744         lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
745         vcp->lsn = lsn;
746         vcp->lana = lana;
747         vcp->secCtx = NULL;
748
749         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
750             /* We must obtain a challenge for extended auth 
751              * in case the client negotiates smb v3 
752              */
753             NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
754             MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
755             PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
756             ULONG lsaRespSize = 0;
757
758             lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
759
760             nts = LsaCallAuthenticationPackage( smb_lsaHandle,
761                                                 smb_lsaSecPackage,
762                                                 &lsaReq,
763                                                 sizeof(lsaReq),
764                                                 &lsaResp,
765                                                 &lsaRespSize,
766                                                 &ntsEx);
767             if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
768                 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
769                          nts, ntsEx, sizeof(lsaReq), lsaRespSize);
770                     afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
771                          nts, ntsEx, lsaRespSize);
772             }
773             osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
774
775             if (ntsEx == STATUS_SUCCESS) {
776                 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
777             } else {
778                 /* 
779                  * This will cause the subsequent authentication to fail but
780                  * that is better than us dereferencing a NULL pointer and 
781                  * crashing.
782                  */
783                 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
784             }
785             if (lsaResp)
786                 LsaFreeReturnBuffer(lsaResp);
787         }
788         else
789             memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
790
791         if (numVCs >= CM_SESSION_RESERVED) {
792             numVCs = 0;
793             osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
794         }
795     }
796 #ifdef DEBUG_SMB_REFCOUNT
797     if (vcp) {
798         afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
799         osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
800     }
801 #endif
802     lock_ReleaseWrite(&smb_rctLock);
803     lock_ReleaseWrite(&smb_globalLock);
804     return vcp;
805 }
806
807 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
808 {
809     int i;
810     clientchar_t tc;
811         
812     for(i=0; i<11; i++) {
813         tc = *maskp++;
814         if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
815             return 1;
816     }
817     return 0;
818 }
819
820 static int smb_IsStarMask(clientchar_t *maskp)
821 {
822     clientchar_t tc;
823         
824     while (*maskp) {
825         tc = *maskp++;
826         if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
827             return 1;
828     }
829     return 0;
830 }
831
832 #ifdef DEBUG_SMB_REFCOUNT
833 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
834 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
835 #else
836 void smb_ReleaseVCInternal(smb_vc_t *vcp)
837 #endif
838 {
839     smb_vc_t **vcpp;
840     smb_vc_t * avcp;
841
842     lock_AssertWrite(&smb_rctLock);
843     vcp->refCount--;
844
845     if (vcp->refCount == 0) {
846         if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
847 #ifdef DEBUG_SMB_REFCOUNT
848             afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
849             osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
850 #endif
851             /* remove VCP from smb_deadVCsp */
852             for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
853                 if (*vcpp == vcp) {
854                     *vcpp = vcp->nextp;
855                     break;
856                 }
857             } 
858             lock_FinalizeMutex(&vcp->mx);
859             memset(vcp,0,sizeof(smb_vc_t));
860             free(vcp);
861         } else {
862 #ifdef DEBUG_SMB_REFCOUNT
863             afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
864 #endif
865             for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
866                 if (avcp == vcp)
867                     break;
868             }
869             osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
870                       avcp?"":"not ",vcp, vcp->refCount);
871
872             /* This is a wrong.  However, I suspect that there is an undercount
873              * and I don't want to release 1.4.1 in a state that will allow
874              * smb_vc_t objects to be deallocated while still in the
875              * smb_allVCsp list.  The list is supposed to keep a reference
876              * to the smb_vc_t.  Put it back.
877              */
878             if (avcp) {
879                 vcp->refCount++;
880 #ifdef DEBUG_SMB_REFCOUNT
881                 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
882                 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
883 #endif
884             }
885         }
886     } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
887         /* The reference count is non-zero but the VC is dead.
888          * This implies that some FIDs, TIDs, etc on the VC have yet to 
889          * be cleaned up.  If we were not called by smb_CleanupDeadVC(),
890          * add a reference that will be dropped by
891          * smb_CleanupDeadVC() and try to cleanup the VC again.
892          * Eventually the refCount will drop to zero when all of the
893          * active threads working with the VC end their task.
894          */
895         if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
896             vcp->refCount++;        /* put the refCount back */
897             lock_ReleaseWrite(&smb_rctLock);
898             smb_CleanupDeadVC(vcp);
899 #ifdef DEBUG_SMB_REFCOUNT
900             afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
901             osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
902 #endif
903             lock_ObtainWrite(&smb_rctLock);
904         }
905     } else {
906 #ifdef DEBUG_SMB_REFCOUNT
907         afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
908         osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
909 #endif
910     }
911 }
912
913 #ifdef DEBUG_SMB_REFCOUNT
914 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
915 #else
916 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
917 #endif
918 {
919     lock_AssertWrite(&smb_rctLock);
920     osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
921     smb_ReleaseVCInternal(vcp);
922 }       
923
924 #ifdef DEBUG_SMB_REFCOUNT
925 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
926 #else
927 void smb_ReleaseVC(smb_vc_t *vcp)
928 #endif
929 {
930     lock_ObtainWrite(&smb_rctLock);
931     osi_Log2(smb_logp,"smb_ReleaseVC       vcp %x ref %d",vcp, vcp->refCount);
932     smb_ReleaseVCInternal(vcp);
933     lock_ReleaseWrite(&smb_rctLock);
934 }       
935
936 #ifdef DEBUG_SMB_REFCOUNT
937 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
938 #else
939 void smb_HoldVCNoLock(smb_vc_t *vcp)
940 #endif
941 {
942     lock_AssertWrite(&smb_rctLock);
943     vcp->refCount++;
944 #ifdef DEBUG_SMB_REFCOUNT
945     afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
946     osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
947 #else
948     osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
949 #endif
950 }       
951
952 #ifdef DEBUG_SMB_REFCOUNT
953 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
954 #else
955 void smb_HoldVC(smb_vc_t *vcp)
956 #endif
957 {
958     lock_ObtainWrite(&smb_rctLock);
959     vcp->refCount++;
960 #ifdef DEBUG_SMB_REFCOUNT
961     afsi_log("%s:%d smb_HoldVC       vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
962     osi_Log4(smb_logp,"%s:%d smb_HoldVC       vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
963 #else
964     osi_Log2(smb_logp,"smb_HoldVC       vcp %x ref %d",vcp, vcp->refCount);
965 #endif
966     lock_ReleaseWrite(&smb_rctLock);
967 }       
968
969 void smb_CleanupDeadVC(smb_vc_t *vcp)
970 {
971     smb_fid_t *fidpIter;
972     smb_fid_t *fidpNext;
973     unsigned short fid;
974     smb_tid_t *tidpIter;
975     smb_tid_t *tidpNext;
976     unsigned short tid;
977     smb_user_t *uidpIter;
978     smb_user_t *uidpNext;
979     smb_vc_t **vcpp;
980     afs_uint32 refCount = 0;
981
982     lock_ObtainMutex(&vcp->mx);
983     if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
984         lock_ReleaseMutex(&vcp->mx);
985         osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
986         return;
987     }
988     vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
989     lock_ReleaseMutex(&vcp->mx);
990     osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
991
992     lock_ObtainWrite(&smb_rctLock);
993     /* remove VCP from smb_allVCsp */
994     for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
995         if ((*vcpp)->magic != SMB_VC_MAGIC)
996             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
997                        __FILE__, __LINE__);
998         if (*vcpp == vcp) {
999             *vcpp = vcp->nextp;
1000             vcp->nextp = smb_deadVCsp;
1001             smb_deadVCsp = vcp;
1002             /* Hold onto the reference until we are done with this function */
1003             break;
1004         }
1005     }
1006
1007     for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1008         fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1009
1010         if (fidpIter->deleteOk)
1011             continue;
1012
1013         fid = fidpIter->fid;
1014         osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1015
1016         smb_HoldFIDNoLock(fidpIter);
1017         lock_ReleaseWrite(&smb_rctLock);
1018
1019         smb_CloseFID(vcp, fidpIter, NULL, 0);
1020         smb_ReleaseFID(fidpIter);
1021
1022         lock_ObtainWrite(&smb_rctLock);
1023         fidpNext = vcp->fidsp;
1024     }
1025
1026     for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1027         tidpNext = tidpIter->nextp;
1028         if (tidpIter->deleteOk)
1029             continue;
1030         tidpIter->deleteOk = 1;
1031
1032         tid = tidpIter->tid;
1033         osi_Log2(smb_logp, "  Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1034
1035         smb_HoldTIDNoLock(tidpIter);
1036         smb_ReleaseTID(tidpIter, TRUE);
1037         tidpNext = vcp->tidsp;
1038     }
1039
1040     for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1041         uidpNext = uidpIter->nextp;
1042         if (uidpIter->deleteOk)
1043             continue;
1044         uidpIter->deleteOk = 1;
1045
1046         /* do not add an additional reference count for the smb_user_t
1047          * as the smb_vc_t already is holding a reference */
1048         lock_ReleaseWrite(&smb_rctLock);
1049
1050         smb_ReleaseUID(uidpIter);
1051
1052         lock_ObtainWrite(&smb_rctLock);
1053         uidpNext = vcp->usersp;
1054     }
1055
1056     /* The vcp is now on the deadVCsp list.  We intentionally drop the
1057      * reference so that the refcount can reach 0 and we can delete it 
1058      *
1059      * If the refCount == 1 going into the ReleaseVCNoLock call 
1060      * the object will be freed and it won't be safe to clear 
1061      * the flag.
1062      */
1063     refCount = vcp->refCount;
1064     smb_ReleaseVCNoLock(vcp);
1065     if (refCount > 1) {
1066         lock_ObtainMutex(&vcp->mx);
1067         vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1068         lock_ReleaseMutex(&vcp->mx);
1069     }
1070
1071     lock_ReleaseWrite(&smb_rctLock);
1072     osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1073 }
1074
1075 #ifdef DEBUG_SMB_REFCOUNT
1076 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1077 #else
1078 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1079 #endif
1080 {
1081     smb_tid_t *tidp;
1082
1083     lock_ObtainWrite(&smb_rctLock);
1084   retry:
1085     for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1086         if (tidp->refCount == 0 && tidp->deleteOk) {
1087             tidp->refCount++;
1088             smb_ReleaseTID(tidp, TRUE);
1089             goto retry;
1090         }
1091
1092         if (tid == tidp->tid) {
1093             tidp->refCount++;
1094             break;
1095         }
1096     }
1097     if (!tidp && (flags & SMB_FLAG_CREATE)) {
1098         tidp = malloc(sizeof(*tidp));
1099         memset(tidp, 0, sizeof(*tidp));
1100         tidp->nextp = vcp->tidsp;
1101         tidp->refCount = 1;
1102         tidp->vcp = vcp;
1103         smb_HoldVCNoLock(vcp);
1104         vcp->tidsp = tidp;
1105         lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1106         tidp->tid = tid;
1107     }
1108 #ifdef DEBUG_SMB_REFCOUNT
1109     if (tidp) {
1110         afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1111         osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1112     }
1113 #endif
1114     lock_ReleaseWrite(&smb_rctLock);
1115     return tidp;
1116 }
1117
1118 #ifdef DEBUG_SMB_REFCOUNT
1119 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1120 #else
1121 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1122 #endif
1123 {
1124     lock_AssertWrite(&smb_rctLock);
1125     tidp->refCount++;
1126 #ifdef DEBUG_SMB_REFCOUNT
1127     afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1128     osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1129 #endif
1130 }
1131
1132 #ifdef DEBUG_SMB_REFCOUNT
1133 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1134 #else
1135 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1136 #endif
1137 {
1138     smb_tid_t *tp;
1139     smb_tid_t **ltpp;
1140     cm_user_t *userp = NULL;
1141     smb_vc_t  *vcp = NULL;
1142
1143     if (!locked)
1144         lock_ObtainWrite(&smb_rctLock);
1145     else
1146         lock_AssertWrite(&smb_rctLock);
1147
1148     osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1149 #ifdef DEBUG_SMB_REFCOUNT
1150     afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1151     osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1152 #endif
1153     if (tidp->refCount == 0) {
1154         if (tidp->deleteOk) {
1155             ltpp = &tidp->vcp->tidsp;
1156             for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1157                 if (tp == tidp) 
1158                     break;
1159             }
1160             osi_assertx(tp != NULL, "null smb_tid_t");
1161             *ltpp = tp->nextp;
1162             lock_FinalizeMutex(&tidp->mx);
1163             userp = tidp->userp;        /* remember to drop ref later */
1164             tidp->userp = NULL;
1165             vcp = tidp->vcp;
1166             tidp->vcp = NULL;
1167             free(tidp);
1168         }
1169     }
1170     if (vcp)
1171         smb_ReleaseVCNoLock(vcp);
1172     if (!locked)
1173         lock_ReleaseWrite(&smb_rctLock);
1174     if (userp)
1175         cm_ReleaseUser(userp);
1176 }               
1177
1178 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1179 {
1180     smb_user_t *uidp = NULL;
1181
1182     lock_ObtainWrite(&smb_rctLock);
1183     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1184         if (uid == uidp->userID) {
1185             uidp->refCount++;
1186             osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1187                      vcp, uidp->userID, 
1188                      ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1189             break;
1190         }
1191     }
1192     if (!uidp && (flags & SMB_FLAG_CREATE)) {
1193         uidp = malloc(sizeof(*uidp));
1194         memset(uidp, 0, sizeof(*uidp));
1195         uidp->nextp = vcp->usersp;
1196         uidp->refCount = 2; /* one for the vcp and one for the caller */
1197         uidp->vcp = vcp;
1198         smb_HoldVCNoLock(vcp);
1199         vcp->usersp = uidp;
1200         lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1201         uidp->userID = uid;
1202         osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1203                  vcp, uidp->userID,
1204                  ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1205     }
1206     lock_ReleaseWrite(&smb_rctLock);
1207     return uidp;
1208 }               
1209
1210 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1211                                    afs_uint32 flags)
1212 {
1213     smb_username_t *unp= NULL;
1214
1215     lock_ObtainWrite(&smb_rctLock);
1216     for(unp = usernamesp; unp; unp = unp->nextp) {
1217         if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1218             cm_ClientStrCmpI(unp->machine, machine) == 0) {
1219             unp->refCount++;
1220             break;
1221         }
1222     }
1223     if (!unp && (flags & SMB_FLAG_CREATE)) {
1224         unp = malloc(sizeof(*unp));
1225         memset(unp, 0, sizeof(*unp));
1226         unp->refCount = 1;
1227         unp->nextp = usernamesp;
1228         unp->name = cm_ClientStrDup(usern);
1229         unp->machine = cm_ClientStrDup(machine);
1230         usernamesp = unp;
1231         lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1232         if (flags & SMB_FLAG_AFSLOGON)
1233             unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1234     }
1235
1236     lock_ReleaseWrite(&smb_rctLock);
1237     return unp;
1238 }       
1239
1240 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1241 {
1242     smb_user_t *uidp= NULL;
1243
1244     lock_ObtainWrite(&smb_rctLock);
1245     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1246         if (!uidp->unp) 
1247             continue;
1248         if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1249             uidp->refCount++;
1250             osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1251                      vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1252             break;
1253         } else
1254             continue;
1255     }           
1256     lock_ReleaseWrite(&smb_rctLock);
1257     return uidp;
1258 }       
1259
1260 void smb_ReleaseUsername(smb_username_t *unp)
1261 {
1262     smb_username_t *up;
1263     smb_username_t **lupp;
1264     cm_user_t *userp = NULL;
1265     time_t      now = osi_Time();
1266
1267     lock_ObtainWrite(&smb_rctLock);
1268     osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1269     if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1270         (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1271         lupp = &usernamesp;
1272         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1273             if (up == unp) 
1274                 break;
1275         }
1276         osi_assertx(up != NULL, "null smb_username_t");
1277         *lupp = up->nextp;
1278         up->nextp = NULL;                       /* do not remove this */
1279         lock_FinalizeMutex(&unp->mx);
1280         userp = unp->userp;
1281         free(unp->name);
1282         free(unp->machine);
1283         free(unp);
1284     }
1285     lock_ReleaseWrite(&smb_rctLock);
1286     if (userp)
1287         cm_ReleaseUser(userp);
1288 }       
1289
1290 void smb_HoldUIDNoLock(smb_user_t *uidp)
1291 {
1292     lock_AssertWrite(&smb_rctLock);
1293     uidp->refCount++;
1294 }
1295
1296 void smb_ReleaseUID(smb_user_t *uidp)
1297 {
1298     smb_user_t *up;
1299     smb_user_t **lupp;
1300     smb_username_t *unp = NULL;
1301
1302     lock_ObtainWrite(&smb_rctLock);
1303     osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1304     if (uidp->refCount == 0) {
1305         lupp = &uidp->vcp->usersp;
1306         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1307             if (up == uidp) 
1308                 break;
1309         }
1310         osi_assertx(up != NULL, "null smb_user_t");
1311         *lupp = up->nextp;
1312         lock_FinalizeMutex(&uidp->mx);
1313         unp = uidp->unp;
1314         smb_ReleaseVCNoLock(uidp->vcp);
1315         uidp->vcp = NULL;
1316         free(uidp);
1317     }           
1318     lock_ReleaseWrite(&smb_rctLock);
1319
1320     if (unp) {
1321         if (unp->userp)
1322             cm_ReleaseUserVCRef(unp->userp);
1323         smb_ReleaseUsername(unp);
1324     }
1325 }       
1326
1327 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1328 {
1329     cm_user_t *up = NULL;
1330
1331     if (!uidp)
1332         return NULL;
1333     
1334     lock_ObtainMutex(&uidp->mx);
1335     if (uidp->unp) {
1336         up = uidp->unp->userp;
1337         cm_HoldUser(up);
1338     }
1339     lock_ReleaseMutex(&uidp->mx);
1340
1341     return up;
1342 }
1343
1344
1345 /* retrieve a held reference to a user structure corresponding to an incoming
1346  * request.
1347  * corresponding release function is cm_ReleaseUser.
1348  */
1349 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1350 {
1351     smb_user_t *uidp;
1352     cm_user_t *up = NULL;
1353     smb_t *smbp;
1354
1355     smbp = (smb_t *) inp;
1356     uidp = smb_FindUID(vcp, smbp->uid, 0);
1357     if (!uidp)
1358         return NULL;
1359     
1360     up = smb_GetUserFromUID(uidp);
1361
1362     smb_ReleaseUID(uidp);
1363     return up;
1364 }
1365
1366 /*
1367  * Return a pointer to a pathname extracted from a TID structure.  The
1368  * TID structure is not held; assume it won't go away.
1369  */
1370 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1371 {
1372     smb_tid_t *tidp;
1373     long code = 0;
1374
1375     tidp = smb_FindTID(vcp, tid, 0);
1376     if (!tidp) {
1377         *treepath = NULL;
1378     } else {
1379         if (tidp->flags & SMB_TIDFLAG_IPC) {
1380             code = CM_ERROR_TIDIPC;
1381             /* tidp->pathname would be NULL, but that's fine */
1382         }
1383         *treepath = tidp->pathname;
1384         smb_ReleaseTID(tidp, FALSE);
1385     }
1386     return code;
1387 }
1388
1389 /* check to see if we have a chained fid, that is, a fid that comes from an
1390  * OpenAndX message that ran earlier in this packet.  In this case, the fid
1391  * field in a read, for example, request, isn't set, since the value is
1392  * supposed to be inherited from the openAndX call.
1393  */
1394 int smb_ChainFID(int fid, smb_packet_t *inp)
1395 {
1396     if (inp->fid == 0 || inp->inCount == 0) 
1397         return fid;
1398     else 
1399         return inp->fid;
1400 }
1401
1402 /* are we a priv'd user?  What does this mean on NT? */
1403 int smb_SUser(cm_user_t *userp)
1404 {
1405     return 1;
1406 }
1407
1408 /* find a file ID.  If we pass in 0 we select an unused File ID.
1409  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
1410  * smb_fid_t data structure if desired File ID cannot be found.
1411  */
1412 #ifdef DEBUG_SMB_REFCOUNT
1413 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1414 #else
1415 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1416 #endif
1417 {
1418     smb_fid_t *fidp;
1419     int newFid = 0;
1420         
1421     if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1422         return NULL;
1423
1424     lock_ObtainWrite(&smb_rctLock);
1425     /* figure out if we need to allocate a new file ID */
1426     if (fid == 0) {
1427         newFid = 1;
1428         fid = vcp->fidCounter;
1429     }
1430
1431   retry:
1432     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1433         if (fidp->refCount == 0 && fidp->deleteOk) {
1434             fidp->refCount++;
1435             lock_ReleaseWrite(&smb_rctLock);
1436             smb_ReleaseFID(fidp);
1437             lock_ObtainWrite(&smb_rctLock);
1438             goto retry;
1439         }
1440         if (fid == fidp->fid) {
1441             if (newFid) {
1442                 fid++;
1443                 if (fid == 0xFFFF) {
1444                     osi_Log1(smb_logp,
1445                              "New FID number wraps on vcp 0x%x", vcp);
1446                     fid = 1;
1447                 }
1448                 goto retry;
1449             }
1450             fidp->refCount++;
1451             break;
1452         }
1453     }
1454
1455     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1456         char eventName[MAX_PATH];
1457         EVENT_HANDLE event;
1458         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1459         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1460         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1461             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1462             thrd_CloseHandle(event);
1463             fid++;
1464             if (fid == 0xFFFF) {
1465                 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1466                 fid = 1;
1467             }
1468             goto retry;
1469         }
1470
1471         fidp = malloc(sizeof(*fidp));
1472         memset(fidp, 0, sizeof(*fidp));
1473         osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1474         fidp->refCount = 1;
1475         fidp->vcp = vcp;
1476         smb_HoldVCNoLock(vcp);
1477         lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1478         fidp->fid = fid;
1479         fidp->curr_chunk = fidp->prev_chunk = -2;
1480         fidp->raw_write_event = event;
1481         if (newFid) {
1482             vcp->fidCounter = fid+1;
1483             if (vcp->fidCounter == 0xFFFF) {
1484                 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1485                          vcp);
1486                 vcp->fidCounter = 1;
1487             }
1488         }
1489     }
1490
1491 #ifdef DEBUG_SMB_REFCOUNT
1492     if (fidp) {
1493         afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1494         osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1495     }
1496 #endif
1497     lock_ReleaseWrite(&smb_rctLock);
1498     return fidp;
1499 }
1500
1501
1502 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1503 #ifdef DEBUG_SMB_REFCOUNT
1504 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1505 #else
1506 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1507 #endif
1508 {
1509     smb_fid_t *fidp = NULL, *nextp = NULL;
1510         
1511     if (!scp)
1512         return NULL;
1513
1514     /* 
1515      * If the fidp->scp changes out from under us then
1516      * we must not grab a refCount.  It means the *fidp
1517      * was processed by smb_CloseFID() and the *fidp is 
1518      * no longer valid for use.
1519      */
1520     lock_ObtainWrite(&smb_rctLock);
1521         for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1522         nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1523         if (nextp)
1524             nextp->refCount++;
1525
1526         if (scp == fidp->scp) {
1527             lock_ReleaseWrite(&smb_rctLock);
1528             lock_ObtainMutex(&fidp->mx);
1529             lock_ObtainWrite(&smb_rctLock);
1530             if (scp == fidp->scp) {
1531                 lock_ReleaseMutex(&fidp->mx);
1532                 break;
1533             }
1534             lock_ReleaseMutex(&fidp->mx);
1535         }
1536
1537         if (fidp->refCount > 1) {
1538             fidp->refCount--;
1539         } else {
1540             lock_ReleaseWrite(&smb_rctLock);
1541             smb_ReleaseFID(fidp);
1542             lock_ObtainWrite(&smb_rctLock);
1543         }
1544     }
1545
1546     if (nextp) {
1547         if (nextp->refCount > 1) {
1548             nextp->refCount--;
1549         } else {
1550             lock_ReleaseWrite(&smb_rctLock);
1551             smb_ReleaseFID(nextp);
1552             lock_ObtainWrite(&smb_rctLock);
1553         }
1554     }
1555
1556 #ifdef DEBUG_SMB_REFCOUNT
1557     if (fidp) {
1558         afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1559         osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1560       }
1561 #endif
1562     lock_ReleaseWrite(&smb_rctLock);
1563     return (fidp);
1564 }
1565
1566 #ifdef DEBUG_SMB_REFCOUNT
1567 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1568 #else
1569 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1570 #endif
1571 {
1572     lock_AssertWrite(&smb_rctLock);
1573     fidp->refCount++;
1574 #ifdef DEBUG_SMB_REFCOUNT
1575     afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1576     osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1577 #endif
1578 }
1579
1580
1581 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1582 /* the smb_fid_t->mx and smb_rctLock must not be held */
1583 #ifdef DEBUG_SMB_REFCOUNT
1584 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1585 #else
1586 void smb_ReleaseFID(smb_fid_t *fidp)
1587 #endif
1588 {
1589     cm_scache_t *scp = NULL;
1590     cm_user_t *userp = NULL;
1591     smb_vc_t *vcp = NULL;
1592     smb_ioctl_t *ioctlp;
1593
1594     lock_ObtainMutex(&fidp->mx);
1595     lock_ObtainWrite(&smb_rctLock);
1596     osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1597 #ifdef DEBUG_SMB_REFCOUNT
1598     afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1599     osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1600 #endif
1601     if (fidp->refCount == 0) {
1602         if (fidp->deleteOk) {
1603             vcp = fidp->vcp;
1604             fidp->vcp = NULL;
1605             scp = fidp->scp;    /* release after lock is released */
1606             if (scp) {
1607                 lock_ObtainWrite(&scp->rw);
1608                 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1609                 lock_ReleaseWrite(&scp->rw);
1610                 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1611                 fidp->scp = NULL;
1612             }
1613             userp = fidp->userp;
1614             fidp->userp = NULL;
1615
1616             if (vcp->fidsp) 
1617                 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1618             thrd_CloseHandle(fidp->raw_write_event);
1619
1620             /* and see if there is ioctl stuff to free */
1621             ioctlp = fidp->ioctlp;
1622             if (ioctlp) {
1623                 if (ioctlp->prefix)
1624                 cm_FreeSpace(ioctlp->prefix);
1625                 if (ioctlp->ioctl.inAllocp)
1626                     free(ioctlp->ioctl.inAllocp);
1627                 if (ioctlp->ioctl.outAllocp)
1628                     free(ioctlp->ioctl.outAllocp);
1629                 free(ioctlp);
1630             }
1631
1632             smb_CleanupRPCFid(fidp);
1633
1634             lock_ReleaseMutex(&fidp->mx);
1635             lock_FinalizeMutex(&fidp->mx);
1636             free(fidp);
1637             fidp = NULL;
1638
1639             if (vcp)
1640                 smb_ReleaseVCNoLock(vcp);
1641         }
1642     }
1643     if (fidp)
1644         lock_ReleaseMutex(&fidp->mx);
1645
1646     lock_ReleaseWrite(&smb_rctLock);
1647
1648     /* now release the scache structure */
1649     if (scp) 
1650         cm_ReleaseSCache(scp);
1651
1652     if (userp)
1653         cm_ReleaseUser(userp);
1654 }       
1655
1656 /*
1657  * Case-insensitive search for one string in another;
1658  * used to find variable names in submount pathnames.
1659  */
1660 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1661 {
1662     clientchar_t *cursor;
1663
1664     for (cursor = str1; *cursor; cursor++)
1665         if (cm_ClientStrCmpI(cursor, str2) == 0)
1666             return cursor;
1667
1668     return NULL;
1669 }
1670
1671 /*
1672  * Substitute a variable value for its name in a submount pathname.  Variable
1673  * name has been identified by smb_stristr() and is in substr.  Variable name
1674  * length (plus one) is in substr_size.  Variable value is in newstr.
1675  */
1676 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1677                       unsigned int substr_size, clientchar_t *newstr)
1678 {
1679     clientchar_t temp[1024];
1680
1681     cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1682     cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1683     cm_ClientStrCat(str1, cchstr1, temp);
1684 }
1685
1686 clientchar_t VNUserName[] = _C("%USERNAME%");
1687 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1688 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1689 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1690
1691 typedef struct smb_findShare_rock {
1692     clientchar_t * shareName;
1693     clientchar_t * match;
1694     int matchType;
1695 } smb_findShare_rock_t;
1696
1697 #define SMB_FINDSHARE_EXACT_MATCH 1
1698 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1699
1700 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1701                        osi_hyper_t *offp)
1702 {
1703     int matchType = 0;
1704     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1705     normchar_t normName[MAX_PATH];
1706
1707     if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1708         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1709                  osi_LogSaveString(smb_logp, dep->name));
1710         return 0;
1711     }
1712
1713     if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1714         if(!cm_ClientStrCmpI(normName, vrock->shareName))
1715             matchType = SMB_FINDSHARE_EXACT_MATCH;
1716         else
1717             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1718         if(vrock->match) 
1719             free(vrock->match);
1720         vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1721         vrock->matchType = matchType;
1722
1723         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1724             return CM_ERROR_STOPNOW;
1725     }
1726     return 0;
1727 }
1728
1729
1730 /* find a shareName in the table of submounts */
1731 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1732                   clientchar_t *shareName,
1733                   clientchar_t **pathNamep)
1734 {
1735     DWORD cblen;
1736     DWORD cchlen;
1737     clientchar_t pathName[1024];
1738     clientchar_t *var;
1739     DWORD sizeTemp;
1740     clientchar_t *p, *q;
1741     fschar_t *cellname = NULL;
1742     HKEY parmKey;
1743     DWORD code;
1744     DWORD allSubmount = 1;
1745
1746     /* if allSubmounts == 0, only return the //mountRoot/all share 
1747      * if in fact it has been been created in the subMounts table.  
1748      * This is to allow sites that want to restrict access to the 
1749      * world to do so.
1750      */
1751     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1752                         0, KEY_QUERY_VALUE, &parmKey);
1753     if (code == ERROR_SUCCESS) {
1754         cblen = sizeof(allSubmount);
1755         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1756                                (BYTE *) &allSubmount, &cblen);
1757         if (code != ERROR_SUCCESS) {
1758             allSubmount = 1;
1759         }
1760         RegCloseKey (parmKey);
1761     }
1762
1763     if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1764         *pathNamep = NULL;
1765         return 1;
1766     }
1767
1768     /* In case, the all share is disabled we need to still be able
1769      * to handle ioctl requests 
1770      */
1771     if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1772         *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1773         return 1;
1774     }
1775
1776     if (MSRPC_IsWellKnownService(shareName) ||
1777         cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1778         cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1779         ) {
1780         *pathNamep = NULL;
1781         return 0;
1782     }
1783
1784     /* Check for volume references
1785      * 
1786      * They look like <cell>{%,#}<volume>
1787      */
1788     if (cm_ClientStrChr(shareName, '%') != NULL ||
1789         cm_ClientStrChr(shareName, '#') != NULL) {
1790         clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1791         /* make room for '/@vol:' + mountchar + NULL terminator*/
1792
1793         osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1794                  osi_LogSaveClientString(smb_logp, shareName));
1795
1796         cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1797                             _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1798         cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1799
1800         *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1801         if (*pathNamep) {
1802             cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1803             cm_ClientStrLwr(*pathNamep);
1804             osi_Log1(smb_logp, "   returning pathname [%S]",
1805                      osi_LogSaveClientString(smb_logp, *pathNamep));
1806
1807             return 1;
1808         } else {
1809             return 0;
1810         }
1811     }
1812
1813     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1814                         0, KEY_QUERY_VALUE, &parmKey);
1815     if (code == ERROR_SUCCESS) {
1816         cblen = sizeof(pathName);
1817         code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1818                                 (BYTE *) pathName, &cblen);
1819         if (code != ERROR_SUCCESS)
1820             cblen = 0;
1821         RegCloseKey (parmKey);
1822     } else {
1823         cblen = 0;
1824     }
1825     cchlen = cblen / sizeof(clientchar_t);
1826     if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1827         /* We can accept either unix or PC style AFS pathnames.  Convert
1828          * Unix-style to PC style here for internal use. 
1829          */
1830         p = pathName;
1831         cchlen = lengthof(pathName);
1832
1833         /* within this code block, we maintain, cchlen = writeable
1834            buffer length of p */
1835
1836         if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1837             p += cm_mountRootCLen;  /* skip mount path */
1838             cchlen -= (DWORD)(p - pathName);
1839         }
1840
1841         q = p;
1842         while (*q) {
1843             if (*q == _C('/')) *q = _C('\\');    /* change to \ */
1844             q++;
1845         }
1846
1847         while (1)
1848         {
1849             clientchar_t temp[1024];
1850
1851             if (var = smb_stristr(p, VNUserName)) {
1852                 if (uidp && uidp->unp)
1853                     smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1854                 else
1855                     smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1856             }
1857             else if (var = smb_stristr(p, VNLCUserName)) 
1858             {
1859                 if (uidp && uidp->unp)
1860                     cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1861                 else 
1862                     cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1863                 cm_ClientStrLwr(temp);
1864                 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1865             }
1866             else if (var = smb_stristr(p, VNComputerName)) 
1867             {
1868                 sizeTemp = lengthof(temp);
1869                 GetComputerNameW(temp, &sizeTemp);
1870                 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1871             }
1872             else if (var = smb_stristr(p, VNLCComputerName)) 
1873             {
1874                 sizeTemp = lengthof(temp);
1875                 GetComputerName((LPTSTR)temp, &sizeTemp);
1876                 cm_ClientStrLwr(temp);
1877                 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1878             }
1879             else     
1880                 break;
1881         }
1882         *pathNamep = cm_ClientStrDup(p);
1883         return 1;
1884     } 
1885     else
1886     {
1887         /* First lookup shareName in root.afs */
1888         cm_req_t req;
1889         smb_findShare_rock_t vrock;
1890         osi_hyper_t thyper;
1891         fschar_t ftemp[1024];
1892         clientchar_t * p = shareName; 
1893         int rw = 0;
1894
1895         /*  attempt to locate a partial match in root.afs.  This is because
1896             when using the ANSI RAP calls, the share name is limited to 13 chars
1897             and hence is truncated. Of course we prefer exact matches. */
1898         smb_InitReq(&req);
1899         thyper.HighPart = 0;
1900         thyper.LowPart = 0;
1901
1902         vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1903         if (vrock.shareName == NULL) 
1904             return 0;
1905         vrock.match = NULL;
1906         vrock.matchType = 0;
1907
1908         cm_HoldSCache(cm_data.rootSCachep);
1909         code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1910                            (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1911         cm_ReleaseSCache(cm_data.rootSCachep);
1912
1913         free(vrock.shareName);
1914         vrock.shareName = NULL;
1915
1916         if (vrock.matchType) {
1917             cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1918             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1919             free(vrock.match);
1920             return 1;
1921         }
1922
1923         /* if we get here, there was no match for the share in root.afs */
1924         /* so try to create  \\<netbiosName>\<cellname>  */
1925         if ( *p == '.' ) {
1926             p++;
1927             rw = 1;
1928         }
1929         /* Get the full name for this cell */
1930         cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1931         code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
1932         if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
1933             code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1934 #ifdef AFS_AFSDB_ENV
1935         if (code && cm_dnsEnabled) {
1936             int ttl;
1937             code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1938         }
1939 #endif
1940         if (cellname)
1941             free(cellname);
1942
1943         /* construct the path */
1944         if (code == 0) {
1945             clientchar_t temp[1024];
1946
1947             if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
1948             cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
1949                                 rw ? _C("/.%S/") : _C("/%S/"), temp);
1950             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1951             return 1;
1952         }
1953     }
1954     }
1955     /* failure */
1956     *pathNamep = NULL;
1957     return 0;
1958 }
1959
1960 /* Client-side offline caching policy types */
1961 #define CSC_POLICY_MANUAL 0
1962 #define CSC_POLICY_DOCUMENTS 1
1963 #define CSC_POLICY_PROGRAMS 2
1964 #define CSC_POLICY_DISABLE 3
1965
1966 int smb_FindShareCSCPolicy(clientchar_t *shareName)
1967 {
1968     DWORD len;
1969     clientchar_t policy[1024];
1970     DWORD dwType;
1971     HKEY hkCSCPolicy;
1972     int  retval = CSC_POLICY_MANUAL;
1973
1974     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
1975                     AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1976                     0, 
1977                     "AFS", 
1978                     REG_OPTION_NON_VOLATILE,
1979                     KEY_READ,
1980                     NULL, 
1981                     &hkCSCPolicy,
1982                     NULL );
1983
1984     len = sizeof(policy);
1985     if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
1986          len == 0) {
1987         retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1988     }
1989     else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
1990     {
1991         retval = CSC_POLICY_DOCUMENTS;
1992     }
1993     else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
1994     {
1995         retval = CSC_POLICY_PROGRAMS;
1996     }
1997     else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
1998     {
1999         retval = CSC_POLICY_DISABLE;
2000     }
2001         
2002     RegCloseKey(hkCSCPolicy);
2003     return retval;
2004 }
2005
2006 /* find a dir search structure by cookie value, and return it held.
2007  * Must be called with smb_globalLock held.
2008  */
2009 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2010 {
2011     smb_dirSearch_t *dsp;
2012         
2013     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2014         if (dsp->cookie == cookie) {
2015             if (dsp != smb_firstDirSearchp) {
2016                 /* move to head of LRU queue, too, if we're not already there */
2017                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2018                     smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2019                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2020                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2021                 if (!smb_lastDirSearchp)
2022                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2023             }
2024             dsp->refCount++;
2025             break;
2026         }
2027     }
2028
2029     if (dsp == NULL) {
2030         osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2031         for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2032             osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2033         }
2034     }
2035     return dsp;
2036 }       
2037
2038 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2039 {
2040     lock_ObtainMutex(&dsp->mx);
2041     osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p", 
2042               dsp->cookie, dsp, dsp->scp);
2043     dsp->flags |= SMB_DIRSEARCH_DELETE;
2044     if (dsp->scp != NULL) {
2045         lock_ObtainWrite(&dsp->scp->rw);
2046         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2047             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2048             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2049             dsp->scp->bulkStatProgress = hzero;
2050         }       
2051         lock_ReleaseWrite(&dsp->scp->rw);
2052     }   
2053     lock_ReleaseMutex(&dsp->mx);
2054 }               
2055
2056 /* Must be called with the smb_globalLock held */
2057 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2058 {
2059     cm_scache_t *scp = NULL;
2060
2061     osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2062     if (dsp->refCount == 0) {
2063         lock_ObtainMutex(&dsp->mx);
2064         if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2065             if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2066                 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2067             osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2068             lock_ReleaseMutex(&dsp->mx);
2069             lock_FinalizeMutex(&dsp->mx);
2070             scp = dsp->scp;
2071             osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
2072                      dsp->cookie, dsp, scp);
2073             free(dsp);
2074         } else {
2075             lock_ReleaseMutex(&dsp->mx);
2076         }
2077     }
2078     /* do this now to avoid spurious locking hierarchy creation */
2079     if (scp) 
2080         cm_ReleaseSCache(scp);
2081 }       
2082
2083 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2084 {
2085     lock_ObtainWrite(&smb_globalLock);
2086     smb_ReleaseDirSearchNoLock(dsp);
2087     lock_ReleaseWrite(&smb_globalLock);
2088 }       
2089
2090 /* find a dir search structure by cookie value, and return it held */
2091 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2092 {
2093     smb_dirSearch_t *dsp;
2094
2095     lock_ObtainWrite(&smb_globalLock);
2096     dsp = smb_FindDirSearchNoLock(cookie);
2097     lock_ReleaseWrite(&smb_globalLock);
2098     return dsp;
2099 }
2100
2101 /* GC some dir search entries, in the address space expected by the specific protocol.
2102  * Must be called with smb_globalLock held; release the lock temporarily.
2103  */
2104 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
2105 void smb_GCDirSearches(int isV3)
2106 {
2107     smb_dirSearch_t *prevp;
2108     smb_dirSearch_t *dsp;
2109     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2110     int victimCount;
2111     int i;
2112         
2113     victimCount = 0;    /* how many have we got so far */
2114     for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2115         /* we'll move tp from queue, so
2116          * do this early.
2117          */
2118         prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q); 
2119         /* if no one is using this guy, and we're either in the new protocol,
2120          * or we're in the old one and this is a small enough ID to be useful
2121          * to the old protocol, GC this guy.
2122          */
2123         if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2124             /* hold and delete */
2125             lock_ObtainMutex(&dsp->mx);
2126             dsp->flags |= SMB_DIRSEARCH_DELETE;
2127             lock_ReleaseMutex(&dsp->mx);
2128             victimsp[victimCount++] = dsp;
2129             dsp->refCount++;
2130         }
2131
2132         /* don't do more than this */
2133         if (victimCount >= SMB_DIRSEARCH_GCMAX) 
2134             break;
2135     }
2136         
2137     /* now release them */
2138     for (i = 0; i < victimCount; i++) {
2139         smb_ReleaseDirSearchNoLock(victimsp[i]);
2140     }
2141 }
2142
2143 /* function for allocating a dir search entry.  We need these to remember enough context
2144  * since we don't get passed the path from call to call during a directory search.
2145  *
2146  * Returns a held dir search structure, and bumps the reference count on the vnode,
2147  * since it saves a pointer to the vnode.
2148  */
2149 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2150 {
2151     smb_dirSearch_t *dsp;
2152     int counter;
2153     int maxAllowed;
2154     int start;
2155     int wrapped = 0;
2156
2157     lock_ObtainWrite(&smb_globalLock);
2158     counter = 0;
2159
2160     /* what's the biggest ID allowed in this version of the protocol */
2161     /* TODO: do we really want a non v3 dir search request to wrap
2162        smb_dirSearchCounter? */
2163     maxAllowed = isV3 ? 65535 : 255;
2164     if (smb_dirSearchCounter > maxAllowed)
2165         smb_dirSearchCounter = 1;
2166
2167     start = smb_dirSearchCounter;
2168
2169     while (1) {
2170         /* twice so we have enough tries to find guys we GC after one pass;
2171          * 10 extra is just in case I mis-counted.
2172          */
2173         if (++counter > 2*maxAllowed+10) 
2174             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2175
2176         if (smb_dirSearchCounter > maxAllowed) {        
2177             smb_dirSearchCounter = 1;
2178         }
2179         if (smb_dirSearchCounter == start) {
2180             if (wrapped)
2181                 smb_GCDirSearches(isV3);
2182             wrapped++;
2183         }
2184         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2185         if (dsp) {
2186             /* don't need to watch for refcount zero and deleted, since
2187             * we haven't dropped the global lock.
2188             */
2189             dsp->refCount--;
2190             ++smb_dirSearchCounter;
2191             continue;
2192         }       
2193
2194         dsp = malloc(sizeof(*dsp));
2195         memset(dsp, 0, sizeof(*dsp));
2196         dsp->cookie = smb_dirSearchCounter;
2197         ++smb_dirSearchCounter;
2198         dsp->refCount = 1;
2199         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2200         dsp->lastTime = osi_Time();
2201         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2202         if (!smb_lastDirSearchp) 
2203             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2204     
2205         osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p", 
2206                  dsp->cookie, dsp);
2207         break;
2208     }   
2209     lock_ReleaseWrite(&smb_globalLock);
2210     return dsp;
2211 }
2212
2213 static smb_packet_t *smb_GetPacket(void)
2214 {
2215     smb_packet_t *tbp;
2216
2217     lock_ObtainWrite(&smb_globalLock);
2218     tbp = smb_packetFreeListp;
2219     if (tbp) 
2220         smb_packetFreeListp = tbp->nextp;
2221     lock_ReleaseWrite(&smb_globalLock);
2222     if (!tbp) {
2223         tbp = calloc(sizeof(*tbp),1);
2224         tbp->magic = SMB_PACKETMAGIC;
2225         tbp->ncbp = NULL;
2226         tbp->vcp = NULL;
2227         tbp->resumeCode = 0;
2228         tbp->inCount = 0;
2229         tbp->fid = 0;
2230         tbp->wctp = NULL;
2231         tbp->inCom = 0;
2232         tbp->oddByte = 0;
2233         tbp->ncb_length = 0;
2234         tbp->flags = 0;
2235         tbp->spacep = NULL;
2236         tbp->stringsp = NULL;
2237     }
2238     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2239
2240     return tbp;
2241 }
2242
2243 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2244 {
2245     smb_packet_t *tbp;
2246     tbp = smb_GetPacket();
2247     memcpy(tbp, pkt, sizeof(smb_packet_t));
2248     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2249     tbp->stringsp = NULL;
2250     if (tbp->vcp)
2251         smb_HoldVC(tbp->vcp);
2252     return tbp;
2253 }
2254
2255 static NCB *smb_GetNCB(void)
2256 {
2257     smb_ncb_t *tbp;
2258     NCB *ncbp;
2259
2260     lock_ObtainWrite(&smb_globalLock);
2261     tbp = smb_ncbFreeListp;
2262     if (tbp) 
2263         smb_ncbFreeListp = tbp->nextp;
2264     lock_ReleaseWrite(&smb_globalLock);
2265     if (!tbp) {
2266         tbp = calloc(sizeof(*tbp),1);
2267         tbp->magic = SMB_NCBMAGIC;
2268     }
2269         
2270     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2271
2272     memset(&tbp->ncb, 0, sizeof(NCB));
2273     ncbp = &tbp->ncb;
2274     return ncbp;
2275 }
2276
2277 static void FreeSMBStrings(smb_packet_t * pkt)
2278 {
2279     cm_space_t * s;
2280     cm_space_t * ns;
2281
2282     for (s = pkt->stringsp; s; s = ns) {
2283         ns = s->nextp;
2284         cm_FreeSpace(s);
2285     }
2286     pkt->stringsp = NULL;
2287 }
2288
2289 void smb_FreePacket(smb_packet_t *tbp)
2290 {
2291     smb_vc_t * vcp = NULL;
2292     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2293         
2294     lock_ObtainWrite(&smb_globalLock);
2295     tbp->nextp = smb_packetFreeListp;
2296     smb_packetFreeListp = tbp;
2297     tbp->magic = SMB_PACKETMAGIC;
2298     tbp->ncbp = NULL;
2299     vcp = tbp->vcp;
2300     tbp->vcp = NULL;
2301     tbp->resumeCode = 0;
2302     tbp->inCount = 0;
2303     tbp->fid = 0;
2304     tbp->wctp = NULL;
2305     tbp->inCom = 0;
2306     tbp->oddByte = 0;
2307     tbp->ncb_length = 0;
2308     tbp->flags = 0;
2309     FreeSMBStrings(tbp);
2310     lock_ReleaseWrite(&smb_globalLock);
2311
2312     if (vcp)
2313         smb_ReleaseVC(vcp);
2314 }
2315
2316 static void smb_FreeNCB(NCB *bufferp)
2317 {
2318     smb_ncb_t *tbp;
2319         
2320     tbp = (smb_ncb_t *) bufferp;
2321     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2322         
2323     lock_ObtainWrite(&smb_globalLock);
2324     tbp->nextp = smb_ncbFreeListp;
2325     smb_ncbFreeListp = tbp;
2326     lock_ReleaseWrite(&smb_globalLock);
2327 }
2328
2329 /* get a ptr to the data part of a packet, and its count */
2330 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2331 {
2332     int parmBytes;
2333     int dataBytes;
2334     unsigned char *afterParmsp;
2335
2336     parmBytes = *smbp->wctp << 1;
2337     afterParmsp = smbp->wctp + parmBytes + 1;
2338         
2339     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2340     if (nbytesp) *nbytesp = dataBytes;
2341         
2342     /* don't forget to skip the data byte count, since it follows
2343      * the parameters; that's where the "2" comes from below.
2344      */
2345     return (unsigned char *) (afterParmsp + 2);
2346 }
2347
2348 /* must set all the returned parameters before playing around with the
2349  * data region, since the data region is located past the end of the
2350  * variable number of parameters.
2351  */
2352 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2353 {
2354     unsigned char *afterParmsp;
2355
2356     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2357         
2358     *afterParmsp++ = dsize & 0xff;
2359     *afterParmsp = (dsize>>8) & 0xff;
2360 }       
2361
2362 /* return the parm'th parameter in the smbp packet */
2363 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2364 {
2365     int parmCount;
2366     unsigned char *parmDatap;
2367
2368     parmCount = *smbp->wctp;
2369
2370     if (parm >= parmCount) {
2371         char s[100];
2372
2373         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2374                 parm, parmCount, smbp->ncb_length);
2375         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2376                  parm, parmCount, smbp->ncb_length);
2377         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2378                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2379         osi_panic(s, __FILE__, __LINE__);
2380     }
2381     parmDatap = smbp->wctp + (2*parm) + 1;
2382         
2383     return parmDatap[0] + (parmDatap[1] << 8);
2384 }
2385
2386 /* return the parm'th parameter in the smbp packet */
2387 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2388 {
2389     int parmCount;
2390     unsigned char *parmDatap;
2391
2392     parmCount = *smbp->wctp;
2393
2394     if (parm >= parmCount) {
2395         char s[100];
2396
2397         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2398                 parm, parmCount, smbp->ncb_length);
2399         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2400                  parm, parmCount, smbp->ncb_length);
2401         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2402                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2403         osi_panic(s, __FILE__, __LINE__);
2404     }
2405     parmDatap = smbp->wctp + (2*parm) + 1;
2406         
2407     return parmDatap[0];
2408 }
2409
2410 /* return the parm'th parameter in the smbp packet */
2411 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2412 {
2413     int parmCount;
2414     unsigned char *parmDatap;
2415
2416     parmCount = *smbp->wctp;
2417
2418     if (parm + 1 >= parmCount) {
2419         char s[100];
2420
2421         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2422                 parm, parmCount, smbp->ncb_length);
2423         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2424                  parm, parmCount, smbp->ncb_length);
2425         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2426                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2427         osi_panic(s, __FILE__, __LINE__);
2428     }
2429     parmDatap = smbp->wctp + (2*parm) + 1;
2430         
2431     return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2432 }
2433
2434 /* return the parm'th parameter in the smbp packet */
2435 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2436 {
2437     int parmCount;
2438     unsigned char *parmDatap;
2439
2440     parmCount = *smbp->wctp;
2441
2442     if (parm * 2 + offset >= parmCount * 2) {
2443         char s[100];
2444
2445         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2446                 parm, offset, parmCount, smbp->ncb_length);
2447         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
2448                  __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2449         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2450                 parm, offset, parmCount, smbp->ncb_length);
2451         osi_panic(s, __FILE__, __LINE__);
2452     }
2453     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2454         
2455     return parmDatap[0] + (parmDatap[1] << 8);
2456 }
2457
2458 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2459 {
2460     unsigned char *parmDatap;
2461
2462     /* make sure we have enough slots */
2463     if (*smbp->wctp <= slot) 
2464         *smbp->wctp = slot+1;
2465         
2466     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2467     *parmDatap++ = parmValue & 0xff;
2468     *parmDatap = (parmValue>>8) & 0xff;
2469 }       
2470
2471 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2472 {
2473     unsigned char *parmDatap;
2474
2475     /* make sure we have enough slots */
2476     if (*smbp->wctp <= slot) 
2477         *smbp->wctp = slot+2;
2478
2479     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2480     *parmDatap++ = parmValue & 0xff;
2481     *parmDatap++ = (parmValue>>8) & 0xff;
2482     *parmDatap++ = (parmValue>>16) & 0xff;
2483     *parmDatap   = (parmValue>>24) & 0xff;
2484 }
2485
2486 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2487 {
2488     unsigned char *parmDatap;
2489     int i;
2490
2491     /* make sure we have enough slots */
2492     if (*smbp->wctp <= slot) 
2493         *smbp->wctp = slot+4;
2494
2495     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2496     for (i=0; i<8; i++)
2497         *parmDatap++ = *parmValuep++;
2498 }       
2499
2500 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2501 {
2502     unsigned char *parmDatap;
2503
2504     /* make sure we have enough slots */
2505     if (*smbp->wctp <= slot) {
2506         if (smbp->oddByte) {
2507             smbp->oddByte = 0;
2508             *smbp->wctp = slot+1;
2509         } else
2510             smbp->oddByte = 1;
2511     }
2512
2513     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2514     *parmDatap++ = parmValue & 0xff;
2515 }
2516
2517
2518
2519 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2520                             clientchar_t *inPathp)
2521 {
2522     clientchar_t *lastSlashp;
2523     clientchar_t *streamp = NULL;
2524     clientchar_t *typep = NULL;
2525
2526     lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2527     if (lastComponentp) {
2528         *lastComponentp = lastSlashp;
2529     }
2530     if (lastSlashp) {
2531         /*
2532          * If the name contains a stream name and a type
2533          * and the stream name is the nul-string and the
2534          * type is $DATA, then strip "::$DATA" from the
2535          * last component string that is returned.
2536          *
2537          * Otherwise, return the full path name and allow
2538          * the file name to be rejected because it contains
2539          * a colon.
2540          */
2541         typep = cm_ClientStrRChr(lastSlashp, L':');
2542         if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2543             *typep = '\0';
2544             streamp = cm_ClientStrRChr(lastSlashp, L':');
2545             if (streamp && cm_ClientStrCmpI(streamp, L":") == 0)
2546                 *streamp = '\0';
2547             else
2548                 *typep = ':';
2549         }
2550
2551         while (1) {
2552             if (inPathp == lastSlashp) 
2553                 break;
2554             *outPathp++ = *inPathp++;
2555         }
2556         *outPathp++ = 0;
2557     }
2558     else {
2559         *outPathp++ = 0;
2560     }
2561 }
2562
2563 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2564                                   char **chainpp, int flags)
2565 {
2566     size_t cb;
2567     afs_uint32 type = *inp++;
2568
2569     /* 
2570      * The first byte specifies the type of the input string.
2571      * CIFS TR 1.0 3.2.10.  This function only parses null terminated
2572      * strings.
2573      */
2574     switch (type) {
2575     /* Length Counted */
2576     case 0x1: /* Data Block */
2577     case 0x5: /* Variable Block */
2578         cb = *inp++ << 16 | *inp++;
2579         break;
2580
2581     /* Null-terminated string */
2582     case 0x4: /* ASCII */
2583     case 0x3: /* Pathname */
2584     case 0x2: /* Dialect */
2585         cb = sizeof(pktp->data) - (inp - pktp->data);
2586         if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2587 #ifdef DEBUG_UNICODE
2588             DebugBreak();
2589 #endif
2590             cb = sizeof(pktp->data);
2591         }
2592         break;
2593
2594     default:
2595         return NULL;            /* invalid input */
2596     }
2597
2598 #ifdef SMB_UNICODE
2599     if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2600         flags |= SMB_STRF_FORCEASCII;
2601 #endif
2602
2603     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2604 }
2605
2606 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2607                               char ** chainpp, int flags)
2608 {
2609     size_t cb;
2610
2611 #ifdef SMB_UNICODE
2612     if (!WANTS_UNICODE(pktp))
2613         flags |= SMB_STRF_FORCEASCII;
2614 #endif
2615
2616     cb = sizeof(pktp->data) - (inp - pktp->data);
2617     if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2618 #ifdef DEBUG_UNICODE
2619         DebugBreak();
2620 #endif
2621         cb = sizeof(pktp->data);
2622     }
2623     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2624                               flags | SMB_STRF_SRCNULTERM);
2625 }
2626
2627 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2628                                 size_t cb, char ** chainpp, int flags)
2629 {
2630 #ifdef SMB_UNICODE
2631     if (!WANTS_UNICODE(pktp))
2632         flags |= SMB_STRF_FORCEASCII;
2633 #endif
2634
2635     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2636 }
2637
2638 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2639                                  size_t cch, char ** chainpp, int flags)
2640 {
2641     size_t cb = cch;
2642
2643 #ifdef SMB_UNICODE
2644     if (!WANTS_UNICODE(pktp))
2645         flags |= SMB_STRF_FORCEASCII;
2646     else
2647         cb = cch * sizeof(wchar_t);
2648 #endif
2649
2650     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2651 }
2652
2653 clientchar_t *
2654 smb_ParseStringBuf(const unsigned char * bufbase,
2655                    cm_space_t ** stringspp,
2656                    unsigned char *inp, size_t *pcb_max,
2657                    char **chainpp, int flags)
2658 {
2659 #ifdef SMB_UNICODE
2660     if (!(flags & SMB_STRF_FORCEASCII)) {
2661         size_t cch_src;
2662         cm_space_t * spacep;
2663         int    null_terms = 0;
2664
2665         if (bufbase && ((inp - bufbase) % 2) != 0) {
2666             inp++;              /* unicode strings are always word aligned */
2667         }
2668
2669         if (*pcb_max > 0) {
2670             if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2671                                         &cch_src))) {
2672                 cch_src = *pcb_max / sizeof(wchar_t);
2673                 *pcb_max = 0;
2674                 null_terms = 0;
2675             } else {
2676                 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2677                 null_terms = 1;
2678             }
2679         } else {
2680             cch_src = 0;
2681         }
2682
2683         spacep = cm_GetSpace();
2684         spacep->nextp = *stringspp;
2685         *stringspp = spacep;
2686
2687         if (cch_src == 0) {
2688             if (chainpp) {
2689                 *chainpp = inp + sizeof(wchar_t);
2690             }
2691
2692             *(spacep->wdata) = 0;
2693             return spacep->wdata;
2694         }
2695
2696         StringCchCopyNW(spacep->wdata,
2697                         lengthof(spacep->wdata),
2698                         (const clientchar_t *) inp, cch_src);
2699
2700         if (chainpp)
2701             *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2702
2703         return spacep->wdata;
2704
2705     } else {
2706 #endif
2707         cm_space_t * spacep;
2708         int cchdest;
2709
2710         /* Not using Unicode */
2711         if (chainpp) {
2712             *chainpp = inp + strlen(inp) + 1;
2713         }
2714
2715         spacep = cm_GetSpace();
2716         spacep->nextp = *stringspp;
2717         *stringspp = spacep;
2718
2719         cchdest = lengthof(spacep->wdata);
2720         cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2721                        spacep->wdata, cchdest);
2722
2723         return spacep->wdata;
2724 #ifdef SMB_UNICODE
2725     }
2726 #endif
2727 }
2728
2729 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2730                             clientchar_t * str,
2731                             size_t * plen, int flags)
2732 {
2733     size_t buffersize;
2734     int align = 0;
2735
2736     if (outp == NULL) {
2737         /* we are only calculating the required size */
2738
2739         if (plen == NULL)
2740             return NULL;
2741
2742 #ifdef SMB_UNICODE
2743
2744         if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2745
2746             StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2747             if (!(flags & SMB_STRF_IGNORENUL))
2748                 *plen += sizeof(wchar_t);
2749
2750             return (unsigned char *) 1; /* return TRUE if we are using unicode */
2751         }
2752         else
2753 #endif
2754         {
2755             /* Storing ANSI */
2756
2757             size_t cch_str;
2758             size_t cch_dest;
2759
2760             cch_str = cm_ClientStrLen(str);
2761             cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2762
2763             if (plen)
2764                 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2765
2766             return NULL;
2767         }
2768
2769         /* Not reached. */
2770     }
2771
2772     /* if outp != NULL ... */
2773
2774     /* Number of bytes left in the buffer.
2775
2776        If outp lies inside the packet data buffer, we assume that the
2777        buffer is the packet data buffer.  Otherwise we assume that the
2778        buffer is sizeof(packet->data).
2779
2780     */
2781     if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2782         align = (int)((outp - pktp->data) % 2);
2783         buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2784     } else {
2785         align = (int)(((size_t) outp) % 2);
2786         buffersize = (int)sizeof(pktp->data);
2787     }
2788
2789 #ifdef SMB_UNICODE
2790
2791     if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2792         int nchars;
2793
2794         if (align)
2795             *outp++ = '\0';
2796
2797         if (*str == _C('\0')) {
2798
2799             if (buffersize < sizeof(wchar_t))
2800                 return NULL;
2801
2802             *((wchar_t *) outp) = L'\0';
2803             if (plen && !(flags & SMB_STRF_IGNORENUL))
2804                 *plen += sizeof(wchar_t);
2805             return outp + sizeof(wchar_t);
2806         }
2807
2808         nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2809         if (nchars == 0) {
2810             osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2811                      osi_LogSaveClientString(smb_logp, str),
2812                      GetLastError());
2813             return NULL;
2814         }
2815
2816         if (plen)
2817             *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2818
2819         return outp + sizeof(wchar_t) * nchars;
2820     }
2821     else
2822 #endif
2823     {
2824         /* Storing ANSI */
2825         size_t cch_dest;
2826
2827         cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2828
2829         if (plen)
2830             *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2831
2832         return outp + cch_dest;
2833     }
2834 }
2835
2836 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2837 {
2838     int tlen;
2839
2840     if (*inp++ != 0x5) 
2841         return NULL;
2842     tlen = inp[0] + (inp[1]<<8);
2843     inp += 2;           /* skip length field */
2844
2845     if (chainpp) {
2846         *chainpp = inp + tlen;
2847     }
2848         
2849     if (lengthp) 
2850         *lengthp = tlen;
2851         
2852     return inp;
2853 }       
2854
2855 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2856 {
2857     int tlen;
2858
2859     if (*inp++ != 0x1) return NULL;
2860     tlen = inp[0] + (inp[1]<<8);
2861     inp += 2;           /* skip length field */
2862         
2863     if (chainpp) {
2864         *chainpp = inp + tlen;
2865     }   
2866
2867     if (lengthp) *lengthp = tlen;
2868         
2869     return inp;
2870 }
2871
2872 /* format a packet as a response */
2873 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2874 {
2875     smb_t *outp;
2876     smb_t *inSmbp;
2877
2878     outp = (smb_t *) op;
2879         
2880     /* zero the basic structure through the smb_wct field, and zero the data
2881      * size field, assuming that wct stays zero; otherwise, you have to 
2882      * explicitly set the data size field, too.
2883      */
2884     inSmbp = (smb_t *) inp;
2885     memset(outp, 0, sizeof(smb_t)+2);
2886     outp->id[0] = 0xff;
2887     outp->id[1] = 'S';
2888     outp->id[2] = 'M';
2889     outp->id[3] = 'B';
2890     if (inp) {
2891         outp->com = inSmbp->com;
2892         outp->tid = inSmbp->tid;
2893         outp->pid = inSmbp->pid;
2894         outp->uid = inSmbp->uid;
2895         outp->mid = inSmbp->mid;
2896         outp->res[0] = inSmbp->res[0];
2897         outp->res[1] = inSmbp->res[1];
2898         op->inCom = inSmbp->com;
2899     }
2900     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2901 #ifdef SEND_CANONICAL_PATHNAMES
2902     outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2903 #endif
2904     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2905 #ifdef SMB_UNICODE
2906     if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2907         outp->flg2 |= SMB_FLAGS2_UNICODE;
2908 #endif
2909
2910     /* copy fields in generic packet area */
2911     op->wctp = &outp->wct;
2912 }       
2913
2914 /* send a (probably response) packet; vcp tells us to whom to send it.
2915  * we compute the length by looking at wct and bcc fields.
2916  */
2917 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2918 {
2919     NCB *ncbp;
2920     int extra;
2921     long code = 0;
2922     unsigned char *tp;
2923     int localNCB = 0;
2924         
2925     ncbp = inp->ncbp;
2926     if (ncbp == NULL) {
2927         ncbp = smb_GetNCB();
2928         localNCB = 1;
2929     }
2930  
2931     memset((char *)ncbp, 0, sizeof(NCB));
2932
2933     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
2934     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
2935     extra += tp[0] + (tp[1]<<8);
2936     extra += (unsigned int)(inp->wctp - inp->data);     /* distance to last wct field */
2937     extra += 3;                 /* wct and length fields */
2938         
2939     ncbp->ncb_length = extra;   /* bytes to send */
2940     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
2941     ncbp->ncb_lana_num = vcp->lana;
2942     ncbp->ncb_command = NCBSEND;        /* op means send data */
2943     ncbp->ncb_buffer = (char *) inp;/* packet */
2944     code = Netbios(ncbp);
2945         
2946     if (code != 0) {
2947         const char * s = ncb_error_string(code);
2948         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2949         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2950
2951         lock_ObtainMutex(&vcp->mx);
2952         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2953             osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2954                       vcp, vcp->usersp);
2955             vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2956             lock_ReleaseMutex(&vcp->mx);
2957             lock_ObtainWrite(&smb_globalLock);
2958             dead_sessions[vcp->session] = TRUE;
2959             lock_ReleaseWrite(&smb_globalLock);
2960             smb_CleanupDeadVC(vcp);
2961         } else {
2962             lock_ReleaseMutex(&vcp->mx);
2963         }
2964     }
2965
2966     if (localNCB)
2967         smb_FreeNCB(ncbp);
2968 }
2969
2970 void smb_MapNTError(long code, unsigned long *NTStatusp)
2971 {
2972     unsigned long NTStatus;
2973
2974     /* map CM_ERROR_* errors to NT 32-bit status codes */
2975     /* NT Status codes are listed in ntstatus.h not winerror.h */
2976     if (code == 0) {
2977         NTStatus = 0;
2978     } 
2979     else if (code == CM_ERROR_NOSUCHCELL) {
2980         NTStatus = 0xC000000FL; /* No such file */
2981     }
2982     else if (code == CM_ERROR_NOSUCHVOLUME) {
2983         NTStatus = 0xC000000FL; /* No such file */
2984     }
2985     else if (code == CM_ERROR_TIMEDOUT) {
2986 #ifdef COMMENT
2987         NTStatus = 0xC00000CFL; /* Sharing Paused */
2988 #else
2989         NTStatus = 0x00000102L; /* Timeout */
2990 #endif
2991     }
2992     else if (code == CM_ERROR_RETRY) {
2993         NTStatus = 0xC000022DL; /* Retry */
2994     }
2995     else if (code == CM_ERROR_NOACCESS) {
2996         NTStatus = 0xC0000022L; /* Access denied */
2997     }
2998     else if (code == CM_ERROR_READONLY) {
2999         NTStatus = 0xC00000A2L; /* Write protected */
3000     }
3001     else if (code == CM_ERROR_NOSUCHFILE ||
3002              code == CM_ERROR_BPLUS_NOMATCH) {
3003         NTStatus = 0xC000000FL; /* No such file */
3004     }
3005     else if (code == CM_ERROR_NOSUCHPATH) {
3006         NTStatus = 0xC000003AL; /* Object path not found */
3007     }           
3008     else if (code == CM_ERROR_TOOBIG) {
3009         NTStatus = 0xC000007BL; /* Invalid image format */
3010     }
3011     else if (code == CM_ERROR_INVAL) {
3012         NTStatus = 0xC000000DL; /* Invalid parameter */
3013     }
3014     else if (code == CM_ERROR_BADFD) {
3015         NTStatus = 0xC0000008L; /* Invalid handle */
3016     }
3017     else if (code == CM_ERROR_BADFDOP) {
3018         NTStatus = 0xC0000022L; /* Access denied */
3019     }
3020     else if (code == CM_ERROR_EXISTS) {
3021         NTStatus = 0xC0000035L; /* Object name collision */
3022     }
3023     else if (code == CM_ERROR_NOTEMPTY) {
3024         NTStatus = 0xC0000101L; /* Directory not empty */
3025     }   
3026     else if (code == CM_ERROR_CROSSDEVLINK) {
3027         NTStatus = 0xC00000D4L; /* Not same device */
3028     }
3029     else if (code == CM_ERROR_NOTDIR) {
3030         NTStatus = 0xC0000103L; /* Not a directory */
3031     }
3032     else if (code == CM_ERROR_ISDIR) {
3033         NTStatus = 0xC00000BAL; /* File is a directory */
3034     }
3035     else if (code == CM_ERROR_BADOP) {
3036 #ifdef COMMENT
3037         /* I have no idea where this comes from */
3038         NTStatus = 0xC09820FFL; /* SMB no support */
3039 #else
3040         NTStatus = 0xC00000BBL;     /* Not supported */
3041 #endif /* COMMENT */
3042     }
3043     else if (code == CM_ERROR_BADSHARENAME) {
3044         NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3045     }
3046     else if (code == CM_ERROR_NOIPC) {
3047 #ifdef COMMENT
3048         NTStatus = 0xC0000022L; /* Access Denied */
3049 #else   
3050         NTStatus = 0xC000013DL; /* Remote Resources */
3051 #endif
3052     }
3053     else if (code == CM_ERROR_CLOCKSKEW) {
3054         NTStatus = 0xC0000133L; /* Time difference at DC */
3055     }
3056     else if (code == CM_ERROR_BADTID) {
3057         NTStatus = 0xC0982005L; /* SMB bad TID */
3058     }
3059     else if (code == CM_ERROR_USESTD) {
3060         NTStatus = 0xC09820FBL; /* SMB use standard */
3061     }
3062     else if (code == CM_ERROR_QUOTA) {
3063         NTStatus = 0xC0000044L; /* Quota exceeded */
3064     }
3065     else if (code == CM_ERROR_SPACE) {
3066         NTStatus = 0xC000007FL; /* Disk full */
3067     }
3068     else if (code == CM_ERROR_ATSYS) {
3069         NTStatus = 0xC0000033L; /* Object name invalid */
3070     }
3071     else if (code == CM_ERROR_BADNTFILENAME) {
3072         NTStatus = 0xC0000033L; /* Object name invalid */
3073     }
3074     else if (code == CM_ERROR_WOULDBLOCK) {
3075         NTStatus = 0xC00000D8L; /* Can't wait */
3076     }
3077     else if (code == CM_ERROR_SHARING_VIOLATION) {
3078         NTStatus = 0xC0000043L; /* Sharing violation */
3079     }
3080     else if (code == CM_ERROR_LOCK_CONFLICT) {
3081         NTStatus = 0xC0000054L; /* Lock conflict */
3082     }
3083     else if (code == CM_ERROR_PARTIALWRITE) {
3084         NTStatus = 0xC000007FL; /* Disk full */
3085     }
3086     else if (code == CM_ERROR_BUFFERTOOSMALL) {
3087         NTStatus = 0xC0000023L; /* Buffer too small */
3088     }
3089     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3090         NTStatus = 0xC0000035L; /* Object name collision */
3091     }   
3092     else if (code == CM_ERROR_BADPASSWORD) {
3093         NTStatus = 0xC000006DL; /* unknown username or bad password */
3094     }
3095     else if (code == CM_ERROR_BADLOGONTYPE) {
3096         NTStatus = 0xC000015BL; /* logon type not granted */
3097     }
3098     else if (code == CM_ERROR_GSSCONTINUE) {
3099         NTStatus = 0xC0000016L; /* more processing required */
3100     }
3101     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3102 #ifdef COMMENT
3103         NTStatus = 0xC0000280L; /* reparse point not resolved */
3104 #else
3105         NTStatus = 0xC0000022L; /* Access Denied */
3106 #endif
3107     }
3108     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3109         NTStatus = 0xC0000257L; /* Path Not Covered */
3110     } 
3111     else if (code == CM_ERROR_ALLBUSY) {
3112         NTStatus = 0xC000022DL; /* Retry */
3113     } 
3114     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3115         NTStatus = 0xC000003AL; /* Path not found */
3116     } 
3117     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3118         NTStatus = 0xC0000322L; /* No Kerberos key */
3119     } 
3120     else if (code == CM_ERROR_BAD_LEVEL) {
3121         NTStatus = 0xC0000148L; /* Invalid Level */
3122     } 
3123     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3124         NTStatus = 0xC000007EL; /* Range Not Locked */
3125     } 
3126     else if (code == CM_ERROR_NOSUCHDEVICE) {
3127         NTStatus = 0xC000000EL; /* No Such Device */
3128     }
3129     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3130         NTStatus = 0xC0000055L; /* Lock Not Granted */
3131     }
3132     else if (code == ENOMEM) {
3133         NTStatus = 0xC0000017L; /* Out of Memory */
3134     }
3135     else if (code == CM_ERROR_RPC_MOREDATA) {
3136         NTStatus = 0x80000005L; /* Buffer overflow */
3137     }
3138     else  {
3139         NTStatus = 0xC0982001L; /* SMB non-specific error */
3140     }
3141
3142     *NTStatusp = NTStatus;
3143     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3144 }       
3145
3146 /* 
3147  * NTSTATUS <-> Win32 Error Translation 
3148  * http://support.microsoft.com/kb/113996 
3149  */
3150 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3151 {
3152     unsigned long Win32E;
3153
3154     /* map CM_ERROR_* errors to Win32 32-bit error codes */
3155     if (code == 0) {
3156         Win32E = 0;
3157     } 
3158     else if (code == CM_ERROR_NOSUCHCELL) {
3159         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3160     }
3161     else if (code == CM_ERROR_NOSUCHVOLUME) {
3162         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3163     }
3164     else if (code == CM_ERROR_TIMEDOUT) {
3165 #ifdef COMMENT
3166         Win32E = ERROR_SHARING_PAUSED;  /* Sharing Paused */
3167 #else
3168         Win32E = ERROR_UNEXP_NET_ERR;   /* Timeout */
3169 #endif
3170     }
3171     else if (code == CM_ERROR_RETRY) {
3172         Win32E = ERROR_RETRY;           /* Retry */
3173     }
3174     else if (code == CM_ERROR_NOACCESS) {
3175         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3176     }
3177     else if (code == CM_ERROR_READONLY) {
3178         Win32E = ERROR_WRITE_PROTECT;   /* Write protected */
3179     }
3180     else if (code == CM_ERROR_NOSUCHFILE ||
3181              code == CM_ERROR_BPLUS_NOMATCH) {
3182         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3183     }
3184     else if (code == CM_ERROR_NOSUCHPATH) {
3185         Win32E = ERROR_PATH_NOT_FOUND;  /* Object path not found */
3186     }           
3187     else if (code == CM_ERROR_TOOBIG) {
3188         Win32E = ERROR_BAD_EXE_FORMAT;  /* Invalid image format */
3189     }
3190     else if (code == CM_ERROR_INVAL) {
3191         Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3192     }
3193     else if (code == CM_ERROR_BADFD) {
3194         Win32E = ERROR_INVALID_HANDLE;  /* Invalid handle */
3195     }
3196     else if (code == CM_ERROR_BADFDOP) {
3197         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3198     }
3199     else if (code == CM_ERROR_EXISTS) {
3200         Win32E = ERROR_ALREADY_EXISTS;  /* Object name collision */
3201     }
3202     else if (code == CM_ERROR_NOTEMPTY) {
3203         Win32E = ERROR_DIR_NOT_EMPTY;   /* Directory not empty */
3204     }   
3205     else if (code == CM_ERROR_CROSSDEVLINK) {
3206         Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3207     }
3208     else if (code == CM_ERROR_NOTDIR) {
3209         Win32E = ERROR_DIRECTORY;       /* Not a directory */
3210     }
3211     else if (code == CM_ERROR_ISDIR) {
3212         Win32E = ERROR_ACCESS_DENIED;   /* File is a directory */
3213     }
3214     else if (code == CM_ERROR_BADOP) {
3215         Win32E = ERROR_NOT_SUPPORTED;   /* Not supported */
3216     }
3217     else if (code == CM_ERROR_BADSHARENAME) {
3218         Win32E = ERROR_BAD_NETPATH;     /* Bad network path (server valid, share bad) */
3219     }
3220     else if (code == CM_ERROR_NOIPC) {
3221 #ifdef COMMENT
3222         Win32E = ERROR_ACCESS_DENIED;   /* Access Denied */
3223 #else   
3224         Win32E = ERROR_REM_NOT_LIST;    /* Remote Resources */
3225 #endif
3226     }
3227     else if (code == CM_ERROR_CLOCKSKEW) {
3228         Win32E = ERROR_TIME_SKEW;       /* Time difference at DC */
3229     }
3230     else if (code == CM_ERROR_BADTID) {
3231         Win32E = ERROR_FILE_NOT_FOUND;  /* SMB bad TID */
3232     }
3233     else if (code == CM_ERROR_USESTD) {
3234         Win32E = ERROR_ACCESS_DENIED;   /* SMB use standard */
3235     }
3236     else if (code == CM_ERROR_QUOTA) {
3237         Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3238     }
3239     else if (code == CM_ERROR_SPACE) {
3240         Win32E = ERROR_DISK_FULL;       /* Disk full */
3241     }
3242     else if (code == CM_ERROR_ATSYS) {
3243         Win32E = ERROR_INVALID_NAME;    /* Object name invalid */
3244     }
3245     else if (code == CM_ERROR_BADNTFILENAME) {
3246         Win32E = ERROR_INVALID_NAME;    /* Object name invalid */
3247     }
3248     else if (code == CM_ERROR_WOULDBLOCK) {
3249         Win32E = WAIT_TIMEOUT;          /* Can't wait */
3250     }
3251     else if (code == CM_ERROR_SHARING_VIOLATION) {
3252         Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3253     }
3254     else if (code == CM_ERROR_LOCK_CONFLICT) {
3255         Win32E = ERROR_LOCK_VIOLATION;   /* Lock conflict */
3256     }
3257     else if (code == CM_ERROR_PARTIALWRITE) {
3258         Win32E = ERROR_DISK_FULL;       /* Disk full */
3259     }
3260     else if (code == CM_ERROR_BUFFERTOOSMALL) {
3261         Win32E = ERROR_INSUFFICIENT_BUFFER;     /* Buffer too small */
3262     }
3263     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3264         Win32E = ERROR_ALREADY_EXISTS;  /* Object name collision */
3265     }   
3266     else if (code == CM_ERROR_BADPASSWORD) {
3267         Win32E = ERROR_LOGON_FAILURE;   /* unknown username or bad password */
3268     }
3269     else if (code == CM_ERROR_BADLOGONTYPE) {
3270         Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3271     }
3272     else if (code == CM_ERROR_GSSCONTINUE) {
3273         Win32E = ERROR_MORE_DATA;       /* more processing required */
3274     }
3275     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3276 #ifdef COMMENT
3277         Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3278 #else
3279         Win32E = ERROR_ACCESS_DENIED;   /* Access Denied */
3280 #endif
3281     }
3282     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3283         Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3284     } 
3285     else if (code == CM_ERROR_ALLBUSY) {
3286         Win32E = ERROR_RETRY;           /* Retry */
3287     } 
3288     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3289         Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3290     } 
3291     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3292         Win32E = SEC_E_NO_KERB_KEY;     /* No Kerberos key */
3293     } 
3294     else if (code == CM_ERROR_BAD_LEVEL) {
3295         Win32E = ERROR_INVALID_LEVEL;   /* Invalid Level */
3296     } 
3297     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3298         Win32E = ERROR_NOT_LOCKED;      /* Range Not Locked */
3299     } 
3300     else if (code == CM_ERROR_NOSUCHDEVICE) {
3301         Win32E = ERROR_FILE_NOT_FOUND;  /* No Such Device */
3302     }
3303     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3304         Win32E = ERROR_LOCK_VIOLATION;  /* Lock Not Granted */
3305     }
3306     else if (code == ENOMEM) {
3307         Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3308     }
3309     else if (code == CM_ERROR_RPC_MOREDATA) {
3310         Win32E = ERROR_MORE_DATA;       /* Buffer overflow */
3311     }
3312     else  {
3313         Win32E = ERROR_GEN_FAILURE;     /* SMB non-specific error */
3314     }
3315
3316     *Win32Ep = Win32E;
3317     osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3318 }       
3319
3320 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3321                       unsigned char *classp)
3322 {
3323     unsigned char class;
3324     unsigned short error;
3325
3326     /* map CM_ERROR_* errors to SMB errors */
3327     if (code == CM_ERROR_NOSUCHCELL) {
3328         class = 1;
3329         error = 3;      /* bad path */
3330     }
3331     else if (code == CM_ERROR_NOSUCHVOLUME) {
3332         class = 1;
3333         error = 3;      /* bad path */
3334     }
3335     else if (code == CM_ERROR_TIMEDOUT) {
3336         class = 2;
3337         error = 81;     /* server is paused */
3338     }
3339     else if (code == CM_ERROR_RETRY) {
3340         class = 2;      /* shouldn't happen */
3341         error = 1;
3342     }
3343     else if (code == CM_ERROR_NOACCESS) {
3344         class = 2;
3345         error = 4;      /* bad access */
3346     }
3347     else if (code == CM_ERROR_READONLY) {
3348         class = 3;
3349         error = 19;     /* read only */
3350     }
3351     else if (code == CM_ERROR_NOSUCHFILE ||
3352              code == CM_ERROR_BPLUS_NOMATCH) {
3353         class = 1;
3354         error = 2;      /* ENOENT! */
3355     }
3356     else if (code == CM_ERROR_NOSUCHPATH) {
3357         class = 1;
3358         error = 3;      /* Bad path */
3359     }
3360     else if (code == CM_ERROR_TOOBIG) {
3361         class = 1;
3362         error = 11;     /* bad format */
3363     }
3364     else if (code == CM_ERROR_INVAL) {
3365         class = 2;      /* server non-specific error code */
3366         error = 1;
3367     }
3368     else if (code == CM_ERROR_BADFD) {
3369         class = 1;
3370         error = 6;      /* invalid file handle */
3371     }
3372     else if (code == CM_ERROR_BADFDOP) {
3373         class = 1;      /* invalid op on FD */
3374         error = 5;
3375     }
3376     else if (code == CM_ERROR_EXISTS) {
3377         class = 1;
3378         error = 80;     /* file already exists */
3379     }
3380     else if (code == CM_ERROR_NOTEMPTY) {
3381         class = 1;
3382         error = 5;      /* delete directory not empty */
3383     }
3384     else if (code == CM_ERROR_CROSSDEVLINK) {
3385         class = 1;
3386         error = 17;     /* EXDEV */
3387     }
3388     else if (code == CM_ERROR_NOTDIR) {
3389         class = 1;      /* bad path */
3390         error = 3;
3391     }
3392     else if (code == CM_ERROR_ISDIR) {
3393         class = 1;      /* access denied; DOS doesn't have a good match */
3394         error = 5;
3395     }       
3396     else if (code == CM_ERROR_BADOP) {
3397         class = 2;
3398         error = 65535;
3399     }
3400     else if (code == CM_ERROR_BADSHARENAME) {
3401         class = 2;
3402         error = 6;
3403     }
3404     else if (code == CM_ERROR_NOIPC) {
3405         class = 2;
3406         error = 4; /* bad access */
3407     }
3408     else if (code == CM_ERROR_CLOCKSKEW) {
3409         class = 1;      /* invalid function */
3410         error = 1;
3411     }
3412     else if (code == CM_ERROR_BADTID) {
3413         class = 2;
3414         error = 5;
3415     }
3416     else if (code == CM_ERROR_USESTD) {
3417         class = 2;
3418         error = 251;
3419     }
3420     else if (code == CM_ERROR_REMOTECONN) {
3421         class = 2;
3422         error = 82;
3423     }
3424     else if (code == CM_ERROR_QUOTA) {
3425         if (vcp->flags & SMB_VCFLAG_USEV3) {
3426             class = 3;
3427             error = 39; /* disk full */
3428         }
3429         else {
3430             class = 1;
3431             error = 5;  /* access denied */
3432         }
3433     }
3434     else if (code == CM_ERROR_SPACE) {
3435         if (vcp->flags & SMB_VCFLAG_USEV3) {
3436             class = 3;
3437             error = 39; /* disk full */
3438         }
3439         else {
3440             class = 1;
3441             error = 5;  /* access denied */
3442         }
3443     }
3444     else if (code == CM_ERROR_PARTIALWRITE) {
3445         class = 3;
3446         error = 39;     /* disk full */
3447     }
3448     else if (code == CM_ERROR_ATSYS) {
3449         class = 1;
3450         error = 2;      /* ENOENT */
3451     }
3452     else if (code == CM_ERROR_WOULDBLOCK) {
3453         class = 1;
3454         error = 33;     /* lock conflict */
3455     }
3456     else if (code == CM_ERROR_LOCK_CONFLICT) {
3457         class = 1;
3458         error = 33;     /* lock conflict */
3459     }
3460     else if (code == CM_ERROR_SHARING_VIOLATION) {
3461         class = 1;
3462         error = 33;     /* lock conflict */
3463     }
3464     else if (code == CM_ERROR_NOFILES) {
3465         class = 1;
3466         error = 18;     /* no files in search */
3467     }
3468     else if (code == CM_ERROR_RENAME_IDENTICAL) {
3469         class = 1;
3470         error = 183;     /* Samba uses this */
3471     }
3472     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3473         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3474         class = 2;
3475         error = 2; /* bad password */
3476     }
3477     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3478         class = 2;
3479         error = 3;     /* bad path */
3480     }
3481     else {
3482         class = 2;
3483         error = 1;
3484     }
3485
3486     *scodep = error;
3487     *classp = class;
3488     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3489 }       
3490
3491 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3492 {
3493     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3494     return CM_ERROR_BADOP;
3495 }
3496
3497 /* SMB_COM_ECHO */
3498 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3499 {
3500     unsigned short EchoCount, i;
3501     char *data, *outdata;
3502     int dataSize;
3503
3504     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3505
3506     for (i=1; i<=EchoCount; i++) {
3507         data = smb_GetSMBData(inp, &dataSize);
3508         smb_SetSMBParm(outp, 0, i);
3509         smb_SetSMBDataLength(outp, dataSize);
3510         outdata = smb_GetSMBData(outp, NULL);
3511         memcpy(outdata, data, dataSize);
3512         smb_SendPacket(vcp, outp);
3513     }
3514
3515     return 0;
3516 }
3517
3518 /* SMB_COM_READ_RAW */
3519 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3520 {
3521     osi_hyper_t offset;
3522     long count, minCount, finalCount;
3523     unsigned short fd;
3524     unsigned pid;
3525     smb_fid_t *fidp;
3526     smb_t *smbp = (smb_t*) inp;
3527     long code = 0;
3528     cm_user_t *userp = NULL;
3529     NCB *ncbp;
3530     int rc;
3531     char *rawBuf = NULL;
3532
3533     rawBuf = NULL;
3534     finalCount = 0;
3535
3536     fd = smb_GetSMBParm(inp, 0);
3537     count = smb_GetSMBParm(inp, 3);
3538     minCount = smb_GetSMBParm(inp, 4);
3539     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3540
3541     if (*inp->wctp == 10) {
3542         /* we were sent a request with 64-bit file offsets */
3543 #ifdef AFS_LARGEFILES
3544         offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3545
3546         if (LargeIntegerLessThanZero(offset)) {
3547             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3548             goto send1;
3549         }
3550 #else
3551         if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3552             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset.  Dropping request.");
3553             goto send1;
3554         } else {
3555             offset.HighPart = 0;
3556         }
3557 #endif
3558     } else {
3559         /* we were sent a request with 32-bit file offsets */
3560         offset.HighPart = 0;
3561     }
3562
3563     osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3564              fd, offset.HighPart, offset.LowPart, count);
3565
3566     fidp = smb_FindFID(vcp, fd, 0);
3567     if (!fidp)
3568         goto send1;
3569
3570     lock_ObtainMutex(&fidp->mx);
3571     if (!fidp->scp) {
3572         lock_ReleaseMutex(&fidp->mx);
3573         smb_ReleaseFID(fidp);
3574         return CM_ERROR_BADFD;
3575     }
3576
3577     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3578         lock_ReleaseMutex(&fidp->mx);
3579         smb_CloseFID(vcp, fidp, NULL, 0);
3580         code = CM_ERROR_NOSUCHFILE;
3581         goto send1a;
3582     }
3583
3584     pid = smbp->pid;
3585     {
3586         LARGE_INTEGER LOffset, LLength;
3587         cm_key_t key;
3588
3589         key = cm_GenerateKey(vcp->vcID, pid, fd);
3590
3591         LOffset.HighPart = offset.HighPart;
3592         LOffset.LowPart = offset.LowPart;
3593         LLength.HighPart = 0;
3594         LLength.LowPart = count;
3595
3596         lock_ObtainWrite(&fidp->scp->rw);
3597         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3598         lock_ReleaseWrite(&fidp->scp->rw);
3599     }    
3600     if (code) {
3601         lock_ReleaseMutex(&fidp->mx);
3602         goto send1a;
3603     }
3604
3605     lock_ObtainMutex(&smb_RawBufLock);
3606     if (smb_RawBufs) {
3607         /* Get a raw buf, from head of list */
3608         rawBuf = smb_RawBufs;
3609         smb_RawBufs = *(char **)smb_RawBufs;
3610     }
3611     lock_ReleaseMutex(&smb_RawBufLock);
3612     if (!rawBuf) {
3613         lock_ReleaseMutex(&fidp->mx);
3614         goto send1a;
3615     }
3616
3617     if (fidp->flags & SMB_FID_IOCTL)
3618     {
3619         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3620         if (rawBuf) {
3621             /* Give back raw buffer */
3622             lock_ObtainMutex(&smb_RawBufLock);
3623             *((char **) rawBuf) = smb_RawBufs;
3624             
3625             smb_RawBufs = rawBuf;
3626             lock_ReleaseMutex(&smb_RawBufLock);
3627         }
3628
3629         lock_ReleaseMutex(&fidp->mx);
3630         smb_ReleaseFID(fidp);
3631         return rc;
3632     }
3633     lock_ReleaseMutex(&fidp->mx);
3634
3635     userp = smb_GetUserFromVCP(vcp, inp);
3636
3637     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3638
3639     if (code != 0)
3640         goto send;
3641
3642   send:
3643     cm_ReleaseUser(userp);
3644
3645   send1a:
3646     smb_ReleaseFID(fidp);
3647
3648   send1:
3649     ncbp = outp->ncbp;
3650     memset((char *)ncbp, 0, sizeof(NCB));
3651
3652     ncbp->ncb_length = (unsigned short) finalCount;
3653     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3654     ncbp->ncb_lana_num = vcp->lana;
3655     ncbp->ncb_command = NCBSEND;
3656     ncbp->ncb_buffer = rawBuf;
3657
3658     code = Netbios(ncbp);
3659     if (code != 0)
3660         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3661
3662     if (rawBuf) {
3663         /* Give back raw buffer */
3664         lock_ObtainMutex(&smb_RawBufLock);
3665         *((char **) rawBuf) = smb_RawBufs;
3666
3667         smb_RawBufs = rawBuf;
3668         lock_ReleaseMutex(&smb_RawBufLock);
3669     }
3670
3671     return 0;
3672 }
3673
3674 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3675 {
3676     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3677                          ongoingOps - 1);
3678     return 0;
3679 }
3680
3681 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3682 {
3683     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3684                          ongoingOps - 1);
3685     return 0;
3686 }
3687
3688 /* SMB_COM_NEGOTIATE */
3689 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3690 {
3691     char *namep;
3692     char *datap;
3693     int coreProtoIndex;
3694     int v3ProtoIndex;
3695     int NTProtoIndex;
3696     int VistaProtoIndex;
3697     int protoIndex;                             /* index we're using */
3698     int namex;
3699     int dbytes;
3700     int entryLength;
3701     int tcounter;
3702     char protocol_array[10][1024];  /* protocol signature of the client */
3703     int caps;                       /* capabilities */
3704     time_t unixTime;
3705     afs_uint32 dosTime;
3706     TIME_ZONE_INFORMATION tzi;
3707
3708     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3709                          ongoingOps - 1);
3710
3711     namep = smb_GetSMBData(inp, &dbytes);
3712     namex = 0;
3713     tcounter = 0;
3714     coreProtoIndex = -1;                /* not found */
3715     v3ProtoIndex = -1;
3716     NTProtoIndex = -1;
3717     VistaProtoIndex = -1;
3718     while(namex < dbytes) {
3719         osi_Log1(smb_logp, "Protocol %s",
3720                   osi_LogSaveString(smb_logp, namep+1));
3721         strcpy(protocol_array[tcounter], namep+1);
3722
3723         /* namep points at the first protocol, or really, a 0x02
3724          * byte preceding the null-terminated ASCII name.
3725          */
3726         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3727             coreProtoIndex = tcounter;
3728