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