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