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