man-page-afs-fixes-20080626
[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     }
951 }
952
953 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
954 {
955     osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
956     smb_ReleaseVCInternal(vcp);
957 }       
958
959 void smb_ReleaseVC(smb_vc_t *vcp)
960 {
961     lock_ObtainWrite(&smb_rctLock);
962     osi_Log2(smb_logp,"smb_ReleaseVC       vcp %x ref %d",vcp, vcp->refCount);
963     smb_ReleaseVCInternal(vcp);
964     lock_ReleaseWrite(&smb_rctLock);
965 }       
966
967 void smb_HoldVCNoLock(smb_vc_t *vcp)
968 {
969     vcp->refCount++;
970     osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
971 }       
972
973 void smb_HoldVC(smb_vc_t *vcp)
974 {
975     lock_ObtainWrite(&smb_rctLock);
976     vcp->refCount++;
977     osi_Log2(smb_logp,"smb_HoldVC       vcp %x ref %d",vcp, vcp->refCount);
978     lock_ReleaseWrite(&smb_rctLock);
979 }       
980
981 void smb_CleanupDeadVC(smb_vc_t *vcp)
982 {
983     smb_fid_t *fidpIter;
984     smb_fid_t *fidpNext;
985     unsigned short fid;
986     smb_tid_t *tidpIter;
987     smb_tid_t *tidpNext;
988     unsigned short tid;
989     smb_user_t *uidpIter;
990     smb_user_t *uidpNext;
991     smb_vc_t **vcpp;
992
993
994     lock_ObtainMutex(&vcp->mx);
995     if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
996         lock_ReleaseMutex(&vcp->mx);
997         osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
998         return;
999     }
1000     vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1001     lock_ReleaseMutex(&vcp->mx);
1002     osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1003
1004     lock_ObtainWrite(&smb_rctLock);
1005     /* remove VCP from smb_allVCsp */
1006     for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1007         if ((*vcpp)->magic != SMB_VC_MAGIC)
1008             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
1009                        __FILE__, __LINE__);
1010         if (*vcpp == vcp) {
1011             *vcpp = vcp->nextp;
1012             vcp->nextp = smb_deadVCsp;
1013             smb_deadVCsp = vcp;
1014             /* Hold onto the reference until we are done with this function */
1015             break;
1016         }
1017     }
1018
1019     for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1020         fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1021
1022         if (fidpIter->deleteOk)
1023             continue;
1024
1025         fid = fidpIter->fid;
1026         osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1027
1028         smb_HoldFIDNoLock(fidpIter);
1029         lock_ReleaseWrite(&smb_rctLock);
1030
1031         smb_CloseFID(vcp, fidpIter, NULL, 0);
1032         smb_ReleaseFID(fidpIter);
1033
1034         lock_ObtainWrite(&smb_rctLock);
1035         fidpNext = vcp->fidsp;
1036     }
1037
1038     for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1039         tidpNext = tidpIter->nextp;
1040         if (tidpIter->deleteOk)
1041             continue;
1042         tidpIter->deleteOk = 1;
1043
1044         tid = tidpIter->tid;
1045         osi_Log2(smb_logp, "  Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1046
1047         smb_HoldTIDNoLock(tidpIter);
1048         smb_ReleaseTID(tidpIter, TRUE);
1049         tidpNext = vcp->tidsp;
1050     }
1051
1052     for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1053         uidpNext = uidpIter->nextp;
1054         if (uidpIter->deleteOk)
1055             continue;
1056         uidpIter->deleteOk = 1;
1057
1058         /* do not add an additional reference count for the smb_user_t
1059          * as the smb_vc_t already is holding a reference */
1060         lock_ReleaseWrite(&smb_rctLock);
1061
1062         smb_ReleaseUID(uidpIter);
1063
1064         lock_ObtainWrite(&smb_rctLock);
1065         uidpNext = vcp->usersp;
1066     }
1067
1068     /* The vcp is now on the deadVCsp list.  We intentionally drop the
1069      * reference so that the refcount can reach 0 and we can delete it */
1070     smb_ReleaseVCNoLock(vcp);
1071     
1072     lock_ReleaseWrite(&smb_rctLock);
1073     osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1074 }
1075
1076 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1077 {
1078     smb_tid_t *tidp;
1079
1080     lock_ObtainWrite(&smb_rctLock);
1081   retry:
1082     for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1083         if (tidp->refCount == 0 && tidp->deleteOk) {
1084             tidp->refCount++;
1085             smb_ReleaseTID(tidp, TRUE);
1086             goto retry;
1087         }
1088
1089         if (tid == tidp->tid) {
1090             tidp->refCount++;
1091             break;
1092         }
1093     }
1094     if (!tidp && (flags & SMB_FLAG_CREATE)) {
1095         tidp = malloc(sizeof(*tidp));
1096         memset(tidp, 0, sizeof(*tidp));
1097         tidp->nextp = vcp->tidsp;
1098         tidp->refCount = 1;
1099         tidp->vcp = vcp;
1100         smb_HoldVCNoLock(vcp);
1101         vcp->tidsp = tidp;
1102         lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1103         tidp->tid = tid;
1104     }
1105     lock_ReleaseWrite(&smb_rctLock);
1106     return tidp;
1107 }
1108
1109 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1110 {
1111     tidp->refCount++;
1112 }
1113
1114 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1115 {
1116     smb_tid_t *tp;
1117     smb_tid_t **ltpp;
1118     cm_user_t *userp;
1119
1120     userp = NULL;
1121     if (!locked)
1122         lock_ObtainWrite(&smb_rctLock);
1123     osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1124     if (tidp->refCount == 0 && (tidp->deleteOk)) {
1125         ltpp = &tidp->vcp->tidsp;
1126         for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1127             if (tp == tidp) 
1128                 break;
1129         }
1130         osi_assertx(tp != NULL, "null smb_tid_t");
1131         *ltpp = tp->nextp;
1132         lock_FinalizeMutex(&tidp->mx);
1133         userp = tidp->userp;    /* remember to drop ref later */
1134         tidp->userp = NULL;
1135         smb_ReleaseVCNoLock(tidp->vcp);
1136         tidp->vcp = NULL;
1137     }
1138     if (!locked)
1139         lock_ReleaseWrite(&smb_rctLock);
1140     if (userp)
1141         cm_ReleaseUser(userp);
1142 }               
1143
1144 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1145 {
1146     smb_user_t *uidp = NULL;
1147
1148     lock_ObtainWrite(&smb_rctLock);
1149     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1150         if (uid == uidp->userID) {
1151             uidp->refCount++;
1152             osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1153                      vcp, uidp->userID, 
1154                      ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1155             break;
1156         }
1157     }
1158     if (!uidp && (flags & SMB_FLAG_CREATE)) {
1159         uidp = malloc(sizeof(*uidp));
1160         memset(uidp, 0, sizeof(*uidp));
1161         uidp->nextp = vcp->usersp;
1162         uidp->refCount = 2; /* one for the vcp and one for the caller */
1163         uidp->vcp = vcp;
1164         smb_HoldVCNoLock(vcp);
1165         vcp->usersp = uidp;
1166         lock_InitializeMutex(&uidp->mx, "user_t mutex");
1167         uidp->userID = uid;
1168         osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1169                  vcp, uidp->userID,
1170                  ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1171     }
1172     lock_ReleaseWrite(&smb_rctLock);
1173     return uidp;
1174 }               
1175
1176 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1177                                    afs_uint32 flags)
1178 {
1179     smb_username_t *unp= NULL;
1180
1181     lock_ObtainWrite(&smb_rctLock);
1182     for(unp = usernamesp; unp; unp = unp->nextp) {
1183         if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1184             cm_ClientStrCmpI(unp->machine, machine) == 0) {
1185             unp->refCount++;
1186             break;
1187         }
1188     }
1189     if (!unp && (flags & SMB_FLAG_CREATE)) {
1190         unp = malloc(sizeof(*unp));
1191         memset(unp, 0, sizeof(*unp));
1192         unp->refCount = 1;
1193         unp->nextp = usernamesp;
1194         unp->name = cm_ClientStrDup(usern);
1195         unp->machine = cm_ClientStrDup(machine);
1196         usernamesp = unp;
1197         lock_InitializeMutex(&unp->mx, "username_t mutex");
1198         if (flags & SMB_FLAG_AFSLOGON)
1199             unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1200     }
1201
1202     lock_ReleaseWrite(&smb_rctLock);
1203     return unp;
1204 }       
1205
1206 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1207 {
1208     smb_user_t *uidp= NULL;
1209
1210     lock_ObtainWrite(&smb_rctLock);
1211     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1212         if (!uidp->unp) 
1213             continue;
1214         if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1215             uidp->refCount++;
1216             osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1217                      vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1218             break;
1219         } else
1220             continue;
1221     }           
1222     lock_ReleaseWrite(&smb_rctLock);
1223     return uidp;
1224 }       
1225
1226 void smb_ReleaseUsername(smb_username_t *unp)
1227 {
1228     smb_username_t *up;
1229     smb_username_t **lupp;
1230     cm_user_t *userp = NULL;
1231     time_t      now = osi_Time();
1232
1233     lock_ObtainWrite(&smb_rctLock);
1234     osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1235     if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1236         (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1237         lupp = &usernamesp;
1238         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1239             if (up == unp) 
1240                 break;
1241         }
1242         osi_assertx(up != NULL, "null smb_username_t");
1243         *lupp = up->nextp;
1244         up->nextp = NULL;                       /* do not remove this */
1245         lock_FinalizeMutex(&unp->mx);
1246         userp = unp->userp;
1247         free(unp->name);
1248         free(unp->machine);
1249         free(unp);
1250     }
1251     lock_ReleaseWrite(&smb_rctLock);
1252     if (userp)
1253         cm_ReleaseUser(userp);
1254 }       
1255
1256 void smb_HoldUIDNoLock(smb_user_t *uidp)
1257 {
1258     uidp->refCount++;
1259 }
1260
1261 void smb_ReleaseUID(smb_user_t *uidp)
1262 {
1263     smb_user_t *up;
1264     smb_user_t **lupp;
1265     smb_username_t *unp = NULL;
1266
1267     lock_ObtainWrite(&smb_rctLock);
1268     osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1269     if (uidp->refCount == 0) {
1270         lupp = &uidp->vcp->usersp;
1271         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1272             if (up == uidp) 
1273                 break;
1274         }
1275         osi_assertx(up != NULL, "null smb_user_t");
1276         *lupp = up->nextp;
1277         lock_FinalizeMutex(&uidp->mx);
1278         unp = uidp->unp;
1279         smb_ReleaseVCNoLock(uidp->vcp);
1280         uidp->vcp = NULL;
1281         free(uidp);
1282     }           
1283     lock_ReleaseWrite(&smb_rctLock);
1284
1285     if (unp) {
1286         if (unp->userp)
1287             cm_ReleaseUserVCRef(unp->userp);
1288         smb_ReleaseUsername(unp);
1289     }
1290 }       
1291
1292 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1293 {
1294     cm_user_t *up = NULL;
1295
1296     if (!uidp)
1297         return NULL;
1298     
1299     lock_ObtainMutex(&uidp->mx);
1300     if (uidp->unp) {
1301         up = uidp->unp->userp;
1302         cm_HoldUser(up);
1303     }
1304     lock_ReleaseMutex(&uidp->mx);
1305
1306     return up;
1307 }
1308
1309
1310 /* retrieve a held reference to a user structure corresponding to an incoming
1311  * request.
1312  * corresponding release function is cm_ReleaseUser.
1313  */
1314 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1315 {
1316     smb_user_t *uidp;
1317     cm_user_t *up = NULL;
1318     smb_t *smbp;
1319
1320     smbp = (smb_t *) inp;
1321     uidp = smb_FindUID(vcp, smbp->uid, 0);
1322     if (!uidp)
1323         return NULL;
1324     
1325     up = smb_GetUserFromUID(uidp);
1326
1327     smb_ReleaseUID(uidp);
1328     return up;
1329 }
1330
1331 /*
1332  * Return a pointer to a pathname extracted from a TID structure.  The
1333  * TID structure is not held; assume it won't go away.
1334  */
1335 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1336 {
1337     smb_tid_t *tidp;
1338     long code = 0;
1339
1340     tidp = smb_FindTID(vcp, tid, 0);
1341     if (!tidp) {
1342         *treepath = NULL;
1343     } else {
1344         if (tidp->flags & SMB_TIDFLAG_IPC) {
1345             code = CM_ERROR_TIDIPC;
1346             /* tidp->pathname would be NULL, but that's fine */
1347         }
1348         *treepath = tidp->pathname;
1349         smb_ReleaseTID(tidp, FALSE);
1350     }
1351     return code;
1352 }
1353
1354 /* check to see if we have a chained fid, that is, a fid that comes from an
1355  * OpenAndX message that ran earlier in this packet.  In this case, the fid
1356  * field in a read, for example, request, isn't set, since the value is
1357  * supposed to be inherited from the openAndX call.
1358  */
1359 int smb_ChainFID(int fid, smb_packet_t *inp)
1360 {
1361     if (inp->fid == 0 || inp->inCount == 0) 
1362         return fid;
1363     else 
1364         return inp->fid;
1365 }
1366
1367 /* are we a priv'd user?  What does this mean on NT? */
1368 int smb_SUser(cm_user_t *userp)
1369 {
1370     return 1;
1371 }
1372
1373 /* find a file ID.  If we pass in 0 we select an unused File ID.
1374  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
1375  * smb_fid_t data structure if desired File ID cannot be found.
1376  */
1377 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1378 {
1379     smb_fid_t *fidp;
1380     int newFid = 0;
1381         
1382     if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1383         return NULL;
1384
1385     lock_ObtainWrite(&smb_rctLock);
1386     /* figure out if we need to allocate a new file ID */
1387     if (fid == 0) {
1388         newFid = 1;
1389         fid = vcp->fidCounter;
1390     }
1391
1392   retry:
1393     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1394         if (fidp->refCount == 0 && fidp->deleteOk) {
1395             fidp->refCount++;
1396             lock_ReleaseWrite(&smb_rctLock);
1397             smb_ReleaseFID(fidp);
1398             lock_ObtainWrite(&smb_rctLock);
1399             goto retry;
1400         }
1401         if (fid == fidp->fid) {
1402             if (newFid) {
1403                 fid++;
1404                 if (fid == 0xFFFF) {
1405                     osi_Log1(smb_logp,
1406                              "New FID number wraps on vcp 0x%x", vcp);
1407                     fid = 1;
1408                 }
1409                 goto retry;
1410             }
1411             fidp->refCount++;
1412             break;
1413         }
1414     }
1415
1416     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1417         char eventName[MAX_PATH];
1418         EVENT_HANDLE event;
1419         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1420         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1421         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1422             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1423             thrd_CloseHandle(event);
1424             fid++;
1425             if (fid == 0xFFFF) {
1426                 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1427                 fid = 1;
1428             }
1429             goto retry;
1430         }
1431
1432         fidp = malloc(sizeof(*fidp));
1433         memset(fidp, 0, sizeof(*fidp));
1434         osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1435         fidp->refCount = 1;
1436         fidp->vcp = vcp;
1437         smb_HoldVCNoLock(vcp);
1438         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1439         fidp->fid = fid;
1440         fidp->curr_chunk = fidp->prev_chunk = -2;
1441         fidp->raw_write_event = event;
1442         if (newFid) {
1443             vcp->fidCounter = fid+1;
1444             if (vcp->fidCounter == 0xFFFF) {
1445                 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1446                          vcp);
1447                 vcp->fidCounter = 1;
1448             }
1449         }
1450     }
1451
1452     lock_ReleaseWrite(&smb_rctLock);
1453     return fidp;
1454 }
1455
1456 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1457 {
1458     smb_fid_t *fidp = NULL;
1459     int newFid = 0;
1460         
1461     if (!scp)
1462         return NULL;
1463
1464     lock_ObtainWrite(&smb_rctLock);
1465     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1466         if (scp == fidp->scp) {
1467             fidp->refCount++;
1468             break;
1469         }
1470     }
1471     lock_ReleaseWrite(&smb_rctLock);
1472     return fidp;
1473 }
1474
1475 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1476 {
1477     fidp->refCount++;
1478 }
1479
1480
1481 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1482 /* the sm_fid_t->mx and smb_rctLock must not be held */
1483 void smb_ReleaseFID(smb_fid_t *fidp)
1484 {
1485     cm_scache_t *scp = NULL;
1486     cm_user_t *userp = NULL;
1487     smb_vc_t *vcp = NULL;
1488     smb_ioctl_t *ioctlp;
1489
1490     lock_ObtainMutex(&fidp->mx);
1491     lock_ObtainWrite(&smb_rctLock);
1492     osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1493     if (fidp->refCount == 0 && (fidp->deleteOk)) {
1494         vcp = fidp->vcp;
1495         fidp->vcp = NULL;
1496         scp = fidp->scp;    /* release after lock is released */
1497         if (scp) {
1498             lock_ObtainWrite(&scp->rw);
1499             scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1500             lock_ReleaseWrite(&scp->rw);
1501             osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1502             fidp->scp = NULL;
1503         }
1504         userp = fidp->userp;
1505         fidp->userp = NULL;
1506
1507         if (vcp->fidsp) 
1508             osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1509         thrd_CloseHandle(fidp->raw_write_event);
1510
1511         /* and see if there is ioctl stuff to free */
1512         ioctlp = fidp->ioctlp;
1513         if (ioctlp) {
1514             if (ioctlp->prefix)
1515                 cm_FreeSpace(ioctlp->prefix);
1516             if (ioctlp->ioctl.inAllocp)
1517                 free(ioctlp->ioctl.inAllocp);
1518             if (ioctlp->ioctl.outAllocp)
1519                 free(ioctlp->ioctl.outAllocp);
1520             free(ioctlp);
1521         }       
1522         lock_ReleaseMutex(&fidp->mx);
1523         lock_FinalizeMutex(&fidp->mx);
1524         free(fidp);
1525
1526         if (vcp)
1527             smb_ReleaseVCNoLock(vcp);
1528     } else {
1529         lock_ReleaseMutex(&fidp->mx);
1530     }
1531     lock_ReleaseWrite(&smb_rctLock);
1532
1533     /* now release the scache structure */
1534     if (scp) 
1535         cm_ReleaseSCache(scp);
1536
1537     if (userp)
1538         cm_ReleaseUser(userp);
1539 }       
1540
1541 /*
1542  * Case-insensitive search for one string in another;
1543  * used to find variable names in submount pathnames.
1544  */
1545 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1546 {
1547     clientchar_t *cursor;
1548
1549     for (cursor = str1; *cursor; cursor++)
1550         if (cm_ClientStrCmpI(cursor, str2) == 0)
1551             return cursor;
1552
1553     return NULL;
1554 }
1555
1556 /*
1557  * Substitute a variable value for its name in a submount pathname.  Variable
1558  * name has been identified by smb_stristr() and is in substr.  Variable name
1559  * length (plus one) is in substr_size.  Variable value is in newstr.
1560  */
1561 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1562                       unsigned int substr_size, clientchar_t *newstr)
1563 {
1564     clientchar_t temp[1024];
1565
1566     cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1567     cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1568     cm_ClientStrCat(str1, cchstr1, temp);
1569 }
1570
1571 clientchar_t VNUserName[] = _C("%USERNAME%");
1572 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1573 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1574 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1575
1576 typedef struct smb_findShare_rock {
1577     clientchar_t * shareName;
1578     clientchar_t * match;
1579     int matchType;
1580 } smb_findShare_rock_t;
1581
1582 #define SMB_FINDSHARE_EXACT_MATCH 1
1583 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1584
1585 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1586                        osi_hyper_t *offp)
1587 {
1588     int matchType = 0;
1589     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1590     normchar_t normName[MAX_PATH];
1591
1592     cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0]));
1593
1594     if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1595         if(!cm_ClientStrCmpI(normName, vrock->shareName))
1596             matchType = SMB_FINDSHARE_EXACT_MATCH;
1597         else
1598             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1599         if(vrock->match) free(vrock->match);
1600         vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1601         vrock->matchType = matchType;
1602
1603         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1604             return CM_ERROR_STOPNOW;
1605     }
1606     return 0;
1607 }
1608
1609
1610 /* find a shareName in the table of submounts */
1611 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1612                   clientchar_t *shareName,
1613                   clientchar_t **pathNamep)
1614 {
1615     DWORD cblen;
1616     DWORD cchlen;
1617     clientchar_t pathName[1024];
1618     clientchar_t *var;
1619     DWORD sizeTemp;
1620     clientchar_t *p, *q;
1621     fschar_t *cellname = NULL;
1622     HKEY parmKey;
1623     DWORD code;
1624     DWORD allSubmount = 1;
1625
1626     /* if allSubmounts == 0, only return the //mountRoot/all share 
1627      * if in fact it has been been created in the subMounts table.  
1628      * This is to allow sites that want to restrict access to the 
1629      * world to do so.
1630      */
1631     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1632                         0, KEY_QUERY_VALUE, &parmKey);
1633     if (code == ERROR_SUCCESS) {
1634         cblen = sizeof(allSubmount);
1635         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1636                                (BYTE *) &allSubmount, &cblen);
1637         if (code != ERROR_SUCCESS) {
1638             allSubmount = 1;
1639         }
1640         RegCloseKey (parmKey);
1641     }
1642
1643     if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1644         *pathNamep = NULL;
1645         return 1;
1646     }
1647
1648     /* In case, the all share is disabled we need to still be able
1649      * to handle ioctl requests 
1650      */
1651     if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1652         *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1653         return 1;
1654     }
1655
1656     if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1657         cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1658         cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1659         cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1660         cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1661         ) {
1662         *pathNamep = NULL;
1663         return 0;
1664     }
1665
1666     /* Check for volume references
1667      * 
1668      * They look like <cell>{%,#}<volume>
1669      */
1670     if (cm_ClientStrChr(shareName, '%') != NULL ||
1671         cm_ClientStrChr(shareName, '#') != NULL) {
1672         clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1673         /* make room for '/@vol:' + mountchar + NULL terminator*/
1674
1675         osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1676                  osi_LogSaveClientString(smb_logp, shareName));
1677
1678         cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1679                             _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1680         cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1681
1682         *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1683         if (*pathNamep) {
1684             cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1685             cm_ClientStrLwr(*pathNamep);
1686             osi_Log1(smb_logp, "   returning pathname [%S]",
1687                      osi_LogSaveClientString(smb_logp, *pathNamep));
1688
1689             return 1;
1690         } else {
1691             return 0;
1692         }
1693     }
1694
1695     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1696                         0, KEY_QUERY_VALUE, &parmKey);
1697     if (code == ERROR_SUCCESS) {
1698         cblen = sizeof(pathName);
1699         code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1700                                 (BYTE *) pathName, &cblen);
1701         if (code != ERROR_SUCCESS)
1702             cblen = 0;
1703         RegCloseKey (parmKey);
1704     } else {
1705         cblen = 0;
1706     }
1707     cchlen = cblen / sizeof(clientchar_t);
1708     if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1709         /* We can accept either unix or PC style AFS pathnames.  Convert
1710          * Unix-style to PC style here for internal use. 
1711          */
1712         p = pathName;
1713         cchlen = lengthof(pathName);
1714
1715         /* within this code block, we maintain, cchlen = writeable
1716            buffer length of p */
1717
1718         if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1719             p += cm_mountRootCLen;  /* skip mount path */
1720             cchlen -= (p - pathName);
1721         }
1722
1723         q = p;
1724         while (*q) {
1725             if (*q == _C('/')) *q = _C('\\');    /* change to \ */
1726             q++;
1727         }
1728
1729         while (1)
1730         {
1731             clientchar_t temp[1024];
1732
1733             if (var = smb_stristr(p, VNUserName)) {
1734                 if (uidp && uidp->unp)
1735                     smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1736                 else
1737                     smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1738             }
1739             else if (var = smb_stristr(p, VNLCUserName)) 
1740             {
1741                 if (uidp && uidp->unp)
1742                     cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1743                 else 
1744                     cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1745                 cm_ClientStrLwr(temp);
1746                 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1747             }
1748             else if (var = smb_stristr(p, VNComputerName)) 
1749             {
1750                 sizeTemp = lengthof(temp);
1751                 GetComputerNameW(temp, &sizeTemp);
1752                 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1753             }
1754             else if (var = smb_stristr(p, VNLCComputerName)) 
1755             {
1756                 sizeTemp = lengthof(temp);
1757                 GetComputerName((LPTSTR)temp, &sizeTemp);
1758                 cm_ClientStrLwr(temp);
1759                 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1760             }
1761             else     
1762                 break;
1763         }
1764         *pathNamep = cm_ClientStrDup(p);
1765         return 1;
1766     } 
1767     else
1768     {
1769         /* First lookup shareName in root.afs */
1770         cm_req_t req;
1771         smb_findShare_rock_t vrock;
1772         osi_hyper_t thyper;
1773         fschar_t ftemp[1024];
1774         clientchar_t * p = shareName; 
1775         int rw = 0;
1776
1777         /*  attempt to locate a partial match in root.afs.  This is because
1778             when using the ANSI RAP calls, the share name is limited to 13 chars
1779             and hence is truncated. Of course we prefer exact matches. */
1780         cm_InitReq(&req);
1781         thyper.HighPart = 0;
1782         thyper.LowPart = 0;
1783
1784         vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1785         vrock.match = NULL;
1786         vrock.matchType = 0;
1787
1788         cm_HoldSCache(cm_data.rootSCachep);
1789         code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1790                            (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1791         cm_ReleaseSCache(cm_data.rootSCachep);
1792
1793         free(vrock.shareName);
1794         vrock.shareName = NULL;
1795
1796         if (vrock.matchType) {
1797             cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1798             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1799             free(vrock.match);
1800             return 1;
1801         }
1802
1803         /* if we get here, there was no match for the share in root.afs */
1804         /* so try to create  \\<netbiosName>\<cellname>  */
1805         if ( *p == '.' ) {
1806             p++;
1807             rw = 1;
1808         }
1809         /* Get the full name for this cell */
1810         cellname = cm_ClientStringToFsStringAlloc(p, cm_ClientStrLen(p), NULL);
1811         code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1812 #ifdef AFS_AFSDB_ENV
1813         if (code && cm_dnsEnabled) {
1814             int ttl;
1815             code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1816         }
1817 #endif
1818         if (cellname)
1819             free(cellname);
1820
1821         /* construct the path */
1822         if (code == 0) {
1823             clientchar_t temp[1024];
1824
1825             cm_FsStringToClientString(ftemp, cm_FsStrLen(ftemp), temp, 1024);
1826             cm_ClientStrPrintfN(pathName, lengthof(pathName),
1827                                 rw ? _C("/.%S/") : _C("/%S/"), temp);
1828             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1829             return 1;
1830         }
1831     }
1832     /* failure */
1833     *pathNamep = NULL;
1834     return 0;
1835 }
1836
1837 /* Client-side offline caching policy types */
1838 #define CSC_POLICY_MANUAL 0
1839 #define CSC_POLICY_DOCUMENTS 1
1840 #define CSC_POLICY_PROGRAMS 2
1841 #define CSC_POLICY_DISABLE 3
1842
1843 int smb_FindShareCSCPolicy(clientchar_t *shareName)
1844 {
1845     DWORD len;
1846     clientchar_t policy[1024];
1847     DWORD dwType;
1848     HKEY hkCSCPolicy;
1849     int  retval = CSC_POLICY_MANUAL;
1850
1851     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
1852                     AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1853                     0, 
1854                     "AFS", 
1855                     REG_OPTION_NON_VOLATILE,
1856                     KEY_READ,
1857                     NULL, 
1858                     &hkCSCPolicy,
1859                     NULL );
1860
1861     len = sizeof(policy);
1862     if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
1863          len == 0) {
1864         retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1865     }
1866     else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
1867     {
1868         retval = CSC_POLICY_DOCUMENTS;
1869     }
1870     else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
1871     {
1872         retval = CSC_POLICY_PROGRAMS;
1873     }
1874     else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
1875     {
1876         retval = CSC_POLICY_DISABLE;
1877     }
1878         
1879     RegCloseKey(hkCSCPolicy);
1880     return retval;
1881 }
1882
1883 /* find a dir search structure by cookie value, and return it held.
1884  * Must be called with smb_globalLock held.
1885  */
1886 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1887 {
1888     smb_dirSearch_t *dsp;
1889         
1890     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1891         if (dsp->cookie == cookie) {
1892             if (dsp != smb_firstDirSearchp) {
1893                 /* move to head of LRU queue, too, if we're not already there */
1894                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1895                     smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1896                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1897                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1898                 if (!smb_lastDirSearchp)
1899                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1900             }
1901             lock_ObtainMutex(&dsp->mx);
1902             dsp->refCount++;
1903             lock_ReleaseMutex(&dsp->mx);
1904             break;
1905         }
1906     }
1907
1908     if (dsp == NULL) {
1909         osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1910         for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1911             osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1912         }
1913     }
1914     return dsp;
1915 }       
1916
1917 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1918 {
1919     lock_ObtainWrite(&smb_globalLock);
1920     lock_ObtainMutex(&dsp->mx);
1921     osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p", 
1922               dsp->cookie, dsp, dsp->scp);
1923     dsp->flags |= SMB_DIRSEARCH_DELETE;
1924     if (dsp->scp != NULL) {
1925         lock_ObtainWrite(&dsp->scp->rw);
1926         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1927             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1928             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1929             dsp->scp->bulkStatProgress = hzero;
1930         }       
1931         lock_ReleaseWrite(&dsp->scp->rw);
1932     }   
1933     lock_ReleaseMutex(&dsp->mx);
1934     lock_ReleaseWrite(&smb_globalLock);
1935 }               
1936
1937 /* Must be called with the smb_globalLock held */
1938 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1939 {
1940     cm_scache_t *scp = NULL;
1941
1942     lock_ObtainMutex(&dsp->mx);
1943     osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1944     if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1945         if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1946             smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1947         osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1948         lock_ReleaseMutex(&dsp->mx);
1949         lock_FinalizeMutex(&dsp->mx);
1950         scp = dsp->scp;
1951         osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
1952                  dsp->cookie, dsp, scp);
1953         free(dsp);
1954     } else {
1955         lock_ReleaseMutex(&dsp->mx);
1956     }
1957     /* do this now to avoid spurious locking hierarchy creation */
1958     if (scp) 
1959         cm_ReleaseSCache(scp);
1960 }       
1961
1962 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1963 {
1964     lock_ObtainWrite(&smb_globalLock);
1965     smb_ReleaseDirSearchNoLock(dsp);
1966     lock_ReleaseWrite(&smb_globalLock);
1967 }       
1968
1969 /* find a dir search structure by cookie value, and return it held */
1970 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1971 {
1972     smb_dirSearch_t *dsp;
1973
1974     lock_ObtainWrite(&smb_globalLock);
1975     dsp = smb_FindDirSearchNoLock(cookie);
1976     lock_ReleaseWrite(&smb_globalLock);
1977     return dsp;
1978 }
1979
1980 /* GC some dir search entries, in the address space expected by the specific protocol.
1981  * Must be called with smb_globalLock held; release the lock temporarily.
1982  */
1983 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1984 void smb_GCDirSearches(int isV3)
1985 {
1986     smb_dirSearch_t *prevp;
1987     smb_dirSearch_t *tp;
1988     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1989     int victimCount;
1990     int i;
1991         
1992     victimCount = 0;    /* how many have we got so far */
1993     for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1994         /* we'll move tp from queue, so
1995          * do this early.
1996          */
1997         prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1998         /* if no one is using this guy, and we're either in the new protocol,
1999          * or we're in the old one and this is a small enough ID to be useful
2000          * to the old protocol, GC this guy.
2001          */
2002         if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
2003             /* hold and delete */
2004             lock_ObtainMutex(&tp->mx);
2005             tp->flags |= SMB_DIRSEARCH_DELETE;
2006             lock_ReleaseMutex(&tp->mx);
2007             victimsp[victimCount++] = tp;
2008             tp->refCount++;
2009         }
2010
2011         /* don't do more than this */
2012         if (victimCount >= SMB_DIRSEARCH_GCMAX) 
2013             break;
2014     }
2015         
2016     /* now release them */
2017     for (i = 0; i < victimCount; i++) {
2018         smb_ReleaseDirSearchNoLock(victimsp[i]);
2019     }
2020 }
2021
2022 /* function for allocating a dir search entry.  We need these to remember enough context
2023  * since we don't get passed the path from call to call during a directory search.
2024  *
2025  * Returns a held dir search structure, and bumps the reference count on the vnode,
2026  * since it saves a pointer to the vnode.
2027  */
2028 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2029 {
2030     smb_dirSearch_t *dsp;
2031     int counter;
2032     int maxAllowed;
2033     int start;
2034     int wrapped = 0;
2035
2036     lock_ObtainWrite(&smb_globalLock);
2037     counter = 0;
2038
2039     /* what's the biggest ID allowed in this version of the protocol */
2040     /* TODO: do we really want a non v3 dir search request to wrap
2041        smb_dirSearchCounter? */
2042     maxAllowed = isV3 ? 65535 : 255;
2043     if (smb_dirSearchCounter > maxAllowed)
2044         smb_dirSearchCounter = 1;
2045
2046     start = smb_dirSearchCounter;
2047
2048     while (1) {
2049         /* twice so we have enough tries to find guys we GC after one pass;
2050          * 10 extra is just in case I mis-counted.
2051          */
2052         if (++counter > 2*maxAllowed+10) 
2053             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2054
2055         if (smb_dirSearchCounter > maxAllowed) {        
2056             smb_dirSearchCounter = 1;
2057         }
2058         if (smb_dirSearchCounter == start) {
2059             if (wrapped)
2060                 smb_GCDirSearches(isV3);
2061             wrapped++;
2062         }
2063         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2064         if (dsp) {
2065             /* don't need to watch for refcount zero and deleted, since
2066             * we haven't dropped the global lock.
2067             */
2068             lock_ObtainMutex(&dsp->mx);
2069             dsp->refCount--;
2070             lock_ReleaseMutex(&dsp->mx);
2071             ++smb_dirSearchCounter;
2072             continue;
2073         }       
2074
2075         dsp = malloc(sizeof(*dsp));
2076         memset(dsp, 0, sizeof(*dsp));
2077         dsp->cookie = smb_dirSearchCounter;
2078         ++smb_dirSearchCounter;
2079         dsp->refCount = 1;
2080         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2081         dsp->lastTime = osi_Time();
2082         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2083         if (!smb_lastDirSearchp) 
2084             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2085     
2086         osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p", 
2087                  dsp->cookie, dsp);
2088         break;
2089     }   
2090     lock_ReleaseWrite(&smb_globalLock);
2091     return dsp;
2092 }
2093
2094 static smb_packet_t *GetPacket(void)
2095 {
2096     smb_packet_t *tbp;
2097
2098     lock_ObtainWrite(&smb_globalLock);
2099     tbp = smb_packetFreeListp;
2100     if (tbp) 
2101         smb_packetFreeListp = tbp->nextp;
2102     lock_ReleaseWrite(&smb_globalLock);
2103     if (!tbp) {
2104         tbp = calloc(sizeof(*tbp),1);
2105         tbp->magic = SMB_PACKETMAGIC;
2106         tbp->ncbp = NULL;
2107         tbp->vcp = NULL;
2108         tbp->resumeCode = 0;
2109         tbp->inCount = 0;
2110         tbp->fid = 0;
2111         tbp->wctp = NULL;
2112         tbp->inCom = 0;
2113         tbp->oddByte = 0;
2114         tbp->ncb_length = 0;
2115         tbp->flags = 0;
2116         tbp->spacep = NULL;
2117         tbp->stringsp = NULL;
2118     }
2119     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2120
2121     return tbp;
2122 }
2123
2124 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2125 {
2126     smb_packet_t *tbp;
2127     tbp = GetPacket();
2128     memcpy(tbp, pkt, sizeof(smb_packet_t));
2129     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2130     tbp->stringsp = NULL;
2131     if (tbp->vcp)
2132         smb_HoldVC(tbp->vcp);
2133     return tbp;
2134 }
2135
2136 static NCB *GetNCB(void)
2137 {
2138     smb_ncb_t *tbp;
2139     NCB *ncbp;
2140
2141     lock_ObtainWrite(&smb_globalLock);
2142     tbp = smb_ncbFreeListp;
2143     if (tbp) 
2144         smb_ncbFreeListp = tbp->nextp;
2145     lock_ReleaseWrite(&smb_globalLock);
2146     if (!tbp) {
2147         tbp = calloc(sizeof(*tbp),1);
2148         tbp->magic = SMB_NCBMAGIC;
2149     }
2150         
2151     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2152
2153     memset(&tbp->ncb, 0, sizeof(NCB));
2154     ncbp = &tbp->ncb;
2155     return ncbp;
2156 }
2157
2158 static void FreeSMBStrings(smb_packet_t * pkt)
2159 {
2160     cm_space_t * s;
2161     cm_space_t * ns;
2162
2163     for (s = pkt->stringsp; s; s = ns) {
2164         ns = s->nextp;
2165         cm_FreeSpace(s);
2166     }
2167     pkt->stringsp = NULL;
2168 }
2169
2170 void smb_FreePacket(smb_packet_t *tbp)
2171 {
2172     smb_vc_t * vcp = NULL;
2173     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2174         
2175     lock_ObtainWrite(&smb_globalLock);
2176     tbp->nextp = smb_packetFreeListp;
2177     smb_packetFreeListp = tbp;
2178     tbp->magic = SMB_PACKETMAGIC;
2179     tbp->ncbp = NULL;
2180     vcp = tbp->vcp;
2181     tbp->vcp = NULL;
2182     tbp->resumeCode = 0;
2183     tbp->inCount = 0;
2184     tbp->fid = 0;
2185     tbp->wctp = NULL;
2186     tbp->inCom = 0;
2187     tbp->oddByte = 0;
2188     tbp->ncb_length = 0;
2189     tbp->flags = 0;
2190     FreeSMBStrings(tbp);
2191     lock_ReleaseWrite(&smb_globalLock);
2192
2193     if (vcp)
2194         smb_ReleaseVC(vcp);
2195 }
2196
2197 static void FreeNCB(NCB *bufferp)
2198 {
2199     smb_ncb_t *tbp;
2200         
2201     tbp = (smb_ncb_t *) bufferp;
2202     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2203         
2204     lock_ObtainWrite(&smb_globalLock);
2205     tbp->nextp = smb_ncbFreeListp;
2206     smb_ncbFreeListp = tbp;
2207     lock_ReleaseWrite(&smb_globalLock);
2208 }
2209
2210 /* get a ptr to the data part of a packet, and its count */
2211 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2212 {
2213     int parmBytes;
2214     int dataBytes;
2215     unsigned char *afterParmsp;
2216
2217     parmBytes = *smbp->wctp << 1;
2218     afterParmsp = smbp->wctp + parmBytes + 1;
2219         
2220     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2221     if (nbytesp) *nbytesp = dataBytes;
2222         
2223     /* don't forget to skip the data byte count, since it follows
2224      * the parameters; that's where the "2" comes from below.
2225      */
2226     return (unsigned char *) (afterParmsp + 2);
2227 }
2228
2229 /* must set all the returned parameters before playing around with the
2230  * data region, since the data region is located past the end of the
2231  * variable number of parameters.
2232  */
2233 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2234 {
2235     unsigned char *afterParmsp;
2236
2237     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2238         
2239     *afterParmsp++ = dsize & 0xff;
2240     *afterParmsp = (dsize>>8) & 0xff;
2241 }       
2242
2243 /* return the parm'th parameter in the smbp packet */
2244 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2245 {
2246     int parmCount;
2247     unsigned char *parmDatap;
2248
2249     parmCount = *smbp->wctp;
2250
2251     if (parm >= parmCount) {
2252         char s[100];
2253
2254         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2255                 parm, parmCount, smbp->ncb_length);
2256         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2257                  parm, parmCount, smbp->ncb_length);
2258         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2259                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2260         osi_panic(s, __FILE__, __LINE__);
2261     }
2262     parmDatap = smbp->wctp + (2*parm) + 1;
2263         
2264     return parmDatap[0] + (parmDatap[1] << 8);
2265 }
2266
2267 /* return the parm'th parameter in the smbp packet */
2268 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2269 {
2270     int parmCount;
2271     unsigned char *parmDatap;
2272
2273     parmCount = *smbp->wctp;
2274
2275     if (parm >= parmCount) {
2276         char s[100];
2277
2278         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2279                 parm, parmCount, smbp->ncb_length);
2280         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2281                  parm, parmCount, smbp->ncb_length);
2282         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2283                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2284         osi_panic(s, __FILE__, __LINE__);
2285     }
2286     parmDatap = smbp->wctp + (2*parm) + 1;
2287         
2288     return parmDatap[0];
2289 }
2290
2291 /* return the parm'th parameter in the smbp packet */
2292 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2293 {
2294     int parmCount;
2295     unsigned char *parmDatap;
2296
2297     parmCount = *smbp->wctp;
2298
2299     if (parm + 1 >= parmCount) {
2300         char s[100];
2301
2302         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2303                 parm, parmCount, smbp->ncb_length);
2304         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2305                  parm, parmCount, smbp->ncb_length);
2306         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2307                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2308         osi_panic(s, __FILE__, __LINE__);
2309     }
2310     parmDatap = smbp->wctp + (2*parm) + 1;
2311         
2312     return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2313 }
2314
2315 /* return the parm'th parameter in the smbp packet */
2316 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2317 {
2318     int parmCount;
2319     unsigned char *parmDatap;
2320
2321     parmCount = *smbp->wctp;
2322
2323     if (parm * 2 + offset >= parmCount * 2) {
2324         char s[100];
2325
2326         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2327                 parm, offset, parmCount, smbp->ncb_length);
2328         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
2329                  __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2330         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2331                 parm, offset, parmCount, smbp->ncb_length);
2332         osi_panic(s, __FILE__, __LINE__);
2333     }
2334     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2335         
2336     return parmDatap[0] + (parmDatap[1] << 8);
2337 }
2338
2339 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2340 {
2341     unsigned char *parmDatap;
2342
2343     /* make sure we have enough slots */
2344     if (*smbp->wctp <= slot) 
2345         *smbp->wctp = slot+1;
2346         
2347     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2348     *parmDatap++ = parmValue & 0xff;
2349     *parmDatap = (parmValue>>8) & 0xff;
2350 }       
2351
2352 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2353 {
2354     unsigned char *parmDatap;
2355
2356     /* make sure we have enough slots */
2357     if (*smbp->wctp <= slot) 
2358         *smbp->wctp = slot+2;
2359
2360     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2361     *parmDatap++ = parmValue & 0xff;
2362     *parmDatap++ = (parmValue>>8) & 0xff;
2363     *parmDatap++ = (parmValue>>16) & 0xff;
2364     *parmDatap   = (parmValue>>24) & 0xff;
2365 }
2366
2367 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2368 {
2369     unsigned char *parmDatap;
2370     int i;
2371
2372     /* make sure we have enough slots */
2373     if (*smbp->wctp <= slot) 
2374         *smbp->wctp = slot+4;
2375
2376     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2377     for (i=0; i<8; i++)
2378         *parmDatap++ = *parmValuep++;
2379 }       
2380
2381 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2382 {
2383     unsigned char *parmDatap;
2384
2385     /* make sure we have enough slots */
2386     if (*smbp->wctp <= slot) {
2387         if (smbp->oddByte) {
2388             smbp->oddByte = 0;
2389             *smbp->wctp = slot+1;
2390         } else
2391             smbp->oddByte = 1;
2392     }
2393
2394     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2395     *parmDatap++ = parmValue & 0xff;
2396 }
2397
2398
2399
2400 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2401                             clientchar_t *inPathp)
2402 {
2403     clientchar_t *lastSlashp;
2404         
2405     lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2406     if (lastComponentp)
2407         *lastComponentp = lastSlashp;
2408     if (lastSlashp) {
2409         while (1) {
2410             if (inPathp == lastSlashp) 
2411                 break;
2412             *outPathp++ = *inPathp++;
2413         }
2414         *outPathp++ = 0;
2415     }
2416     else {
2417         *outPathp++ = 0;
2418     }
2419 }
2420
2421 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2422                                   char **chainpp, int flags)
2423 {
2424     size_t cb;
2425
2426     if (*inp++ != 0x4) 
2427         return NULL;
2428
2429 #ifdef SMB_UNICODE
2430     if (!WANTS_UNICODE(pktp))
2431         flags |= SMB_STRF_FORCEASCII;
2432 #endif
2433
2434     cb = sizeof(pktp->data) - (inp - pktp->data);
2435     if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2436 #ifdef DEBUG_UNICODE
2437         DebugBreak();
2438 #endif
2439         cb = sizeof(pktp->data);
2440     }
2441     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2442 }
2443
2444 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2445                               char ** chainpp, int flags)
2446 {
2447     size_t cb;
2448
2449 #ifdef SMB_UNICODE
2450     if (!WANTS_UNICODE(pktp))
2451         flags |= SMB_STRF_FORCEASCII;
2452 #endif
2453
2454     cb = sizeof(pktp->data) - (inp - pktp->data);
2455     if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2456 #ifdef DEBUG_UNICODE
2457         DebugBreak();
2458 #endif
2459         cb = sizeof(pktp->data);
2460     }
2461     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2462 }
2463
2464 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2465                                 size_t cb, char ** chainpp, int flags)
2466 {
2467 #ifdef SMB_UNICODE
2468     if (!WANTS_UNICODE(pktp))
2469         flags |= SMB_STRF_FORCEASCII;
2470 #endif
2471
2472     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2473 }
2474
2475 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2476                                  size_t cch, char ** chainpp, int flags)
2477 {
2478     size_t cb = cch;
2479
2480 #ifdef SMB_UNICODE
2481     if (!WANTS_UNICODE(pktp))
2482         flags |= SMB_STRF_FORCEASCII;
2483     else
2484         cb = cch * sizeof(wchar_t);
2485 #endif
2486
2487     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2488 }
2489
2490 clientchar_t *
2491 smb_ParseStringBuf(const char * bufbase,
2492                    cm_space_t ** stringspp,
2493                    unsigned char *inp, size_t *pcb_max,
2494                    char **chainpp, int flags)
2495 {
2496 #ifdef SMB_UNICODE
2497     if (!(flags & SMB_STRF_FORCEASCII)) {
2498         size_t cch_src;
2499         cm_space_t * spacep;
2500         int    null_terms = 0;
2501
2502         if (bufbase && ((inp - bufbase) % 2) != 0) {
2503             inp++;              /* unicode strings are always word aligned */
2504         }
2505
2506         if (*pcb_max > 0) {
2507             if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2508                                         &cch_src))) {
2509                 cch_src = *pcb_max / sizeof(wchar_t);
2510                 *pcb_max = 0;
2511                 null_terms = 0;
2512             } else {
2513                 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2514                 null_terms = 1;
2515             }
2516         } else {
2517             cch_src = 0;
2518         }
2519
2520         spacep = cm_GetSpace();
2521         spacep->nextp = *stringspp;
2522         *stringspp = spacep;
2523
2524         if (cch_src == 0) {
2525             if (chainpp) {
2526                 *chainpp = inp + sizeof(wchar_t);
2527             }
2528
2529             *(spacep->wdata) = 0;
2530             return spacep->wdata;
2531         }
2532
2533         StringCchCopyNW(spacep->wdata,
2534                         lengthof(spacep->wdata),
2535                         (const clientchar_t *) inp, cch_src);
2536
2537         if (chainpp)
2538             *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2539
2540         return spacep->wdata;
2541
2542     } else {
2543 #endif
2544         cm_space_t * spacep;
2545         int cchdest;
2546
2547         /* Not using Unicode */
2548         if (chainpp) {
2549             *chainpp = inp + strlen(inp) + 1;
2550         }
2551
2552         spacep = cm_GetSpace();
2553         spacep->nextp = *stringspp;
2554         *stringspp = spacep;
2555
2556         cchdest = lengthof(spacep->wdata);
2557         cm_Utf8ToUtf16(inp, *pcb_max, spacep->wdata, cchdest);
2558
2559         return spacep->wdata;
2560 #ifdef SMB_UNICODE
2561     }
2562 #endif
2563 }
2564
2565 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2566                             clientchar_t * str,
2567                             size_t * plen, int flags)
2568 {
2569     size_t buffersize;
2570     int align = 0;
2571
2572     if (outp == NULL) {
2573         /* we are only calculating the required size */
2574
2575         if (plen == NULL)
2576             return NULL;
2577
2578 #ifdef SMB_UNICODE
2579
2580         if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2581
2582             StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2583             if (!(flags & SMB_STRF_IGNORENULL))
2584                 *plen += sizeof(wchar_t);
2585
2586             return (unsigned char *) 1; /* return TRUE if we are using unicode */
2587         }
2588         else
2589 #endif
2590         {
2591             /* Storing ANSI */
2592
2593             int cch_str;
2594             int cch_dest;
2595
2596             cch_str = cm_ClientStrLen(str);
2597             cch_dest = cm_ClientStringToUtf8(str, cch_str, NULL, 0);
2598
2599             if (plen)
2600                 *plen = ((flags & SMB_STRF_IGNORENULL)? cch_dest: cch_dest+1);
2601
2602             return NULL;
2603         }
2604
2605         /* Not reached. */
2606     }
2607
2608     /* if outp != NULL ... */
2609
2610     /* Number of bytes left in the buffer.
2611
2612        If outp lies inside the packet data buffer, we assume that the
2613        buffer is the packet data buffer.  Otherwise we assume that the
2614        buffer is sizeof(packet->data).
2615
2616     */
2617     if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2618         align = ((outp - pktp->data) % 2);
2619         buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2620     } else {
2621         align = (((size_t) outp) % 2);
2622         buffersize = sizeof(pktp->data);
2623     }
2624
2625 #ifdef SMB_UNICODE
2626
2627     if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2628         int nchars;
2629
2630         if (align)
2631             *outp++ = '\0';
2632
2633         if (*str == _C('\0')) {
2634
2635             if (buffersize < sizeof(wchar_t))
2636                 return NULL;
2637
2638             *((wchar_t *) outp) = L'\0';
2639             if (plen && !(flags & SMB_STRF_IGNORENULL))
2640                 *plen += sizeof(wchar_t);
2641             return outp + sizeof(wchar_t);
2642         }
2643
2644         nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, buffersize / sizeof(wchar_t));
2645         if (nchars == 0) {
2646             osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2647                      osi_LogSaveClientString(smb_logp, str),
2648                      GetLastError());
2649             return NULL;
2650         }
2651
2652         if (plen)
2653             *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENULL)? nchars - 1: nchars);
2654
2655         return outp + sizeof(wchar_t) * nchars;
2656     }
2657     else
2658 #endif
2659     {
2660         /* Storing ANSI */
2661         size_t cch_dest;
2662
2663         cch_dest = cm_ClientStringToUtf8(str, -1, outp, buffersize);
2664
2665         if (plen)
2666             *plen += ((flags & SMB_STRF_IGNORENULL)? cch_dest - 1: cch_dest);
2667
2668         return outp + cch_dest;
2669     }
2670 }
2671
2672 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2673 {
2674     int tlen;
2675
2676     if (*inp++ != 0x5) 
2677         return NULL;
2678     tlen = inp[0] + (inp[1]<<8);
2679     inp += 2;           /* skip length field */
2680
2681     if (chainpp) {
2682         *chainpp = inp + tlen;
2683     }
2684         
2685     if (lengthp) 
2686         *lengthp = tlen;
2687         
2688     return inp;
2689 }       
2690
2691 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2692 {
2693     int tlen;
2694
2695     if (*inp++ != 0x1) return NULL;
2696     tlen = inp[0] + (inp[1]<<8);
2697     inp += 2;           /* skip length field */
2698         
2699     if (chainpp) {
2700         *chainpp = inp + tlen;
2701     }   
2702
2703     if (lengthp) *lengthp = tlen;
2704         
2705     return inp;
2706 }
2707
2708 /* format a packet as a response */
2709 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2710 {
2711     smb_t *outp;
2712     smb_t *inSmbp;
2713
2714     outp = (smb_t *) op;
2715         
2716     /* zero the basic structure through the smb_wct field, and zero the data
2717      * size field, assuming that wct stays zero; otherwise, you have to 
2718      * explicitly set the data size field, too.
2719      */
2720     inSmbp = (smb_t *) inp;
2721     memset(outp, 0, sizeof(smb_t)+2);
2722     outp->id[0] = 0xff;
2723     outp->id[1] = 'S';
2724     outp->id[2] = 'M';
2725     outp->id[3] = 'B';
2726     if (inp) {
2727         outp->com = inSmbp->com;
2728         outp->tid = inSmbp->tid;
2729         outp->pid = inSmbp->pid;
2730         outp->uid = inSmbp->uid;
2731         outp->mid = inSmbp->mid;
2732         outp->res[0] = inSmbp->res[0];
2733         outp->res[1] = inSmbp->res[1];
2734         op->inCom = inSmbp->com;
2735     }
2736     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2737 #ifdef SEND_CANONICAL_PATHNAMES
2738     outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2739 #endif
2740     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2741 #ifdef SMB_UNICODE
2742     if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2743         outp->flg2 |= SMB_FLAGS2_UNICODE;
2744 #endif
2745
2746     /* copy fields in generic packet area */
2747     op->wctp = &outp->wct;
2748 }       
2749
2750 /* send a (probably response) packet; vcp tells us to whom to send it.
2751  * we compute the length by looking at wct and bcc fields.
2752  */
2753 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2754 {
2755     NCB *ncbp;
2756     int extra;
2757     long code = 0;
2758     unsigned char *tp;
2759     int localNCB = 0;
2760         
2761     ncbp = inp->ncbp;
2762     if (ncbp == NULL) {
2763         ncbp = GetNCB();
2764         localNCB = 1;
2765     }
2766  
2767     memset((char *)ncbp, 0, sizeof(NCB));
2768
2769     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
2770     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
2771     extra += tp[0] + (tp[1]<<8);
2772     extra += (unsigned int)(inp->wctp - inp->data);     /* distance to last wct field */
2773     extra += 3;                 /* wct and length fields */
2774         
2775     ncbp->ncb_length = extra;   /* bytes to send */
2776     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
2777     ncbp->ncb_lana_num = vcp->lana;
2778     ncbp->ncb_command = NCBSEND;        /* op means send data */
2779     ncbp->ncb_buffer = (char *) inp;/* packet */
2780     code = Netbios(ncbp);
2781         
2782     if (code != 0) {
2783         const char * s = ncb_error_string(code);
2784         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2785         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2786
2787         lock_ObtainMutex(&vcp->mx);
2788         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2789             osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2790                       vcp, vcp->usersp);
2791             vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2792             lock_ReleaseMutex(&vcp->mx);
2793             lock_ObtainWrite(&smb_globalLock);
2794             dead_sessions[vcp->session] = TRUE;
2795             lock_ReleaseWrite(&smb_globalLock);
2796             smb_CleanupDeadVC(vcp);
2797         } else {
2798             lock_ReleaseMutex(&vcp->mx);
2799         }
2800     }
2801
2802     if (localNCB)
2803         FreeNCB(ncbp);
2804 }
2805
2806 void smb_MapNTError(long code, unsigned long *NTStatusp)
2807 {
2808     unsigned long NTStatus;
2809
2810     /* map CM_ERROR_* errors to NT 32-bit status codes */
2811     /* NT Status codes are listed in ntstatus.h not winerror.h */
2812     if (code == CM_ERROR_NOSUCHCELL) {
2813         NTStatus = 0xC000000FL; /* No such file */
2814     }
2815     else if (code == CM_ERROR_NOSUCHVOLUME) {
2816         NTStatus = 0xC000000FL; /* No such file */
2817     }
2818     else if (code == CM_ERROR_TIMEDOUT) {
2819 #ifdef COMMENT
2820         NTStatus = 0xC00000CFL; /* Sharing Paused */
2821 #else
2822         NTStatus = 0x00000102L; /* Timeout */
2823 #endif
2824     }
2825     else if (code == CM_ERROR_RETRY) {
2826         NTStatus = 0xC000022DL; /* Retry */
2827     }
2828     else if (code == CM_ERROR_NOACCESS) {
2829         NTStatus = 0xC0000022L; /* Access denied */
2830     }
2831     else if (code == CM_ERROR_READONLY) {
2832         NTStatus = 0xC00000A2L; /* Write protected */
2833     }
2834     else if (code == CM_ERROR_NOSUCHFILE ||
2835              code == CM_ERROR_BPLUS_NOMATCH) {
2836         NTStatus = 0xC000000FL; /* No such file */
2837     }
2838     else if (code == CM_ERROR_NOSUCHPATH) {
2839         NTStatus = 0xC000003AL; /* Object path not found */
2840     }           
2841     else if (code == CM_ERROR_TOOBIG) {
2842         NTStatus = 0xC000007BL; /* Invalid image format */
2843     }
2844     else if (code == CM_ERROR_INVAL) {
2845         NTStatus = 0xC000000DL; /* Invalid parameter */
2846     }
2847     else if (code == CM_ERROR_BADFD) {
2848         NTStatus = 0xC0000008L; /* Invalid handle */
2849     }
2850     else if (code == CM_ERROR_BADFDOP) {
2851         NTStatus = 0xC0000022L; /* Access denied */
2852     }
2853     else if (code == CM_ERROR_EXISTS) {
2854         NTStatus = 0xC0000035L; /* Object name collision */
2855     }
2856     else if (code == CM_ERROR_NOTEMPTY) {
2857         NTStatus = 0xC0000101L; /* Directory not empty */
2858     }   
2859     else if (code == CM_ERROR_CROSSDEVLINK) {
2860         NTStatus = 0xC00000D4L; /* Not same device */
2861     }
2862     else if (code == CM_ERROR_NOTDIR) {
2863         NTStatus = 0xC0000103L; /* Not a directory */
2864     }
2865     else if (code == CM_ERROR_ISDIR) {
2866         NTStatus = 0xC00000BAL; /* File is a directory */
2867     }
2868     else if (code == CM_ERROR_BADOP) {
2869 #ifdef COMMENT
2870         /* I have no idea where this comes from */
2871         NTStatus = 0xC09820FFL; /* SMB no support */
2872 #else
2873         NTStatus = 0xC00000BBL;     /* Not supported */
2874 #endif /* COMMENT */
2875     }
2876     else if (code == CM_ERROR_BADSHARENAME) {
2877         NTStatus = 0xC00000CCL; /* Bad network name */
2878     }
2879     else if (code == CM_ERROR_NOIPC) {
2880 #ifdef COMMENT
2881         NTStatus = 0xC0000022L; /* Access Denied */
2882 #else   
2883         NTStatus = 0xC000013DL; /* Remote Resources */
2884 #endif
2885     }
2886     else if (code == CM_ERROR_CLOCKSKEW) {
2887         NTStatus = 0xC0000133L; /* Time difference at DC */
2888     }
2889     else if (code == CM_ERROR_BADTID) {
2890         NTStatus = 0xC0982005L; /* SMB bad TID */
2891     }
2892     else if (code == CM_ERROR_USESTD) {
2893         NTStatus = 0xC09820FBL; /* SMB use standard */
2894     }
2895     else if (code == CM_ERROR_QUOTA) {
2896         NTStatus = 0xC0000044L; /* Quota exceeded */
2897     }
2898     else if (code == CM_ERROR_SPACE) {
2899         NTStatus = 0xC000007FL; /* Disk full */
2900     }
2901     else if (code == CM_ERROR_ATSYS) {
2902         NTStatus = 0xC0000033L; /* Object name invalid */
2903     }
2904     else if (code == CM_ERROR_BADNTFILENAME) {
2905         NTStatus = 0xC0000033L; /* Object name invalid */
2906     }
2907     else if (code == CM_ERROR_WOULDBLOCK) {
2908         NTStatus = 0xC0000055L; /* Lock not granted */
2909     }
2910     else if (code == CM_ERROR_SHARING_VIOLATION) {
2911         NTStatus = 0xC0000043L; /* Sharing violation */
2912     }
2913     else if (code == CM_ERROR_LOCK_CONFLICT) {
2914         NTStatus = 0xC0000054L; /* Lock conflict */
2915     }
2916     else if (code == CM_ERROR_PARTIALWRITE) {
2917         NTStatus = 0xC000007FL; /* Disk full */
2918     }
2919     else if (code == CM_ERROR_BUFFERTOOSMALL) {
2920         NTStatus = 0xC0000023L; /* Buffer too small */
2921     }
2922     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2923         NTStatus = 0xC0000035L; /* Object name collision */
2924     }   
2925     else if (code == CM_ERROR_BADPASSWORD) {
2926         NTStatus = 0xC000006DL; /* unknown username or bad password */
2927     }
2928     else if (code == CM_ERROR_BADLOGONTYPE) {
2929         NTStatus = 0xC000015BL; /* logon type not granted */
2930     }
2931     else if (code == CM_ERROR_GSSCONTINUE) {
2932         NTStatus = 0xC0000016L; /* more processing required */
2933     }
2934     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2935 #ifdef COMMENT
2936         NTStatus = 0xC0000280L; /* reparse point not resolved */
2937 #else
2938         NTStatus = 0xC0000022L; /* Access Denied */
2939 #endif
2940     }
2941     else if (code == CM_ERROR_PATH_NOT_COVERED) {
2942         NTStatus = 0xC0000257L; /* Path Not Covered */
2943     } 
2944     else if (code == CM_ERROR_ALLBUSY) {
2945         NTStatus = 0xC000022DL; /* Retry */
2946     } 
2947     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2948         NTStatus = 0xC00000BEL; /* Bad Network Path */
2949     } 
2950     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
2951         NTStatus = 0xC0000322L; /* No Kerberos key */
2952     } 
2953     else if (code == CM_ERROR_BAD_LEVEL) {
2954         NTStatus = 0xC0000148L; /* Invalid Level */
2955     } 
2956     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
2957         NTStatus = 0xC000007EL; /* Range Not Locked */
2958     } 
2959     else if (code == CM_ERROR_NOSUCHDEVICE) {
2960         NTStatus = 0xC000000EL; /* No Such Device */
2961     }
2962     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
2963         NTStatus = 0xC0000055L; /* Lock Not Granted */
2964     } else {
2965         NTStatus = 0xC0982001L; /* SMB non-specific error */
2966     }
2967
2968     *NTStatusp = NTStatus;
2969     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2970 }       
2971
2972 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2973                       unsigned char *classp)
2974 {
2975     unsigned char class;
2976     unsigned short error;
2977
2978     /* map CM_ERROR_* errors to SMB errors */
2979     if (code == CM_ERROR_NOSUCHCELL) {
2980         class = 1;
2981         error = 3;      /* bad path */
2982     }
2983     else if (code == CM_ERROR_NOSUCHVOLUME) {
2984         class = 1;
2985         error = 3;      /* bad path */
2986     }
2987     else if (code == CM_ERROR_TIMEDOUT) {
2988         class = 2;
2989         error = 81;     /* server is paused */
2990     }
2991     else if (code == CM_ERROR_RETRY) {
2992         class = 2;      /* shouldn't happen */
2993         error = 1;
2994     }
2995     else if (code == CM_ERROR_NOACCESS) {
2996         class = 2;
2997         error = 4;      /* bad access */
2998     }
2999     else if (code == CM_ERROR_READONLY) {
3000         class = 3;
3001         error = 19;     /* read only */
3002     }
3003     else if (code == CM_ERROR_NOSUCHFILE ||
3004              code == CM_ERROR_BPLUS_NOMATCH) {
3005         class = 1;
3006         error = 2;      /* ENOENT! */
3007     }
3008     else if (code == CM_ERROR_NOSUCHPATH) {
3009         class = 1;
3010         error = 3;      /* Bad path */
3011     }
3012     else if (code == CM_ERROR_TOOBIG) {
3013         class = 1;
3014         error = 11;     /* bad format */
3015     }
3016     else if (code == CM_ERROR_INVAL) {
3017         class = 2;      /* server non-specific error code */
3018         error = 1;
3019     }
3020     else if (code == CM_ERROR_BADFD) {
3021         class = 1;
3022         error = 6;      /* invalid file handle */
3023     }
3024     else if (code == CM_ERROR_BADFDOP) {
3025         class = 1;      /* invalid op on FD */
3026         error = 5;
3027     }
3028     else if (code == CM_ERROR_EXISTS) {
3029         class = 1;
3030         error = 80;     /* file already exists */
3031     }
3032     else if (code == CM_ERROR_NOTEMPTY) {
3033         class = 1;
3034         error = 5;      /* delete directory not empty */
3035     }
3036     else if (code == CM_ERROR_CROSSDEVLINK) {
3037         class = 1;
3038         error = 17;     /* EXDEV */
3039     }
3040     else if (code == CM_ERROR_NOTDIR) {
3041         class = 1;      /* bad path */
3042         error = 3;
3043     }
3044     else if (code == CM_ERROR_ISDIR) {
3045         class = 1;      /* access denied; DOS doesn't have a good match */
3046         error = 5;
3047     }       
3048     else if (code == CM_ERROR_BADOP) {
3049         class = 2;
3050         error = 65535;
3051     }
3052     else if (code == CM_ERROR_BADSHARENAME) {
3053         class = 2;
3054         error = 6;
3055     }
3056     else if (code == CM_ERROR_NOIPC) {
3057         class = 2;
3058         error = 4; /* bad access */
3059     }
3060     else if (code == CM_ERROR_CLOCKSKEW) {
3061         class = 1;      /* invalid function */
3062         error = 1;
3063     }
3064     else if (code == CM_ERROR_BADTID) {
3065         class = 2;
3066         error = 5;
3067     }
3068     else if (code == CM_ERROR_USESTD) {
3069         class = 2;
3070         error = 251;
3071     }
3072     else if (code == CM_ERROR_REMOTECONN) {
3073         class = 2;
3074         error = 82;
3075     }
3076     else if (code == CM_ERROR_QUOTA) {
3077         if (vcp->flags & SMB_VCFLAG_USEV3) {
3078             class = 3;
3079             error = 39; /* disk full */
3080         }
3081         else {
3082             class = 1;
3083             error = 5;  /* access denied */
3084         }
3085     }
3086     else if (code == CM_ERROR_SPACE) {
3087         if (vcp->flags & SMB_VCFLAG_USEV3) {
3088             class = 3;
3089             error = 39; /* disk full */
3090         }
3091         else {
3092             class = 1;
3093             error = 5;  /* access denied */
3094         }
3095     }
3096     else if (code == CM_ERROR_PARTIALWRITE) {
3097         class = 3;
3098         error = 39;     /* disk full */
3099     }
3100     else if (code == CM_ERROR_ATSYS) {
3101         class = 1;
3102         error = 2;      /* ENOENT */
3103     }
3104     else if (code == CM_ERROR_WOULDBLOCK) {
3105         class = 1;
3106         error = 33;     /* lock conflict */
3107     }
3108     else if (code == CM_ERROR_LOCK_CONFLICT) {
3109         class = 1;
3110         error = 33;     /* lock conflict */
3111     }
3112     else if (code == CM_ERROR_SHARING_VIOLATION) {
3113         class = 1;
3114         error = 33;     /* lock conflict */
3115     }
3116     else if (code == CM_ERROR_NOFILES) {
3117         class = 1;
3118         error = 18;     /* no files in search */
3119     }
3120     else if (code == CM_ERROR_RENAME_IDENTICAL) {
3121         class = 1;
3122         error = 183;     /* Samba uses this */
3123     }
3124     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3125         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3126         class = 2;
3127         error = 2; /* bad password */
3128     }
3129     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3130         class = 2;
3131         error = 3;     /* bad path */
3132     }
3133     else {
3134         class = 2;
3135         error = 1;
3136     }
3137
3138     *scodep = error;
3139     *classp = class;
3140     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3141 }       
3142
3143 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3144 {
3145     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3146     return CM_ERROR_BADOP;
3147 }
3148
3149 /* SMB_COM_ECHO */
3150 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3151 {
3152     unsigned short EchoCount, i;
3153     char *data, *outdata;
3154     int dataSize;
3155
3156     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3157
3158     for (i=1; i<=EchoCount; i++) {
3159         data = smb_GetSMBData(inp, &dataSize);
3160         smb_SetSMBParm(outp, 0, i);
3161         smb_SetSMBDataLength(outp, dataSize);
3162         outdata = smb_GetSMBData(outp, NULL);
3163         memcpy(outdata, data, dataSize);
3164         smb_SendPacket(vcp, outp);
3165     }
3166
3167     return 0;
3168 }
3169
3170 /* SMB_COM_READ_RAW */
3171 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3172 {
3173     osi_hyper_t offset;
3174     long count, minCount, finalCount;
3175     unsigned short fd;
3176     unsigned pid;
3177     smb_fid_t *fidp;
3178     smb_t *smbp = (smb_t*) inp;
3179     long code = 0;
3180     cm_user_t *userp = NULL;
3181     NCB *ncbp;
3182     int rc;
3183     char *rawBuf = NULL;
3184
3185     rawBuf = NULL;
3186     finalCount = 0;
3187
3188     fd = smb_GetSMBParm(inp, 0);
3189     count = smb_GetSMBParm(inp, 3);
3190     minCount = smb_GetSMBParm(inp, 4);
3191     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3192
3193     if (*inp->wctp == 10) {
3194         /* we were sent a request with 64-bit file offsets */
3195 #ifdef AFS_LARGEFILES
3196         offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3197
3198         if (LargeIntegerLessThanZero(offset)) {
3199             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3200             goto send1;
3201         }
3202 #else
3203         if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3204             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset.  Dropping request.");
3205             goto send1;
3206         } else {
3207             offset.HighPart = 0;
3208         }
3209 #endif
3210     } else {
3211         /* we were sent a request with 32-bit file offsets */
3212         offset.HighPart = 0;
3213     }
3214
3215     osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3216              fd, offset.HighPart, offset.LowPart, count);
3217
3218     fidp = smb_FindFID(vcp, fd, 0);
3219     if (!fidp)
3220         goto send1;
3221
3222     if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3223         smb_CloseFID(vcp, fidp, NULL, 0);
3224         code = CM_ERROR_NOSUCHFILE;
3225         goto send1a;
3226     }
3227
3228
3229     pid = smbp->pid;
3230     {
3231         LARGE_INTEGER LOffset, LLength;
3232         cm_key_t key;
3233
3234         key = cm_GenerateKey(vcp->vcID, pid, fd);
3235
3236         LOffset.HighPart = offset.HighPart;
3237         LOffset.LowPart = offset.LowPart;
3238         LLength.HighPart = 0;
3239         LLength.LowPart = count;
3240
3241         lock_ObtainWrite(&fidp->scp->rw);
3242         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3243         lock_ReleaseWrite(&fidp->scp->rw);
3244     }    
3245     if (code) {
3246         goto send1a;
3247     }
3248
3249     lock_ObtainMutex(&smb_RawBufLock);
3250     if (smb_RawBufs) {
3251         /* Get a raw buf, from head of list */
3252         rawBuf = smb_RawBufs;
3253         smb_RawBufs = *(char **)smb_RawBufs;
3254     }
3255     lock_ReleaseMutex(&smb_RawBufLock);
3256     if (!rawBuf)
3257         goto send1a;
3258
3259     lock_ObtainMutex(&fidp->mx);
3260     if (fidp->flags & SMB_FID_IOCTL)
3261     {
3262         lock_ReleaseMutex(&fidp->mx);
3263         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3264         if (rawBuf) {
3265             /* Give back raw buffer */
3266             lock_ObtainMutex(&smb_RawBufLock);
3267             *((char **) rawBuf) = smb_RawBufs;
3268             
3269             smb_RawBufs = rawBuf;
3270             lock_ReleaseMutex(&smb_RawBufLock);
3271         }
3272
3273         lock_ReleaseMutex(&fidp->mx);
3274         smb_ReleaseFID(fidp);
3275         return rc;
3276     }
3277     lock_ReleaseMutex(&fidp->mx);
3278
3279     userp = smb_GetUserFromVCP(vcp, inp);
3280
3281     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3282
3283     if (code != 0)
3284         goto send;
3285
3286   send:
3287     cm_ReleaseUser(userp);
3288
3289   send1a:
3290     smb_ReleaseFID(fidp);
3291
3292   send1:
3293     ncbp = outp->ncbp;
3294     memset((char *)ncbp, 0, sizeof(NCB));
3295
3296     ncbp->ncb_length = (unsigned short) finalCount;
3297     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3298     ncbp->ncb_lana_num = vcp->lana;
3299     ncbp->ncb_command = NCBSEND;
3300     ncbp->ncb_buffer = rawBuf;
3301
3302     code = Netbios(ncbp);
3303     if (code != 0)
3304         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3305
3306     if (rawBuf) {
3307         /* Give back raw buffer */
3308         lock_ObtainMutex(&smb_RawBufLock);
3309         *((char **) rawBuf) = smb_RawBufs;
3310
3311         smb_RawBufs = rawBuf;
3312         lock_ReleaseMutex(&smb_RawBufLock);
3313     }
3314
3315     return 0;
3316 }
3317
3318 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3319 {
3320     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3321                          ongoingOps - 1);
3322     return 0;
3323 }
3324
3325 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3326 {
3327     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3328                          ongoingOps - 1);
3329     return 0;
3330 }
3331
3332 /* SMB_COM_NEGOTIATE */
3333 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3334 {
3335     char *namep;
3336     char *datap;
3337     int coreProtoIndex;
3338     int v3ProtoIndex;
3339     int NTProtoIndex;
3340     int VistaProtoIndex;
3341     int protoIndex;                             /* index we're using */
3342     int namex;
3343     int dbytes;
3344     int entryLength;
3345     int tcounter;
3346     char protocol_array[10][1024];  /* protocol signature of the client */
3347     int caps;                       /* capabilities */
3348     time_t unixTime;
3349     afs_uint32 dosTime;
3350     TIME_ZONE_INFORMATION tzi;
3351
3352     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3353                          ongoingOps - 1);
3354
3355     namep = smb_GetSMBData(inp, &dbytes);
3356     namex = 0;
3357     tcounter = 0;
3358     coreProtoIndex = -1;                /* not found */
3359     v3ProtoIndex = -1;
3360     NTProtoIndex = -1;
3361     VistaProtoIndex = -1;
3362     while(namex < dbytes) {
3363         osi_Log1(smb_logp, "Protocol %s",
3364                   osi_LogSaveString(smb_logp, namep+1));
3365         strcpy(protocol_array[tcounter], namep+1);
3366
3367         /* namep points at the first protocol, or really, a 0x02
3368          * byte preceding the null-terminated ASCII name.
3369          */
3370         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3371             coreProtoIndex = tcounter;
3372         }       
3373         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3374             v3ProtoIndex = tcounter;
3375         }
3376         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3377             NTProtoIndex = tcounter;
3378         }
3379         else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3380             VistaProtoIndex = tcounter;
3381         }
3382
3383         /* compute size of protocol entry */
3384         entryLength = (int)strlen(namep+1);
3385         entryLength += 2;       /* 0x02 bytes and null termination */
3386
3387         /* advance over this protocol entry */
3388         namex += entryLength;
3389         namep += entryLength;
3390         tcounter++;             /* which proto entry we're looking at */
3391     }
3392
3393     lock_ObtainMutex(&vcp->mx);
3394 #if 0
3395     if (VistaProtoIndex != -1) {
3396         protoIndex = VistaProtoIndex;
3397         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3398     } else 
3399 #endif  
3400         if (NTProtoIndex != -1) {
3401         protoIndex = NTProtoIndex;
3402         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3403     }
3404     else if (v3ProtoIndex != -1) {
3405         protoIndex = v3ProtoIndex;
3406         vcp->flags |= SMB_VCFLAG_USEV3;
3407     }   
3408     else if (coreProtoIndex != -1) {
3409         protoIndex = coreProtoIndex;
3410         vcp->flags |= SMB_VCFLAG_USECORE;
3411     }   
3412     else protoIndex = -1;
3413     lock_ReleaseMutex(&vcp->mx);
3414
3415     if (protoIndex == -1)
3416         return CM_ERROR_INVAL;
3417     else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3418         smb_SetSMBParm(outp, 0, protoIndex);
3419         if (smb_authType != SMB_AUTH_NONE) {
3420             smb_SetSMBParmByte(outp, 1,
3421                                NEGOTIATE_SECURITY_USER_LEVEL |
3422                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
3423         } else {
3424             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3425         }
3426         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
3427         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3428         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
3429         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
3430         /* The session key is not a well documented field however most clients
3431          * will echo back the session key to the server.  Currently we are using
3432          * the same value for all sessions.  We should generate a random value
3433          * and store it into the vcp 
3434          */
3435         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
3436         smb_SetSMBParm(outp, 8, 1);
3437         /* 
3438          * Tried changing the capabilities to support for W2K - defect 117695
3439          * Maybe something else needs to be changed here?
3440          */
3441         /*
3442         if (isWindows2000) 
3443         smb_SetSMBParmLong(outp, 9, 0x43fd);
3444         else 
3445         smb_SetSMBParmLong(outp, 9, 0x251);
3446         */
3447         /* Capabilities: *
3448          * 32-bit error codes *
3449          * and NT Find *
3450          * and NT SMB's *
3451          * and raw mode 
3452          * and DFS
3453          * and Unicode */
3454         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3455 #ifdef DFS_SUPPORT
3456                NTNEGOTIATE_CAPABILITY_DFS |
3457 #endif
3458 #ifdef AFS_LARGEFILES
3459                NTNEGOTIATE_CAPABILITY_LARGEFILES |
3460 #endif
3461                NTNEGOTIATE_CAPABILITY_NTFIND |
3462                NTNEGOTIATE_CAPABILITY_RAWMODE |
3463                NTNEGOTIATE_CAPABILITY_NTSMB;
3464
3465         if ( smb_authType == SMB_AUTH_EXTENDED )
3466             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3467
3468 #ifdef SMB_UNICODE
3469         if ( smb_UseUnicode ) {
3470             caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3471         }
3472 #endif
3473
3474         smb_SetSMBParmLong(outp, 9, caps);
3475         time(&unixTime);
3476         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3477         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3478         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3479
3480         GetTimeZoneInformation(&tzi);
3481         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
3482
3483         if (smb_authType == SMB_AUTH_NTLM) {
3484             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3485             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3486             /* paste in encryption key */
3487             datap = smb_GetSMBData(outp, NULL);
3488             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3489             /* and the faux domain name */
3490             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3491                                   datap + MSV1_0_CHALLENGE_LENGTH,
3492                                   sizeof(outp->data)/sizeof(char) - (datap - outp->data));
3493         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3494             void * secBlob;
3495             int secBlobLength;
3496
3497             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3498
3499             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3500
3501             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3502                         
3503             datap = smb_GetSMBData(outp, NULL);
3504             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3505
3506             if (secBlob) {
3507                 datap += sizeof(smb_ServerGUID);
3508                 memcpy(datap, secBlob, secBlobLength);
3509                 free(secBlob);
3510             }
3511         } else {
3512             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3513             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
3514         }
3515     }
3516     else if (v3ProtoIndex != -1) {
3517         smb_SetSMBParm(outp, 0, protoIndex);
3518
3519         /* NOTE: Extended authentication cannot be negotiated with v3
3520          * therefore we fail over to NTLM 
3521          */
3522         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3523             smb_SetSMBParm(outp, 1,
3524                            NEGOTIATE_SECURITY_USER_LEVEL |
3525                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
3526         } else {
3527             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3528         }
3529         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3530         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
3531         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3532         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
3533         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
3534         smb_SetSMBParm(outp, 7, 1);
3535         time(&unixTime);
3536         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3537         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
3538         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
3539
3540         GetTimeZoneInformation(&tzi);
3541         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
3542
3543         /* NOTE: Extended authentication cannot be negotiated with v3
3544          * therefore we fail over to NTLM 
3545          */
3546         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3547             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
3548             smb_SetSMBParm(outp, 12, 0);        /* resvd */
3549             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
3550             datap = smb_GetSMBData(outp, NULL);
3551             /* paste in a new encryption key */
3552             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3553             /* and the faux domain name */
3554             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3555                                   datap + MSV1_0_CHALLENGE_LENGTH,
3556                                   sizeof(outp->data)/sizeof(char) - (datap - outp->data));
3557         } else {
3558             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3559             smb_SetSMBParm(outp, 12, 0); /* resvd */
3560             smb_SetSMBDataLength(outp, 0);
3561         }
3562     }
3563     else if (coreProtoIndex != -1) {     /* not really supported anymore */
3564         smb_SetSMBParm(outp, 0, protoIndex);
3565         smb_SetSMBDataLength(outp, 0);
3566     }
3567     return 0;
3568 }
3569
3570 void smb_CheckVCs(void)
3571 {
3572     smb_vc_t * vcp, *nextp;
3573     smb_packet_t * outp = GetPacket();
3574     smb_t *smbp;
3575             
3576     lock_ObtainWrite(&smb_rctLock);
3577     for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp ) 
3578     {
3579         if (vcp->magic != SMB_VC_MAGIC)
3580             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
3581                        __FILE__, __LINE__);
3582
3583         nextp = vcp->nextp;
3584
3585         if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3586             continue;
3587
3588         smb_HoldVCNoLock(vcp);
3589         if (nextp)
3590             smb_HoldVCNoLock(nextp);
3591         smb_FormatResponsePacket(vcp, NULL, outp);
3592         smbp = (smb_t *)outp;
3593         outp->inCom = smbp->com = 0x2b /* Echo */;
3594         smbp->tid = 0xFFFF;
3595         smbp->pid = 0;
3596         smbp->uid = 0;
3597         smbp->mid = 0;
3598         smbp->res[0] = 0;
3599         smbp->res[1] = 0;
3600
3601         smb_SetSMBParm(outp, 0, 0);
3602         smb_SetSMBDataLength(outp, 0);
3603         lock_ReleaseWrite(&smb_rctLock);
3604
3605         smb_SendPacket(vcp, outp);
3606
3607         lock_ObtainWrite(&smb_rctLock);
3608         smb_ReleaseVCNoLock(vcp);
3609         if (nextp)
3610             smb_ReleaseVCNoLock(nextp);
3611     }
3612     lock_ReleaseWrite(&smb_rctLock);
3613     smb_FreePacket(outp);
3614 }
3615
3616 void smb_Daemon(void *parmp)
3617 {
3618     afs_uint32 count = 0;
3619     smb_username_t    **unpp;
3620     time_t              now;
3621
3622     while(smbShutdownFlag == 0) {
3623         count++;
3624         thrd_Sleep(10000);
3625
3626         if (smbShutdownFlag == 1)
3627             break;
3628         
3629         if ((count % 72) == 0)  {       /* every five minutes */
3630             struct tm myTime;
3631             time_t old_localZero = smb_localZero;
3632                  
3633             /* Initialize smb_localZero */
3634             myTime.tm_isdst = -1;               /* compute whether on DST or not */
3635             myTime.tm_year = 70;
3636             myTime.tm_mon = 0;
3637             myTime.tm_mday = 1;
3638             myTime.tm_hour = 0;
3639             myTime.tm_min = 0;
3640             myTime.tm_sec = 0;
3641             smb_localZero = mktime(&myTime);
3642
3643 #ifndef USE_NUMERIC_TIME_CONV
3644             smb_CalculateNowTZ();
3645 #endif /* USE_NUMERIC_TIME_CONV */
3646 #ifdef AFS_FREELANCE
3647             if ( smb_localZero != old_localZero )
3648                 cm_noteLocalMountPointChange();
3649 #endif
3650
3651             smb_CheckVCs();
3652         }
3653
3654         /* GC smb_username_t objects that will no longer be used */
3655         now = osi_Time();
3656         lock_ObtainWrite(&smb_rctLock);
3657         for ( unpp=&usernamesp; *unpp; ) {
3658             int deleteOk = 0;
3659             smb_username_t *unp;
3660
3661             lock_ObtainMutex(&(*unpp)->mx);
3662             if ( (*unpp)->refCount > 0 || 
3663                  ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) || 
3664                  !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3665                 ;
3666             else if (!smb_LogoffTokenTransfer ||
3667                      ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3668                 deleteOk = 1;
3669             lock_ReleaseMutex(&(*unpp)->mx);
3670
3671             if (deleteOk) {
3672                 cm_user_t * userp;
3673
3674                 unp = *unpp;    
3675                 *unpp = unp->nextp;
3676                 unp->nextp = NULL;
3677                 lock_FinalizeMutex(&unp->mx);
3678                 userp = unp->userp;
3679                 free(unp->name);
3680                 free(unp->machine);
3681                 free(unp);
3682                 if (userp)
3683                     cm_ReleaseUser(userp);
3684             } else {
3685                 unpp = &(*unpp)->nextp;
3686             }
3687         }
3688         lock_ReleaseWrite(&smb_rctLock);
3689
3690         /* XXX GC dir search entries */
3691     }
3692 }
3693
3694 void smb_WaitingLocksDaemon()
3695 {
3696     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3697     smb_waitingLock_t *wl, *wlNext;
3698     int first;
3699     smb_vc_t *vcp;
3700     smb_packet_t *inp, *outp;
3701     NCB *ncbp;
3702     long code = 0;
3703
3704     while (smbShutdownFlag == 0) {
3705         lock_ObtainWrite(&smb_globalLock);
3706         nwlRequest = smb_allWaitingLocks;
3707         if (nwlRequest == NULL) {
3708             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3709             thrd_Sleep(1000);
3710             continue;
3711         } else {
3712             first = 1;
3713             osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3714         }
3715
3716         do {
3717             if (first)
3718                 first = 0;
3719             else
3720                 lock_ObtainWrite(&smb_globalLock);
3721
3722             osi_Log1(smb_logp, "    Checking waiting lock request %p", nwlRequest);
3723
3724             wlRequest = nwlRequest;
3725             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3726             lock_ReleaseWrite(&smb_globalLock);