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