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