f10f2cfcb1f0b31a63aad381a6cf3972a19f9c63
[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 = "NRC_BUFLEN llegal buffer length";                   break; 
240     case 0x03: s = "NRC_ILLCMD illegal command";                        break; 
241     case 0x05: s = "NRC_CMDTMO command timed out";                      break; 
242     case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break; 
243     case 0x07: s = "NRC_BADDR  illegal buffer address";                 break; 
244     case 0x08: s = "NRC_SNUMOUT session number out of range";           break; 
245     case 0x09: s = "NRC_NORES no resource available";                   break; 
246     case 0x0a: s = "NRC_SCLOSED asession closed";                       break; 
247     case 0x0b: s = "NRC_CMDCAN command cancelled";                      break; 
248     case 0x0d: s = "NRC_DUPNAME duplicate name";                        break; 
249     case 0x0e: s = "NRC_NAMTFUL name table full";                       break; 
250     case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break; 
251     case 0x11: s = "NRC_LOCTFUL local session table full";              break; 
252     case 0x12: s = "NRC_REMTFUL remote session table full";             break; 
253     case 0x13: s = "NRC_ILLNN illegal name number";                     break; 
254     case 0x14: s = "NRC_NOCALL no callname";                            break; 
255     case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME";               break; 
256     case 0x16: s = "NRC_INUSE name in use on remote adapter";           break; 
257     case 0x17: s = "NRC_NAMERR name deleted";                           break; 
258     case 0x18: s = "NRC_SABORT session ended abnormally";               break; 
259     case 0x19: s = "NRC_NAMCONF name conflict detected";                break; 
260     case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying";   break; 
261     case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
262     case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid";             break; 
263     case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break; 
264     case 0x26: s = "NRC_CANCEL command not valid to cancel";            break; 
265     case 0x30: s = "NRC_DUPENV name defined by anther local process";   break; 
266     case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required";      break; 
267     case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted";    break; 
268     case 0x36: s = "NRC_MAXAPPS max number of applications exceeded";   break; 
269     case 0x37: s = "NRC_NOSAPS no saps available for netbios";          break; 
270     case 0x38: s = "NRC_NORESOURCES requested resources are not available";     break; 
271     case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment";    break; 
272     case 0x3B: s = "NRC_INVDDID invalid NCB DDID";                      break; 
273     case 0x3C: s = "NRC_LOCKFAILlock of user area failed";              break; 
274     case 0x3f: s = "NRC_OPENERR NETBIOS not loaded";                    break; 
275     case 0x40: s = "NRC_SYSTEM 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 void smb_MarkAllVCsDead(smb_vc_t * exclude)
823 {
824     smb_vc_t *vcp;
825     smb_vc_t **vcp_to_cleanup = NULL;
826     int n_to_cleanup = 0;
827     int i;
828
829     osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
830
831     lock_ObtainWrite(&smb_globalLock);  /* for dead_sessions[] */
832     lock_ObtainWrite(&smb_rctLock);
833     for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
834
835         if (vcp->magic != SMB_VC_MAGIC)
836             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
837                       __FILE__, __LINE__);
838
839         if (vcp == exclude)
840             continue;
841
842         lock_ObtainMutex(&vcp->mx);
843         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
844             vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
845             lock_ReleaseMutex(&vcp->mx);
846             dead_sessions[vcp->session] = TRUE;
847         } else {
848             lock_ReleaseMutex(&vcp->mx);
849         }
850         n_to_cleanup ++;
851     }
852
853     vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
854     i = 0;
855     for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
856         if (vcp == exclude)
857             continue;
858
859         vcp_to_cleanup[i++] = vcp;
860         smb_HoldVCNoLock(vcp);
861     }
862
863     osi_assert(i == n_to_cleanup);
864
865     lock_ReleaseWrite(&smb_rctLock);
866     lock_ReleaseWrite(&smb_globalLock);
867
868     for (i=0; i < n_to_cleanup; i++) {
869         smb_CleanupDeadVC(vcp_to_cleanup[i]);
870         smb_ReleaseVC(vcp_to_cleanup[i]);
871         vcp_to_cleanup[i] = 0;
872     }
873
874     free(vcp_to_cleanup);
875 }
876
877 #ifdef DEBUG_SMB_REFCOUNT
878 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
879 #else
880 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
881 #endif
882 {
883     smb_vc_t *vcp;
884
885     lock_ObtainWrite(&smb_globalLock);  /* for numVCs */
886     lock_ObtainWrite(&smb_rctLock);
887     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
888         if (vcp->magic != SMB_VC_MAGIC)
889             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
890                        __FILE__, __LINE__);
891
892         lock_ObtainMutex(&vcp->mx);
893         if (lsn == vcp->lsn && lana == vcp->lana &&
894             !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
895             lock_ReleaseMutex(&vcp->mx);
896             smb_HoldVCNoLock(vcp);
897             break;
898         }
899         lock_ReleaseMutex(&vcp->mx);
900     }
901     if (!vcp && (flags & SMB_FLAG_CREATE)) {
902         vcp = malloc(sizeof(*vcp));
903         memset(vcp, 0, sizeof(*vcp));
904         vcp->vcID = ++numVCs;
905         vcp->magic = SMB_VC_MAGIC;
906         vcp->refCount = 2;      /* smb_allVCsp and caller */
907         vcp->tidCounter = 1;
908         vcp->fidCounter = 1;
909         vcp->uidCounter = 1;    /* UID 0 is reserved for blank user */
910         vcp->nextp = smb_allVCsp;
911         smb_allVCsp = vcp;
912         lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
913         vcp->lsn = lsn;
914         vcp->lana = lana;
915         vcp->secCtx = NULL;
916
917         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
918             /* We must obtain a challenge for extended auth 
919              * in case the client negotiates smb v3 
920              */
921             NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
922             MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
923             PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
924             ULONG lsaRespSize = 0;
925
926             lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
927
928             nts = LsaCallAuthenticationPackage( smb_lsaHandle,
929                                                 smb_lsaSecPackage,
930                                                 &lsaReq,
931                                                 sizeof(lsaReq),
932                                                 &lsaResp,
933                                                 &lsaRespSize,
934                                                 &ntsEx);
935             if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
936                 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
937                          nts, ntsEx, sizeof(lsaReq), lsaRespSize);
938                     afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
939                          nts, ntsEx, lsaRespSize);
940             }
941             osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
942
943             if (ntsEx == STATUS_SUCCESS) {
944                 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
945             } else {
946                 /* 
947                  * This will cause the subsequent authentication to fail but
948                  * that is better than us dereferencing a NULL pointer and 
949                  * crashing.
950                  */
951                 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
952             }
953             if (lsaResp)
954                 LsaFreeReturnBuffer(lsaResp);
955         }
956         else
957             memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
958
959         if (numVCs >= CM_SESSION_RESERVED) {
960             numVCs = 0;
961             osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
962         }
963     }
964 #ifdef DEBUG_SMB_REFCOUNT
965     if (vcp) {
966         afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
967         osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
968     }
969 #endif
970     lock_ReleaseWrite(&smb_rctLock);
971     lock_ReleaseWrite(&smb_globalLock);
972     return vcp;
973 }
974
975 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
976 {
977     int i;
978     clientchar_t tc;
979         
980     for(i=0; i<11; i++) {
981         tc = *maskp++;
982         if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
983             return 1;
984     }
985     return 0;
986 }
987
988 static int smb_IsStarMask(clientchar_t *maskp)
989 {
990     clientchar_t tc;
991         
992     while (*maskp) {
993         tc = *maskp++;
994         if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
995             return 1;
996     }
997     return 0;
998 }
999
1000 #ifdef DEBUG_SMB_REFCOUNT
1001 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
1002 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
1003 #else
1004 void smb_ReleaseVCInternal(smb_vc_t *vcp)
1005 #endif
1006 {
1007     smb_vc_t **vcpp;
1008     smb_vc_t * avcp;
1009
1010     lock_AssertWrite(&smb_rctLock);
1011     vcp->refCount--;
1012
1013     if (vcp->refCount == 0) {
1014         if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
1015 #ifdef DEBUG_SMB_REFCOUNT
1016             afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
1017             osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
1018 #endif
1019             /* remove VCP from smb_deadVCsp */
1020             for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1021                 if (*vcpp == vcp) {
1022                     *vcpp = vcp->nextp;
1023                     break;
1024                 }
1025             } 
1026             lock_FinalizeMutex(&vcp->mx);
1027             memset(vcp,0,sizeof(smb_vc_t));
1028             free(vcp);
1029         } else {
1030 #ifdef DEBUG_SMB_REFCOUNT
1031             afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
1032 #endif
1033             for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
1034                 if (avcp == vcp)
1035                     break;
1036             }
1037             osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
1038                       avcp?"":"not ",vcp, vcp->refCount);
1039
1040             /* This is a wrong.  However, I suspect that there is an undercount
1041              * and I don't want to release 1.4.1 in a state that will allow
1042              * smb_vc_t objects to be deallocated while still in the
1043              * smb_allVCsp list.  The list is supposed to keep a reference
1044              * to the smb_vc_t.  Put it back.
1045              */
1046             if (avcp) {
1047                 vcp->refCount++;
1048 #ifdef DEBUG_SMB_REFCOUNT
1049                 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
1050                 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
1051 #endif
1052             }
1053         }
1054     } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
1055         /* The reference count is non-zero but the VC is dead.
1056          * This implies that some FIDs, TIDs, etc on the VC have yet to 
1057          * be cleaned up.  If we were not called by smb_CleanupDeadVC(),
1058          * add a reference that will be dropped by
1059          * smb_CleanupDeadVC() and try to cleanup the VC again.
1060          * Eventually the refCount will drop to zero when all of the
1061          * active threads working with the VC end their task.
1062          */
1063         if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
1064             vcp->refCount++;        /* put the refCount back */
1065             lock_ReleaseWrite(&smb_rctLock);
1066             smb_CleanupDeadVC(vcp);
1067 #ifdef DEBUG_SMB_REFCOUNT
1068             afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1069             osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
1070 #endif
1071             lock_ObtainWrite(&smb_rctLock);
1072         }
1073     } else {
1074 #ifdef DEBUG_SMB_REFCOUNT
1075         afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1076         osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1077 #endif
1078     }
1079 }
1080
1081 #ifdef DEBUG_SMB_REFCOUNT
1082 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1083 #else
1084 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
1085 #endif
1086 {
1087     lock_AssertWrite(&smb_rctLock);
1088     osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1089     smb_ReleaseVCInternal(vcp);
1090 }       
1091
1092 #ifdef DEBUG_SMB_REFCOUNT
1093 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
1094 #else
1095 void smb_ReleaseVC(smb_vc_t *vcp)
1096 #endif
1097 {
1098     lock_ObtainWrite(&smb_rctLock);
1099     osi_Log2(smb_logp,"smb_ReleaseVC       vcp %x ref %d",vcp, vcp->refCount);
1100     smb_ReleaseVCInternal(vcp);
1101     lock_ReleaseWrite(&smb_rctLock);
1102 }       
1103
1104 #ifdef DEBUG_SMB_REFCOUNT
1105 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
1106 #else
1107 void smb_HoldVCNoLock(smb_vc_t *vcp)
1108 #endif
1109 {
1110     lock_AssertWrite(&smb_rctLock);
1111     vcp->refCount++;
1112 #ifdef DEBUG_SMB_REFCOUNT
1113     afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1114     osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1115 #else
1116     osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
1117 #endif
1118 }       
1119
1120 #ifdef DEBUG_SMB_REFCOUNT
1121 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
1122 #else
1123 void smb_HoldVC(smb_vc_t *vcp)
1124 #endif
1125 {
1126     lock_ObtainWrite(&smb_rctLock);
1127     vcp->refCount++;
1128 #ifdef DEBUG_SMB_REFCOUNT
1129     afsi_log("%s:%d smb_HoldVC       vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1130     osi_Log4(smb_logp,"%s:%d smb_HoldVC       vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
1131 #else
1132     osi_Log2(smb_logp,"smb_HoldVC       vcp %x ref %d",vcp, vcp->refCount);
1133 #endif
1134     lock_ReleaseWrite(&smb_rctLock);
1135 }       
1136
1137 void smb_CleanupDeadVC(smb_vc_t *vcp)
1138 {
1139     smb_fid_t *fidpIter;
1140     smb_fid_t *fidpNext;
1141     unsigned short fid;
1142     smb_tid_t *tidpIter;
1143     smb_tid_t *tidpNext;
1144     unsigned short tid;
1145     smb_user_t *uidpIter;
1146     smb_user_t *uidpNext;
1147     smb_vc_t **vcpp;
1148     afs_uint32 refCount = 0;
1149
1150     lock_ObtainMutex(&vcp->mx);
1151     if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1152         lock_ReleaseMutex(&vcp->mx);
1153         osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1154         return;
1155     }
1156     vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1157     lock_ReleaseMutex(&vcp->mx);
1158     osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1159
1160     lock_ObtainWrite(&smb_rctLock);
1161     /* remove VCP from smb_allVCsp */
1162     for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1163         if ((*vcpp)->magic != SMB_VC_MAGIC)
1164             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
1165                        __FILE__, __LINE__);
1166         if (*vcpp == vcp) {
1167             *vcpp = vcp->nextp;
1168             vcp->nextp = smb_deadVCsp;
1169             smb_deadVCsp = vcp;
1170             /* Hold onto the reference until we are done with this function */
1171             break;
1172         }
1173     }
1174
1175     for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1176         fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1177
1178         if (fidpIter->deleteOk)
1179             continue;
1180
1181         fid = fidpIter->fid;
1182         osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1183
1184         smb_HoldFIDNoLock(fidpIter);
1185         lock_ReleaseWrite(&smb_rctLock);
1186
1187         smb_CloseFID(vcp, fidpIter, NULL, 0);
1188         smb_ReleaseFID(fidpIter);
1189
1190         lock_ObtainWrite(&smb_rctLock);
1191         fidpNext = vcp->fidsp;
1192     }
1193
1194     for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1195         tidpNext = tidpIter->nextp;
1196         if (tidpIter->deleteOk)
1197             continue;
1198         tidpIter->deleteOk = 1;
1199
1200         tid = tidpIter->tid;
1201         osi_Log2(smb_logp, "  Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1202
1203         smb_HoldTIDNoLock(tidpIter);
1204         smb_ReleaseTID(tidpIter, TRUE);
1205         tidpNext = vcp->tidsp;
1206     }
1207
1208     for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1209         uidpNext = uidpIter->nextp;
1210         if (uidpIter->deleteOk)
1211             continue;
1212         uidpIter->deleteOk = 1;
1213
1214         /* do not add an additional reference count for the smb_user_t
1215          * as the smb_vc_t already is holding a reference */
1216         lock_ReleaseWrite(&smb_rctLock);
1217
1218         smb_ReleaseUID(uidpIter);
1219
1220         lock_ObtainWrite(&smb_rctLock);
1221         uidpNext = vcp->usersp;
1222     }
1223
1224     /* The vcp is now on the deadVCsp list.  We intentionally drop the
1225      * reference so that the refcount can reach 0 and we can delete it 
1226      *
1227      * If the refCount == 1 going into the ReleaseVCNoLock call 
1228      * the object will be freed and it won't be safe to clear 
1229      * the flag.
1230      */
1231     refCount = vcp->refCount;
1232     smb_ReleaseVCNoLock(vcp);
1233     if (refCount > 1) {
1234         lock_ObtainMutex(&vcp->mx);
1235         vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1236         lock_ReleaseMutex(&vcp->mx);
1237     }
1238
1239     lock_ReleaseWrite(&smb_rctLock);
1240     osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1241 }
1242
1243 #ifdef DEBUG_SMB_REFCOUNT
1244 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1245 #else
1246 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1247 #endif
1248 {
1249     smb_tid_t *tidp;
1250
1251     lock_ObtainWrite(&smb_rctLock);
1252   retry:
1253     for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1254         if (tidp->refCount == 0 && tidp->deleteOk) {
1255             tidp->refCount++;
1256             smb_ReleaseTID(tidp, TRUE);
1257             goto retry;
1258         }
1259
1260         if (tid == tidp->tid) {
1261             tidp->refCount++;
1262             break;
1263         }
1264     }
1265     if (!tidp && (flags & SMB_FLAG_CREATE)) {
1266         tidp = malloc(sizeof(*tidp));
1267         memset(tidp, 0, sizeof(*tidp));
1268         tidp->nextp = vcp->tidsp;
1269         tidp->refCount = 1;
1270         tidp->vcp = vcp;
1271         smb_HoldVCNoLock(vcp);
1272         vcp->tidsp = tidp;
1273         lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1274         tidp->tid = tid;
1275     }
1276 #ifdef DEBUG_SMB_REFCOUNT
1277     if (tidp) {
1278         afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1279         osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1280     }
1281 #endif
1282     lock_ReleaseWrite(&smb_rctLock);
1283     return tidp;
1284 }
1285
1286 #ifdef DEBUG_SMB_REFCOUNT
1287 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1288 #else
1289 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1290 #endif
1291 {
1292     lock_AssertWrite(&smb_rctLock);
1293     tidp->refCount++;
1294 #ifdef DEBUG_SMB_REFCOUNT
1295     afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1296     osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1297 #endif
1298 }
1299
1300 #ifdef DEBUG_SMB_REFCOUNT
1301 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1302 #else
1303 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1304 #endif
1305 {
1306     smb_tid_t *tp;
1307     smb_tid_t **ltpp;
1308     cm_user_t *userp = NULL;
1309     smb_vc_t  *vcp = NULL;
1310
1311     if (!locked)
1312         lock_ObtainWrite(&smb_rctLock);
1313     else
1314         lock_AssertWrite(&smb_rctLock);
1315
1316     osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1317 #ifdef DEBUG_SMB_REFCOUNT
1318     afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1319     osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1320 #endif
1321     if (tidp->refCount == 0) {
1322         if (tidp->deleteOk) {
1323             ltpp = &tidp->vcp->tidsp;
1324             for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1325                 if (tp == tidp) 
1326                     break;
1327             }
1328             osi_assertx(tp != NULL, "null smb_tid_t");
1329             *ltpp = tp->nextp;
1330             lock_FinalizeMutex(&tidp->mx);
1331             userp = tidp->userp;        /* remember to drop ref later */
1332             tidp->userp = NULL;
1333             vcp = tidp->vcp;
1334             tidp->vcp = NULL;
1335             free(tidp);
1336         }
1337     }
1338     if (vcp)
1339         smb_ReleaseVCNoLock(vcp);
1340     if (!locked)
1341         lock_ReleaseWrite(&smb_rctLock);
1342     if (userp)
1343         cm_ReleaseUser(userp);
1344 }               
1345
1346 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1347 {
1348     smb_user_t *uidp = NULL;
1349
1350     lock_ObtainWrite(&smb_rctLock);
1351     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1352         if (uid == uidp->userID) {
1353             uidp->refCount++;
1354             osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1355                      vcp, uidp->userID, 
1356                      ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1357             break;
1358         }
1359     }
1360     if (!uidp && (flags & SMB_FLAG_CREATE)) {
1361         uidp = malloc(sizeof(*uidp));
1362         memset(uidp, 0, sizeof(*uidp));
1363         uidp->nextp = vcp->usersp;
1364         uidp->refCount = 2; /* one for the vcp and one for the caller */
1365         uidp->vcp = vcp;
1366         smb_HoldVCNoLock(vcp);
1367         vcp->usersp = uidp;
1368         lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1369         uidp->userID = uid;
1370         osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1371                  vcp, uidp->userID,
1372                  ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1373     }
1374     lock_ReleaseWrite(&smb_rctLock);
1375     return uidp;
1376 }               
1377
1378 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1379                                    afs_uint32 flags)
1380 {
1381     smb_username_t *unp= NULL;
1382
1383     lock_ObtainWrite(&smb_rctLock);
1384     for(unp = usernamesp; unp; unp = unp->nextp) {
1385         if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1386             cm_ClientStrCmpI(unp->machine, machine) == 0) {
1387             unp->refCount++;
1388             break;
1389         }
1390     }
1391     if (!unp && (flags & SMB_FLAG_CREATE)) {
1392         unp = malloc(sizeof(*unp));
1393         memset(unp, 0, sizeof(*unp));
1394         unp->refCount = 1;
1395         unp->nextp = usernamesp;
1396         unp->name = cm_ClientStrDup(usern);
1397         unp->machine = cm_ClientStrDup(machine);
1398         usernamesp = unp;
1399         lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1400         if (flags & SMB_FLAG_AFSLOGON)
1401             unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1402     }
1403
1404     lock_ReleaseWrite(&smb_rctLock);
1405     return unp;
1406 }       
1407
1408 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1409 {
1410     smb_user_t *uidp= NULL;
1411
1412     lock_ObtainWrite(&smb_rctLock);
1413     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1414         if (!uidp->unp) 
1415             continue;
1416         if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1417             uidp->refCount++;
1418             osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1419                      vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1420             break;
1421         } else
1422             continue;
1423     }           
1424     lock_ReleaseWrite(&smb_rctLock);
1425     return uidp;
1426 }       
1427
1428 void smb_ReleaseUsername(smb_username_t *unp)
1429 {
1430     smb_username_t *up;
1431     smb_username_t **lupp;
1432     cm_user_t *userp = NULL;
1433     time_t      now = osi_Time();
1434
1435     lock_ObtainWrite(&smb_rctLock);
1436     osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1437     if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1438         (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1439         lupp = &usernamesp;
1440         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1441             if (up == unp) 
1442                 break;
1443         }
1444         osi_assertx(up != NULL, "null smb_username_t");
1445         *lupp = up->nextp;
1446         up->nextp = NULL;                       /* do not remove this */
1447         lock_FinalizeMutex(&unp->mx);
1448         userp = unp->userp;
1449         free(unp->name);
1450         free(unp->machine);
1451         free(unp);
1452     }
1453     lock_ReleaseWrite(&smb_rctLock);
1454     if (userp)
1455         cm_ReleaseUser(userp);
1456 }       
1457
1458 void smb_HoldUIDNoLock(smb_user_t *uidp)
1459 {
1460     lock_AssertWrite(&smb_rctLock);
1461     uidp->refCount++;
1462 }
1463
1464 void smb_ReleaseUID(smb_user_t *uidp)
1465 {
1466     smb_user_t *up;
1467     smb_user_t **lupp;
1468     smb_username_t *unp = NULL;
1469
1470     lock_ObtainWrite(&smb_rctLock);
1471     osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1472     if (uidp->refCount == 0) {
1473         lupp = &uidp->vcp->usersp;
1474         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1475             if (up == uidp) 
1476                 break;
1477         }
1478         osi_assertx(up != NULL, "null smb_user_t");
1479         *lupp = up->nextp;
1480         lock_FinalizeMutex(&uidp->mx);
1481         unp = uidp->unp;
1482         smb_ReleaseVCNoLock(uidp->vcp);
1483         uidp->vcp = NULL;
1484         free(uidp);
1485     }           
1486     lock_ReleaseWrite(&smb_rctLock);
1487
1488     if (unp) {
1489         if (unp->userp)
1490             cm_ReleaseUserVCRef(unp->userp);
1491         smb_ReleaseUsername(unp);
1492     }
1493 }       
1494
1495 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1496 {
1497     cm_user_t *up = NULL;
1498
1499     if (!uidp)
1500         return NULL;
1501     
1502     lock_ObtainMutex(&uidp->mx);
1503     if (uidp->unp) {
1504         up = uidp->unp->userp;
1505         cm_HoldUser(up);
1506     }
1507     lock_ReleaseMutex(&uidp->mx);
1508
1509     return up;
1510 }
1511
1512
1513 /* retrieve a held reference to a user structure corresponding to an incoming
1514  * request.
1515  * corresponding release function is cm_ReleaseUser.
1516  */
1517 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1518 {
1519     smb_user_t *uidp;
1520     cm_user_t *up = NULL;
1521     smb_t *smbp;
1522
1523     smbp = (smb_t *) inp;
1524     uidp = smb_FindUID(vcp, smbp->uid, 0);
1525     if (!uidp)
1526         return NULL;
1527     
1528     up = smb_GetUserFromUID(uidp);
1529
1530     smb_ReleaseUID(uidp);
1531     return up;
1532 }
1533
1534 /*
1535  * Return a pointer to a pathname extracted from a TID structure.  The
1536  * TID structure is not held; assume it won't go away.
1537  */
1538 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1539 {
1540     smb_tid_t *tidp;
1541     long code = 0;
1542
1543     tidp = smb_FindTID(vcp, tid, 0);
1544     if (!tidp) {
1545         *treepath = NULL;
1546     } else {
1547         if (tidp->flags & SMB_TIDFLAG_IPC) {
1548             code = CM_ERROR_TIDIPC;
1549             /* tidp->pathname would be NULL, but that's fine */
1550         }
1551         *treepath = tidp->pathname;
1552         smb_ReleaseTID(tidp, FALSE);
1553     }
1554     return code;
1555 }
1556
1557 /* check to see if we have a chained fid, that is, a fid that comes from an
1558  * OpenAndX message that ran earlier in this packet.  In this case, the fid
1559  * field in a read, for example, request, isn't set, since the value is
1560  * supposed to be inherited from the openAndX call.
1561  */
1562 int smb_ChainFID(int fid, smb_packet_t *inp)
1563 {
1564     if (inp->fid == 0 || inp->inCount == 0) 
1565         return fid;
1566     else 
1567         return inp->fid;
1568 }
1569
1570 /* are we a priv'd user?  What does this mean on NT? */
1571 int smb_SUser(cm_user_t *userp)
1572 {
1573     return 1;
1574 }
1575
1576 /* find a file ID.  If we pass in 0 we select an unused File ID.
1577  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
1578  * smb_fid_t data structure if desired File ID cannot be found.
1579  */
1580 #ifdef DEBUG_SMB_REFCOUNT
1581 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1582 #else
1583 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1584 #endif
1585 {
1586     smb_fid_t *fidp;
1587     int newFid = 0;
1588         
1589     if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1590         return NULL;
1591
1592     lock_ObtainWrite(&smb_rctLock);
1593     /* figure out if we need to allocate a new file ID */
1594     if (fid == 0) {
1595         newFid = 1;
1596         fid = vcp->fidCounter;
1597     }
1598
1599   retry:
1600     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1601         if (fidp->refCount == 0 && fidp->deleteOk) {
1602             fidp->refCount++;
1603             lock_ReleaseWrite(&smb_rctLock);
1604             smb_ReleaseFID(fidp);
1605             lock_ObtainWrite(&smb_rctLock);
1606             goto retry;
1607         }
1608         if (fid == fidp->fid) {
1609             if (newFid) {
1610                 fid++;
1611                 if (fid == 0xFFFF) {
1612                     osi_Log1(smb_logp,
1613                              "New FID number wraps on vcp 0x%x", vcp);
1614                     fid = 1;
1615                 }
1616                 goto retry;
1617             }
1618             fidp->refCount++;
1619             break;
1620         }
1621     }
1622
1623     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1624         char eventName[MAX_PATH];
1625         EVENT_HANDLE event;
1626         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1627         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1628         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1629             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1630             thrd_CloseHandle(event);
1631             fid++;
1632             if (fid == 0xFFFF) {
1633                 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1634                 fid = 1;
1635             }
1636             goto retry;
1637         }
1638
1639         fidp = malloc(sizeof(*fidp));
1640         memset(fidp, 0, sizeof(*fidp));
1641         osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1642         fidp->refCount = 1;
1643         fidp->vcp = vcp;
1644         smb_HoldVCNoLock(vcp);
1645         lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1646         fidp->fid = fid;
1647         fidp->curr_chunk = fidp->prev_chunk = -2;
1648         fidp->raw_write_event = event;
1649         if (newFid) {
1650             vcp->fidCounter = fid+1;
1651             if (vcp->fidCounter == 0xFFFF) {
1652                 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1653                          vcp);
1654                 vcp->fidCounter = 1;
1655             }
1656         }
1657     }
1658
1659 #ifdef DEBUG_SMB_REFCOUNT
1660     if (fidp) {
1661         afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1662         osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1663     }
1664 #endif
1665     lock_ReleaseWrite(&smb_rctLock);
1666     return fidp;
1667 }
1668
1669
1670 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1671 #ifdef DEBUG_SMB_REFCOUNT
1672 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1673 #else
1674 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1675 #endif
1676 {
1677     smb_fid_t *fidp = NULL, *nextp = NULL;
1678         
1679     if (!scp)
1680         return NULL;
1681
1682     /* 
1683      * If the fidp->scp changes out from under us then
1684      * we must not grab a refCount.  It means the *fidp
1685      * was processed by smb_CloseFID() and the *fidp is 
1686      * no longer valid for use.
1687      */
1688     lock_ObtainWrite(&smb_rctLock);
1689         for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1690         nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1691         if (nextp)
1692             nextp->refCount++;
1693
1694         if (scp == fidp->scp) {
1695             lock_ReleaseWrite(&smb_rctLock);
1696             lock_ObtainMutex(&fidp->mx);
1697             lock_ObtainWrite(&smb_rctLock);
1698             if (scp == fidp->scp) {
1699                 lock_ReleaseMutex(&fidp->mx);
1700                 break;
1701             }
1702             lock_ReleaseMutex(&fidp->mx);
1703         }
1704
1705         if (fidp->refCount > 1) {
1706             fidp->refCount--;
1707         } else {
1708             lock_ReleaseWrite(&smb_rctLock);
1709             smb_ReleaseFID(fidp);
1710             lock_ObtainWrite(&smb_rctLock);
1711         }
1712     }
1713
1714     if (nextp) {
1715         if (nextp->refCount > 1) {
1716             nextp->refCount--;
1717         } else {
1718             lock_ReleaseWrite(&smb_rctLock);
1719             smb_ReleaseFID(nextp);
1720             lock_ObtainWrite(&smb_rctLock);
1721         }
1722     }
1723
1724 #ifdef DEBUG_SMB_REFCOUNT
1725     if (fidp) {
1726         afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1727         osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1728       }
1729 #endif
1730     lock_ReleaseWrite(&smb_rctLock);
1731     return (fidp);
1732 }
1733
1734 #ifdef DEBUG_SMB_REFCOUNT
1735 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1736 #else
1737 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1738 #endif
1739 {
1740     lock_AssertWrite(&smb_rctLock);
1741     fidp->refCount++;
1742 #ifdef DEBUG_SMB_REFCOUNT
1743     afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1744     osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1745 #endif
1746 }
1747
1748
1749 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1750 /* the smb_fid_t->mx and smb_rctLock must not be held */
1751 #ifdef DEBUG_SMB_REFCOUNT
1752 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1753 #else
1754 void smb_ReleaseFID(smb_fid_t *fidp)
1755 #endif
1756 {
1757     cm_scache_t *scp = NULL;
1758     cm_user_t *userp = NULL;
1759     smb_vc_t *vcp = NULL;
1760     smb_ioctl_t *ioctlp;
1761
1762     lock_ObtainMutex(&fidp->mx);
1763     lock_ObtainWrite(&smb_rctLock);
1764     osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1765 #ifdef DEBUG_SMB_REFCOUNT
1766     afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1767     osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1768 #endif
1769     if (fidp->refCount == 0) {
1770         if (fidp->deleteOk) {
1771             vcp = fidp->vcp;
1772             fidp->vcp = NULL;
1773             scp = fidp->scp;    /* release after lock is released */
1774             if (scp) {
1775                 lock_ObtainWrite(&scp->rw);
1776                 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1777                 lock_ReleaseWrite(&scp->rw);
1778                 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1779                 fidp->scp = NULL;
1780             }
1781             userp = fidp->userp;
1782             fidp->userp = NULL;
1783
1784             if (vcp->fidsp) 
1785                 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1786             thrd_CloseHandle(fidp->raw_write_event);
1787
1788             /* and see if there is ioctl stuff to free */
1789             ioctlp = fidp->ioctlp;
1790             if (ioctlp) {
1791                 if (ioctlp->prefix)
1792                 cm_FreeSpace(ioctlp->prefix);
1793                 if (ioctlp->ioctl.inAllocp)
1794                     free(ioctlp->ioctl.inAllocp);
1795                 if (ioctlp->ioctl.outAllocp)
1796                     free(ioctlp->ioctl.outAllocp);
1797                 free(ioctlp);
1798             }       
1799             lock_ReleaseMutex(&fidp->mx);
1800             lock_FinalizeMutex(&fidp->mx);
1801             free(fidp);
1802             fidp = NULL;
1803
1804             if (vcp)
1805                 smb_ReleaseVCNoLock(vcp);
1806         }
1807     }
1808     if (fidp)
1809         lock_ReleaseMutex(&fidp->mx);
1810
1811     lock_ReleaseWrite(&smb_rctLock);
1812
1813     /* now release the scache structure */
1814     if (scp) 
1815         cm_ReleaseSCache(scp);
1816
1817     if (userp)
1818         cm_ReleaseUser(userp);
1819 }       
1820
1821 /*
1822  * Case-insensitive search for one string in another;
1823  * used to find variable names in submount pathnames.
1824  */
1825 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1826 {
1827     clientchar_t *cursor;
1828
1829     for (cursor = str1; *cursor; cursor++)
1830         if (cm_ClientStrCmpI(cursor, str2) == 0)
1831             return cursor;
1832
1833     return NULL;
1834 }
1835
1836 /*
1837  * Substitute a variable value for its name in a submount pathname.  Variable
1838  * name has been identified by smb_stristr() and is in substr.  Variable name
1839  * length (plus one) is in substr_size.  Variable value is in newstr.
1840  */
1841 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1842                       unsigned int substr_size, clientchar_t *newstr)
1843 {
1844     clientchar_t temp[1024];
1845
1846     cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1847     cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1848     cm_ClientStrCat(str1, cchstr1, temp);
1849 }
1850
1851 clientchar_t VNUserName[] = _C("%USERNAME%");
1852 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1853 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1854 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1855
1856 typedef struct smb_findShare_rock {
1857     clientchar_t * shareName;
1858     clientchar_t * match;
1859     int matchType;
1860 } smb_findShare_rock_t;
1861
1862 #define SMB_FINDSHARE_EXACT_MATCH 1
1863 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1864
1865 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1866                        osi_hyper_t *offp)
1867 {
1868     int matchType = 0;
1869     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1870     normchar_t normName[MAX_PATH];
1871
1872     if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1873         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1874                  osi_LogSaveString(smb_logp, dep->name));
1875         return 0;
1876     }
1877
1878     if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1879         if(!cm_ClientStrCmpI(normName, vrock->shareName))
1880             matchType = SMB_FINDSHARE_EXACT_MATCH;
1881         else
1882             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1883         if(vrock->match) 
1884             free(vrock->match);
1885         vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1886         vrock->matchType = matchType;
1887
1888         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1889             return CM_ERROR_STOPNOW;
1890     }
1891     return 0;
1892 }
1893
1894
1895 /* find a shareName in the table of submounts */
1896 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1897                   clientchar_t *shareName,
1898                   clientchar_t **pathNamep)
1899 {
1900     DWORD cblen;
1901     DWORD cchlen;
1902     clientchar_t pathName[1024];
1903     clientchar_t *var;
1904     DWORD sizeTemp;
1905     clientchar_t *p, *q;
1906     fschar_t *cellname = NULL;
1907     HKEY parmKey;
1908     DWORD code;
1909     DWORD allSubmount = 1;
1910
1911     /* if allSubmounts == 0, only return the //mountRoot/all share 
1912      * if in fact it has been been created in the subMounts table.  
1913      * This is to allow sites that want to restrict access to the 
1914      * world to do so.
1915      */
1916     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1917                         0, KEY_QUERY_VALUE, &parmKey);
1918     if (code == ERROR_SUCCESS) {
1919         cblen = sizeof(allSubmount);
1920         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1921                                (BYTE *) &allSubmount, &cblen);
1922         if (code != ERROR_SUCCESS) {
1923             allSubmount = 1;
1924         }
1925         RegCloseKey (parmKey);
1926     }
1927
1928     if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1929         *pathNamep = NULL;
1930         return 1;
1931     }
1932
1933     /* In case, the all share is disabled we need to still be able
1934      * to handle ioctl requests 
1935      */
1936     if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1937         *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1938         return 1;
1939     }
1940
1941     if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1942         cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1943         cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1944         cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1945         cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1946         ) {
1947         *pathNamep = NULL;
1948         return 0;
1949     }
1950
1951     /* Check for volume references
1952      * 
1953      * They look like <cell>{%,#}<volume>
1954      */
1955     if (cm_ClientStrChr(shareName, '%') != NULL ||
1956         cm_ClientStrChr(shareName, '#') != NULL) {
1957         clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1958         /* make room for '/@vol:' + mountchar + NULL terminator*/
1959
1960         osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1961                  osi_LogSaveClientString(smb_logp, shareName));
1962
1963         cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1964                             _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1965         cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1966
1967         *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1968         if (*pathNamep) {
1969             cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1970             cm_ClientStrLwr(*pathNamep);
1971             osi_Log1(smb_logp, "   returning pathname [%S]",
1972                      osi_LogSaveClientString(smb_logp, *pathNamep));
1973
1974             return 1;
1975         } else {
1976             return 0;
1977         }
1978     }
1979
1980     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1981                         0, KEY_QUERY_VALUE, &parmKey);
1982     if (code == ERROR_SUCCESS) {
1983         cblen = sizeof(pathName);
1984         code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1985                                 (BYTE *) pathName, &cblen);
1986         if (code != ERROR_SUCCESS)
1987             cblen = 0;
1988         RegCloseKey (parmKey);
1989     } else {
1990         cblen = 0;
1991     }
1992     cchlen = cblen / sizeof(clientchar_t);
1993     if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1994         /* We can accept either unix or PC style AFS pathnames.  Convert
1995          * Unix-style to PC style here for internal use. 
1996          */
1997         p = pathName;
1998         cchlen = lengthof(pathName);
1999
2000         /* within this code block, we maintain, cchlen = writeable
2001            buffer length of p */
2002
2003         if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
2004             p += cm_mountRootCLen;  /* skip mount path */
2005             cchlen -= (DWORD)(p - pathName);
2006         }
2007
2008         q = p;
2009         while (*q) {
2010             if (*q == _C('/')) *q = _C('\\');    /* change to \ */
2011             q++;
2012         }
2013
2014         while (1)
2015         {
2016             clientchar_t temp[1024];
2017
2018             if (var = smb_stristr(p, VNUserName)) {
2019                 if (uidp && uidp->unp)
2020                     smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
2021                 else
2022                     smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
2023             }
2024             else if (var = smb_stristr(p, VNLCUserName)) 
2025             {
2026                 if (uidp && uidp->unp)
2027                     cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
2028                 else 
2029                     cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
2030                 cm_ClientStrLwr(temp);
2031                 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
2032             }
2033             else if (var = smb_stristr(p, VNComputerName)) 
2034             {
2035                 sizeTemp = lengthof(temp);
2036                 GetComputerNameW(temp, &sizeTemp);
2037                 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
2038             }
2039             else if (var = smb_stristr(p, VNLCComputerName)) 
2040             {
2041                 sizeTemp = lengthof(temp);
2042                 GetComputerName((LPTSTR)temp, &sizeTemp);
2043                 cm_ClientStrLwr(temp);
2044                 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
2045             }
2046             else     
2047                 break;
2048         }
2049         *pathNamep = cm_ClientStrDup(p);
2050         return 1;
2051     } 
2052     else
2053     {
2054         /* First lookup shareName in root.afs */
2055         cm_req_t req;
2056         smb_findShare_rock_t vrock;
2057         osi_hyper_t thyper;
2058         fschar_t ftemp[1024];
2059         clientchar_t * p = shareName; 
2060         int rw = 0;
2061
2062         /*  attempt to locate a partial match in root.afs.  This is because
2063             when using the ANSI RAP calls, the share name is limited to 13 chars
2064             and hence is truncated. Of course we prefer exact matches. */
2065         smb_InitReq(&req);
2066         thyper.HighPart = 0;
2067         thyper.LowPart = 0;
2068
2069         vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
2070         if (vrock.shareName == NULL) 
2071             return 0;
2072         vrock.match = NULL;
2073         vrock.matchType = 0;
2074
2075         cm_HoldSCache(cm_data.rootSCachep);
2076         code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
2077                            (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
2078         cm_ReleaseSCache(cm_data.rootSCachep);
2079
2080         free(vrock.shareName);
2081         vrock.shareName = NULL;
2082
2083         if (vrock.matchType) {
2084             cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
2085             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2086             free(vrock.match);
2087             return 1;
2088         }
2089
2090         /* if we get here, there was no match for the share in root.afs */
2091         /* so try to create  \\<netbiosName>\<cellname>  */
2092         if ( *p == '.' ) {
2093             p++;
2094             rw = 1;
2095         }
2096         /* Get the full name for this cell */
2097         cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2098         code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
2099         if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
2100             code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2101 #ifdef AFS_AFSDB_ENV
2102         if (code && cm_dnsEnabled) {
2103             int ttl;
2104             code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2105         }
2106 #endif
2107         if (cellname)
2108             free(cellname);
2109
2110         /* construct the path */
2111         if (code == 0) {
2112             clientchar_t temp[1024];
2113
2114             if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2115             cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2116                                 rw ? _C("/.%S/") : _C("/%S/"), temp);
2117             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2118             return 1;
2119         }
2120     }
2121     }
2122     /* failure */
2123     *pathNamep = NULL;
2124     return 0;
2125 }
2126
2127 /* Client-side offline caching policy types */
2128 #define CSC_POLICY_MANUAL 0
2129 #define CSC_POLICY_DOCUMENTS 1
2130 #define CSC_POLICY_PROGRAMS 2
2131 #define CSC_POLICY_DISABLE 3
2132
2133 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2134 {
2135     DWORD len;
2136     clientchar_t policy[1024];
2137     DWORD dwType;
2138     HKEY hkCSCPolicy;
2139     int  retval = CSC_POLICY_MANUAL;
2140
2141     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
2142                     AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2143                     0, 
2144                     "AFS", 
2145                     REG_OPTION_NON_VOLATILE,
2146                     KEY_READ,
2147                     NULL, 
2148                     &hkCSCPolicy,
2149                     NULL );
2150
2151     len = sizeof(policy);
2152     if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2153          len == 0) {
2154         retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2155     }
2156     else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2157     {
2158         retval = CSC_POLICY_DOCUMENTS;
2159     }
2160     else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2161     {
2162         retval = CSC_POLICY_PROGRAMS;
2163     }
2164     else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2165     {
2166         retval = CSC_POLICY_DISABLE;
2167     }
2168         
2169     RegCloseKey(hkCSCPolicy);
2170     return retval;
2171 }
2172
2173 /* find a dir search structure by cookie value, and return it held.
2174  * Must be called with smb_globalLock held.
2175  */
2176 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2177 {
2178     smb_dirSearch_t *dsp;
2179         
2180     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2181         if (dsp->cookie == cookie) {
2182             if (dsp != smb_firstDirSearchp) {
2183                 /* move to head of LRU queue, too, if we're not already there */
2184                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2185                     smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2186                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2187                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2188                 if (!smb_lastDirSearchp)
2189                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2190             }
2191             dsp->refCount++;
2192             break;
2193         }
2194     }
2195
2196     if (dsp == NULL) {
2197         osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2198         for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2199             osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2200         }
2201     }
2202     return dsp;
2203 }       
2204
2205 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2206 {
2207     lock_ObtainMutex(&dsp->mx);
2208     osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p", 
2209               dsp->cookie, dsp, dsp->scp);
2210     dsp->flags |= SMB_DIRSEARCH_DELETE;
2211     if (dsp->scp != NULL) {
2212         lock_ObtainWrite(&dsp->scp->rw);
2213         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2214             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2215             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2216             dsp->scp->bulkStatProgress = hzero;
2217         }       
2218         lock_ReleaseWrite(&dsp->scp->rw);
2219     }   
2220     lock_ReleaseMutex(&dsp->mx);
2221 }               
2222
2223 /* Must be called with the smb_globalLock held */
2224 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2225 {
2226     cm_scache_t *scp = NULL;
2227
2228     osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2229     if (dsp->refCount == 0) {
2230         lock_ObtainMutex(&dsp->mx);
2231         if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2232             if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2233                 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2234             osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2235             lock_ReleaseMutex(&dsp->mx);
2236             lock_FinalizeMutex(&dsp->mx);
2237             scp = dsp->scp;
2238             osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
2239                      dsp->cookie, dsp, scp);
2240             free(dsp);
2241         } else {
2242             lock_ReleaseMutex(&dsp->mx);
2243         }
2244     }
2245     /* do this now to avoid spurious locking hierarchy creation */
2246     if (scp) 
2247         cm_ReleaseSCache(scp);
2248 }       
2249
2250 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2251 {
2252     lock_ObtainWrite(&smb_globalLock);
2253     smb_ReleaseDirSearchNoLock(dsp);
2254     lock_ReleaseWrite(&smb_globalLock);
2255 }       
2256
2257 /* find a dir search structure by cookie value, and return it held */
2258 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2259 {
2260     smb_dirSearch_t *dsp;
2261
2262     lock_ObtainWrite(&smb_globalLock);
2263     dsp = smb_FindDirSearchNoLock(cookie);
2264     lock_ReleaseWrite(&smb_globalLock);
2265     return dsp;
2266 }
2267
2268 /* GC some dir search entries, in the address space expected by the specific protocol.
2269  * Must be called with smb_globalLock held; release the lock temporarily.
2270  */
2271 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
2272 void smb_GCDirSearches(int isV3)
2273 {
2274     smb_dirSearch_t *prevp;
2275     smb_dirSearch_t *dsp;
2276     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2277     int victimCount;
2278     int i;
2279         
2280     victimCount = 0;    /* how many have we got so far */
2281     for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2282         /* we'll move tp from queue, so
2283          * do this early.
2284          */
2285         prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q); 
2286         /* if no one is using this guy, and we're either in the new protocol,
2287          * or we're in the old one and this is a small enough ID to be useful
2288          * to the old protocol, GC this guy.
2289          */
2290         if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2291             /* hold and delete */
2292             lock_ObtainMutex(&dsp->mx);
2293             dsp->flags |= SMB_DIRSEARCH_DELETE;
2294             lock_ReleaseMutex(&dsp->mx);
2295             victimsp[victimCount++] = dsp;
2296             dsp->refCount++;
2297         }
2298
2299         /* don't do more than this */
2300         if (victimCount >= SMB_DIRSEARCH_GCMAX) 
2301             break;
2302     }
2303         
2304     /* now release them */
2305     for (i = 0; i < victimCount; i++) {
2306         smb_ReleaseDirSearchNoLock(victimsp[i]);
2307     }
2308 }
2309
2310 /* function for allocating a dir search entry.  We need these to remember enough context
2311  * since we don't get passed the path from call to call during a directory search.
2312  *
2313  * Returns a held dir search structure, and bumps the reference count on the vnode,
2314  * since it saves a pointer to the vnode.
2315  */
2316 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2317 {
2318     smb_dirSearch_t *dsp;
2319     int counter;
2320     int maxAllowed;
2321     int start;
2322     int wrapped = 0;
2323
2324     lock_ObtainWrite(&smb_globalLock);
2325     counter = 0;
2326
2327     /* what's the biggest ID allowed in this version of the protocol */
2328     /* TODO: do we really want a non v3 dir search request to wrap
2329        smb_dirSearchCounter? */
2330     maxAllowed = isV3 ? 65535 : 255;
2331     if (smb_dirSearchCounter > maxAllowed)
2332         smb_dirSearchCounter = 1;
2333
2334     start = smb_dirSearchCounter;
2335
2336     while (1) {
2337         /* twice so we have enough tries to find guys we GC after one pass;
2338          * 10 extra is just in case I mis-counted.
2339          */
2340         if (++counter > 2*maxAllowed+10) 
2341             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2342
2343         if (smb_dirSearchCounter > maxAllowed) {        
2344             smb_dirSearchCounter = 1;
2345         }
2346         if (smb_dirSearchCounter == start) {
2347             if (wrapped)
2348                 smb_GCDirSearches(isV3);
2349             wrapped++;
2350         }
2351         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2352         if (dsp) {
2353             /* don't need to watch for refcount zero and deleted, since
2354             * we haven't dropped the global lock.
2355             */
2356             dsp->refCount--;
2357             ++smb_dirSearchCounter;
2358             continue;
2359         }       
2360
2361         dsp = malloc(sizeof(*dsp));
2362         memset(dsp, 0, sizeof(*dsp));
2363         dsp->cookie = smb_dirSearchCounter;
2364         ++smb_dirSearchCounter;
2365         dsp->refCount = 1;
2366         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2367         dsp->lastTime = osi_Time();
2368         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2369         if (!smb_lastDirSearchp) 
2370             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2371     
2372         osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p", 
2373                  dsp->cookie, dsp);
2374         break;
2375     }   
2376     lock_ReleaseWrite(&smb_globalLock);
2377     return dsp;
2378 }
2379
2380 static smb_packet_t *smb_GetPacket(void)
2381 {
2382     smb_packet_t *tbp;
2383
2384     lock_ObtainWrite(&smb_globalLock);
2385     tbp = smb_packetFreeListp;
2386     if (tbp) 
2387         smb_packetFreeListp = tbp->nextp;
2388     lock_ReleaseWrite(&smb_globalLock);
2389     if (!tbp) {
2390         tbp = calloc(sizeof(*tbp),1);
2391         tbp->magic = SMB_PACKETMAGIC;
2392         tbp->ncbp = NULL;
2393         tbp->vcp = NULL;
2394         tbp->resumeCode = 0;
2395         tbp->inCount = 0;
2396         tbp->fid = 0;
2397         tbp->wctp = NULL;
2398         tbp->inCom = 0;
2399         tbp->oddByte = 0;
2400         tbp->ncb_length = 0;
2401         tbp->flags = 0;
2402         tbp->spacep = NULL;
2403         tbp->stringsp = NULL;
2404     }
2405     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2406
2407     return tbp;
2408 }
2409
2410 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2411 {
2412     smb_packet_t *tbp;
2413     tbp = smb_GetPacket();
2414     memcpy(tbp, pkt, sizeof(smb_packet_t));
2415     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2416     tbp->stringsp = NULL;
2417     if (tbp->vcp)
2418         smb_HoldVC(tbp->vcp);
2419     return tbp;
2420 }
2421
2422 static NCB *smb_GetNCB(void)
2423 {
2424     smb_ncb_t *tbp;
2425     NCB *ncbp;
2426
2427     lock_ObtainWrite(&smb_globalLock);
2428     tbp = smb_ncbFreeListp;
2429     if (tbp) 
2430         smb_ncbFreeListp = tbp->nextp;
2431     lock_ReleaseWrite(&smb_globalLock);
2432     if (!tbp) {
2433         tbp = calloc(sizeof(*tbp),1);
2434         tbp->magic = SMB_NCBMAGIC;
2435     }
2436         
2437     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2438
2439     memset(&tbp->ncb, 0, sizeof(NCB));
2440     ncbp = &tbp->ncb;
2441     return ncbp;
2442 }
2443
2444 static void FreeSMBStrings(smb_packet_t * pkt)
2445 {
2446     cm_space_t * s;
2447     cm_space_t * ns;
2448
2449     for (s = pkt->stringsp; s; s = ns) {
2450         ns = s->nextp;
2451         cm_FreeSpace(s);
2452     }
2453     pkt->stringsp = NULL;
2454 }
2455
2456 void smb_FreePacket(smb_packet_t *tbp)
2457 {
2458     smb_vc_t * vcp = NULL;
2459     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2460         
2461     lock_ObtainWrite(&smb_globalLock);
2462     tbp->nextp = smb_packetFreeListp;
2463     smb_packetFreeListp = tbp;
2464     tbp->magic = SMB_PACKETMAGIC;
2465     tbp->ncbp = NULL;
2466     vcp = tbp->vcp;
2467     tbp->vcp = NULL;
2468     tbp->resumeCode = 0;
2469     tbp->inCount = 0;
2470     tbp->fid = 0;
2471     tbp->wctp = NULL;
2472     tbp->inCom = 0;
2473     tbp->oddByte = 0;
2474     tbp->ncb_length = 0;
2475     tbp->flags = 0;
2476     FreeSMBStrings(tbp);
2477     lock_ReleaseWrite(&smb_globalLock);
2478
2479     if (vcp)
2480         smb_ReleaseVC(vcp);
2481 }
2482
2483 static void smb_FreeNCB(NCB *bufferp)
2484 {
2485     smb_ncb_t *tbp;
2486         
2487     tbp = (smb_ncb_t *) bufferp;
2488     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2489         
2490     lock_ObtainWrite(&smb_globalLock);
2491     tbp->nextp = smb_ncbFreeListp;
2492     smb_ncbFreeListp = tbp;
2493     lock_ReleaseWrite(&smb_globalLock);
2494 }
2495
2496 /* get a ptr to the data part of a packet, and its count */
2497 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2498 {
2499     int parmBytes;
2500     int dataBytes;
2501     unsigned char *afterParmsp;
2502
2503     parmBytes = *smbp->wctp << 1;
2504     afterParmsp = smbp->wctp + parmBytes + 1;
2505         
2506     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2507     if (nbytesp) *nbytesp = dataBytes;
2508         
2509     /* don't forget to skip the data byte count, since it follows
2510      * the parameters; that's where the "2" comes from below.
2511      */
2512     return (unsigned char *) (afterParmsp + 2);
2513 }
2514
2515 /* must set all the returned parameters before playing around with the
2516  * data region, since the data region is located past the end of the
2517  * variable number of parameters.
2518  */
2519 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2520 {
2521     unsigned char *afterParmsp;
2522
2523     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2524         
2525     *afterParmsp++ = dsize & 0xff;
2526     *afterParmsp = (dsize>>8) & 0xff;
2527 }       
2528
2529 /* return the parm'th parameter in the smbp packet */
2530 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2531 {
2532     int parmCount;
2533     unsigned char *parmDatap;
2534
2535     parmCount = *smbp->wctp;
2536
2537     if (parm >= parmCount) {
2538         char s[100];
2539
2540         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2541                 parm, parmCount, smbp->ncb_length);
2542         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2543                  parm, parmCount, smbp->ncb_length);
2544         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2545                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2546         osi_panic(s, __FILE__, __LINE__);
2547     }
2548     parmDatap = smbp->wctp + (2*parm) + 1;
2549         
2550     return parmDatap[0] + (parmDatap[1] << 8);
2551 }
2552
2553 /* return the parm'th parameter in the smbp packet */
2554 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2555 {
2556     int parmCount;
2557     unsigned char *parmDatap;
2558
2559     parmCount = *smbp->wctp;
2560
2561     if (parm >= parmCount) {
2562         char s[100];
2563
2564         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2565                 parm, parmCount, smbp->ncb_length);
2566         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2567                  parm, parmCount, smbp->ncb_length);
2568         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2569                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2570         osi_panic(s, __FILE__, __LINE__);
2571     }
2572     parmDatap = smbp->wctp + (2*parm) + 1;
2573         
2574     return parmDatap[0];
2575 }
2576
2577 /* return the parm'th parameter in the smbp packet */
2578 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2579 {
2580     int parmCount;
2581     unsigned char *parmDatap;
2582
2583     parmCount = *smbp->wctp;
2584
2585     if (parm + 1 >= parmCount) {
2586         char s[100];
2587
2588         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2589                 parm, parmCount, smbp->ncb_length);
2590         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2591                  parm, parmCount, smbp->ncb_length);
2592         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2593                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2594         osi_panic(s, __FILE__, __LINE__);
2595     }
2596     parmDatap = smbp->wctp + (2*parm) + 1;
2597         
2598     return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2599 }
2600
2601 /* return the parm'th parameter in the smbp packet */
2602 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2603 {
2604     int parmCount;
2605     unsigned char *parmDatap;
2606
2607     parmCount = *smbp->wctp;
2608
2609     if (parm * 2 + offset >= parmCount * 2) {
2610         char s[100];
2611
2612         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2613                 parm, offset, parmCount, smbp->ncb_length);
2614         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
2615                  __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2616         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2617                 parm, offset, parmCount, smbp->ncb_length);
2618         osi_panic(s, __FILE__, __LINE__);
2619     }
2620     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2621         
2622     return parmDatap[0] + (parmDatap[1] << 8);
2623 }
2624
2625 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2626 {
2627     unsigned char *parmDatap;
2628
2629     /* make sure we have enough slots */
2630     if (*smbp->wctp <= slot) 
2631         *smbp->wctp = slot+1;
2632         
2633     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2634     *parmDatap++ = parmValue & 0xff;
2635     *parmDatap = (parmValue>>8) & 0xff;
2636 }       
2637
2638 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2639 {
2640     unsigned char *parmDatap;
2641
2642     /* make sure we have enough slots */
2643     if (*smbp->wctp <= slot) 
2644         *smbp->wctp = slot+2;
2645
2646     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2647     *parmDatap++ = parmValue & 0xff;
2648     *parmDatap++ = (parmValue>>8) & 0xff;
2649     *parmDatap++ = (parmValue>>16) & 0xff;
2650     *parmDatap   = (parmValue>>24) & 0xff;
2651 }
2652
2653 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2654 {
2655     unsigned char *parmDatap;
2656     int i;
2657
2658     /* make sure we have enough slots */
2659     if (*smbp->wctp <= slot) 
2660         *smbp->wctp = slot+4;
2661
2662     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2663     for (i=0; i<8; i++)
2664         *parmDatap++ = *parmValuep++;
2665 }       
2666
2667 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2668 {
2669     unsigned char *parmDatap;
2670
2671     /* make sure we have enough slots */
2672     if (*smbp->wctp <= slot) {
2673         if (smbp->oddByte) {
2674             smbp->oddByte = 0;
2675             *smbp->wctp = slot+1;
2676         } else
2677             smbp->oddByte = 1;
2678     }
2679
2680     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2681     *parmDatap++ = parmValue & 0xff;
2682 }
2683
2684
2685
2686 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2687                             clientchar_t *inPathp)
2688 {
2689     clientchar_t *lastSlashp;
2690         
2691     lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2692     if (lastComponentp)
2693         *lastComponentp = lastSlashp;
2694     if (lastSlashp) {
2695         while (1) {
2696             if (inPathp == lastSlashp) 
2697                 break;
2698             *outPathp++ = *inPathp++;
2699         }
2700         *outPathp++ = 0;
2701     }
2702     else {
2703         *outPathp++ = 0;
2704     }
2705 }
2706
2707 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2708                                   char **chainpp, int flags)
2709 {
2710     size_t cb;
2711     afs_uint32 type = *inp++;
2712
2713     /* 
2714      * The first byte specifies the type of the input string.
2715      * CIFS TR 1.0 3.2.10.  This function only parses null terminated
2716      * strings.
2717      */
2718     switch (type) {
2719     /* Length Counted */
2720     case 0x1: /* Data Block */
2721     case 0x5: /* Variable Block */
2722         cb = *inp++ << 16 | *inp++;
2723         break;
2724
2725     /* Null-terminated string */
2726     case 0x4: /* ASCII */
2727     case 0x3: /* Pathname */
2728     case 0x2: /* Dialect */
2729         cb = sizeof(pktp->data) - (inp - pktp->data);
2730         if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2731 #ifdef DEBUG_UNICODE
2732             DebugBreak();
2733 #endif
2734             cb = sizeof(pktp->data);
2735         }
2736         break;
2737
2738     default:
2739         return NULL;            /* invalid input */
2740     }
2741
2742 #ifdef SMB_UNICODE
2743     if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2744         flags |= SMB_STRF_FORCEASCII;
2745 #endif
2746
2747     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2748 }
2749
2750 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2751                               char ** chainpp, int flags)
2752 {
2753     size_t cb;
2754
2755 #ifdef SMB_UNICODE
2756     if (!WANTS_UNICODE(pktp))
2757         flags |= SMB_STRF_FORCEASCII;
2758 #endif
2759
2760     cb = sizeof(pktp->data) - (inp - pktp->data);
2761     if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2762 #ifdef DEBUG_UNICODE
2763         DebugBreak();
2764 #endif
2765         cb = sizeof(pktp->data);
2766     }
2767     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2768                               flags | SMB_STRF_SRCNULTERM);
2769 }
2770
2771 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2772                                 size_t cb, char ** chainpp, int flags)
2773 {
2774 #ifdef SMB_UNICODE
2775     if (!WANTS_UNICODE(pktp))
2776         flags |= SMB_STRF_FORCEASCII;
2777 #endif
2778
2779     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2780 }
2781
2782 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2783                                  size_t cch, char ** chainpp, int flags)
2784 {
2785     size_t cb = cch;
2786
2787 #ifdef SMB_UNICODE
2788     if (!WANTS_UNICODE(pktp))
2789         flags |= SMB_STRF_FORCEASCII;
2790     else
2791         cb = cch * sizeof(wchar_t);
2792 #endif
2793
2794     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2795 }
2796
2797 clientchar_t *
2798 smb_ParseStringBuf(const unsigned char * bufbase,
2799                    cm_space_t ** stringspp,
2800                    unsigned char *inp, size_t *pcb_max,
2801                    char **chainpp, int flags)
2802 {
2803 #ifdef SMB_UNICODE
2804     if (!(flags & SMB_STRF_FORCEASCII)) {
2805         size_t cch_src;
2806         cm_space_t * spacep;
2807         int    null_terms = 0;
2808
2809         if (bufbase && ((inp - bufbase) % 2) != 0) {
2810             inp++;              /* unicode strings are always word aligned */
2811         }
2812
2813         if (*pcb_max > 0) {
2814             if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2815                                         &cch_src))) {
2816                 cch_src = *pcb_max / sizeof(wchar_t);
2817                 *pcb_max = 0;
2818                 null_terms = 0;
2819             } else {
2820                 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2821                 null_terms = 1;
2822             }
2823         } else {
2824             cch_src = 0;
2825         }
2826
2827         spacep = cm_GetSpace();
2828         spacep->nextp = *stringspp;
2829         *stringspp = spacep;
2830
2831         if (cch_src == 0) {
2832             if (chainpp) {
2833                 *chainpp = inp + sizeof(wchar_t);
2834             }
2835
2836             *(spacep->wdata) = 0;
2837             return spacep->wdata;
2838         }
2839
2840         StringCchCopyNW(spacep->wdata,
2841                         lengthof(spacep->wdata),
2842                         (const clientchar_t *) inp, cch_src);
2843
2844         if (chainpp)
2845             *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2846
2847         return spacep->wdata;
2848
2849     } else {
2850 #endif
2851         cm_space_t * spacep;
2852         int cchdest;
2853
2854         /* Not using Unicode */
2855         if (chainpp) {
2856             *chainpp = inp + strlen(inp) + 1;
2857         }
2858
2859         spacep = cm_GetSpace();
2860         spacep->nextp = *stringspp;
2861         *stringspp = spacep;
2862
2863         cchdest = lengthof(spacep->wdata);
2864         cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2865                        spacep->wdata, cchdest);
2866
2867         return spacep->wdata;
2868 #ifdef SMB_UNICODE
2869     }
2870 #endif
2871 }
2872
2873 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2874                             clientchar_t * str,
2875                             size_t * plen, int flags)
2876 {
2877     size_t buffersize;
2878     int align = 0;
2879
2880     if (outp == NULL) {
2881         /* we are only calculating the required size */
2882
2883         if (plen == NULL)
2884             return NULL;
2885
2886 #ifdef SMB_UNICODE
2887
2888         if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2889
2890             StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2891             if (!(flags & SMB_STRF_IGNORENUL))
2892                 *plen += sizeof(wchar_t);
2893
2894             return (unsigned char *) 1; /* return TRUE if we are using unicode */
2895         }
2896         else
2897 #endif
2898         {
2899             /* Storing ANSI */
2900
2901             size_t cch_str;
2902             size_t cch_dest;
2903
2904             cch_str = cm_ClientStrLen(str);
2905             cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2906
2907             if (plen)
2908                 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2909
2910             return NULL;
2911         }
2912
2913         /* Not reached. */
2914     }
2915
2916     /* if outp != NULL ... */
2917
2918     /* Number of bytes left in the buffer.
2919
2920        If outp lies inside the packet data buffer, we assume that the
2921        buffer is the packet data buffer.  Otherwise we assume that the
2922        buffer is sizeof(packet->data).
2923
2924     */
2925     if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2926         align = (int)((outp - pktp->data) % 2);
2927         buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2928     } else {
2929         align = (int)(((size_t) outp) % 2);
2930         buffersize = (int)sizeof(pktp->data);
2931     }
2932
2933 #ifdef SMB_UNICODE
2934
2935     if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2936         int nchars;
2937
2938         if (align)
2939             *outp++ = '\0';
2940
2941         if (*str == _C('\0')) {
2942
2943             if (buffersize < sizeof(wchar_t))
2944                 return NULL;
2945
2946             *((wchar_t *) outp) = L'\0';
2947             if (plen && !(flags & SMB_STRF_IGNORENUL))
2948                 *plen += sizeof(wchar_t);
2949             return outp + sizeof(wchar_t);
2950         }
2951
2952         nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2953         if (nchars == 0) {
2954             osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2955                      osi_LogSaveClientString(smb_logp, str),
2956                      GetLastError());
2957             return NULL;
2958         }
2959
2960         if (plen)
2961             *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2962
2963         return outp + sizeof(wchar_t) * nchars;
2964     }
2965     else
2966 #endif
2967     {
2968         /* Storing ANSI */
2969         size_t cch_dest;
2970
2971         cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2972
2973         if (plen)
2974             *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2975
2976         return outp + cch_dest;
2977     }
2978 }
2979
2980 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2981 {
2982     int tlen;
2983
2984     if (*inp++ != 0x5) 
2985         return NULL;
2986     tlen = inp[0] + (inp[1]<<8);
2987     inp += 2;           /* skip length field */
2988
2989     if (chainpp) {
2990         *chainpp = inp + tlen;
2991     }
2992         
2993     if (lengthp) 
2994         *lengthp = tlen;
2995         
2996     return inp;
2997 }       
2998
2999 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3000 {
3001     int tlen;
3002
3003     if (*inp++ != 0x1) return NULL;
3004     tlen = inp[0] + (inp[1]<<8);
3005     inp += 2;           /* skip length field */
3006         
3007     if (chainpp) {
3008         *chainpp = inp + tlen;
3009     }   
3010
3011     if (lengthp) *lengthp = tlen;
3012         
3013     return inp;
3014 }
3015
3016 /* format a packet as a response */
3017 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
3018 {
3019     smb_t *outp;
3020     smb_t *inSmbp;
3021
3022     outp = (smb_t *) op;
3023         
3024     /* zero the basic structure through the smb_wct field, and zero the data
3025      * size field, assuming that wct stays zero; otherwise, you have to 
3026      * explicitly set the data size field, too.
3027      */
3028     inSmbp = (smb_t *) inp;
3029     memset(outp, 0, sizeof(smb_t)+2);
3030     outp->id[0] = 0xff;
3031     outp->id[1] = 'S';
3032     outp->id[2] = 'M';
3033     outp->id[3] = 'B';
3034     if (inp) {
3035         outp->com = inSmbp->com;
3036         outp->tid = inSmbp->tid;
3037         outp->pid = inSmbp->pid;
3038         outp->uid = inSmbp->uid;
3039         outp->mid = inSmbp->mid;
3040         outp->res[0] = inSmbp->res[0];
3041         outp->res[1] = inSmbp->res[1];
3042         op->inCom = inSmbp->com;
3043     }
3044     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3045 #ifdef SEND_CANONICAL_PATHNAMES
3046     outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3047 #endif
3048     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3049 #ifdef SMB_UNICODE
3050     if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3051         outp->flg2 |= SMB_FLAGS2_UNICODE;
3052 #endif
3053
3054     /* copy fields in generic packet area */
3055     op->wctp = &outp->wct;
3056 }       
3057
3058 /* send a (probably response) packet; vcp tells us to whom to send it.
3059  * we compute the length by looking at wct and bcc fields.
3060  */
3061 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3062 {
3063     NCB *ncbp;
3064     int extra;
3065     long code = 0;
3066     unsigned char *tp;
3067     int localNCB = 0;
3068         
3069     ncbp = inp->ncbp;
3070     if (ncbp == NULL) {
3071         ncbp = smb_GetNCB();
3072         localNCB = 1;
3073     }
3074  
3075     memset((char *)ncbp, 0, sizeof(NCB));
3076
3077     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
3078     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
3079     extra += tp[0] + (tp[1]<<8);
3080     extra += (unsigned int)(inp->wctp - inp->data);     /* distance to last wct field */
3081     extra += 3;                 /* wct and length fields */
3082         
3083     ncbp->ncb_length = extra;   /* bytes to send */
3084     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
3085     ncbp->ncb_lana_num = vcp->lana;
3086     ncbp->ncb_command = NCBSEND;        /* op means send data */
3087     ncbp->ncb_buffer = (char *) inp;/* packet */
3088     code = Netbios(ncbp);
3089         
3090     if (code != 0) {
3091         const char * s = ncb_error_string(code);
3092         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3093         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3094
3095         lock_ObtainMutex(&vcp->mx);
3096         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3097             osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3098                       vcp, vcp->usersp);
3099             vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3100             lock_ReleaseMutex(&vcp->mx);
3101             lock_ObtainWrite(&smb_globalLock);
3102             dead_sessions[vcp->session] = TRUE;
3103             lock_ReleaseWrite(&smb_globalLock);
3104             smb_CleanupDeadVC(vcp);
3105         } else {
3106             lock_ReleaseMutex(&vcp->mx);
3107         }
3108     }
3109
3110     if (localNCB)
3111         smb_FreeNCB(ncbp);
3112 }
3113
3114 void smb_MapNTError(long code, unsigned long *NTStatusp)
3115 {
3116     unsigned long NTStatus;
3117
3118     /* map CM_ERROR_* errors to NT 32-bit status codes */
3119     /* NT Status codes are listed in ntstatus.h not winerror.h */
3120     if (code == 0) {
3121         NTStatus = 0;
3122     } 
3123     else if (code == CM_ERROR_NOSUCHCELL) {
3124         NTStatus = 0xC000000FL; /* No such file */
3125     }
3126     else if (code == CM_ERROR_NOSUCHVOLUME) {
3127         NTStatus = 0xC000000FL; /* No such file */
3128     }
3129     else if (code == CM_ERROR_TIMEDOUT) {
3130 #ifdef COMMENT
3131         NTStatus = 0xC00000CFL; /* Sharing Paused */
3132 #else
3133         NTStatus = 0x00000102L; /* Timeout */
3134 #endif
3135     }
3136     else if (code == CM_ERROR_RETRY) {
3137         NTStatus = 0xC000022DL; /* Retry */
3138     }
3139     else if (code == CM_ERROR_NOACCESS) {
3140         NTStatus = 0xC0000022L; /* Access denied */
3141     }
3142     else if (code == CM_ERROR_READONLY) {
3143         NTStatus = 0xC00000A2L; /* Write protected */
3144     }
3145     else if (code == CM_ERROR_NOSUCHFILE ||
3146              code == CM_ERROR_BPLUS_NOMATCH) {
3147         NTStatus = 0xC000000FL; /* No such file */
3148     }
3149     else if (code == CM_ERROR_NOSUCHPATH) {
3150         NTStatus = 0xC000003AL; /* Object path not found */
3151     }           
3152     else if (code == CM_ERROR_TOOBIG) {
3153         NTStatus = 0xC000007BL; /* Invalid image format */
3154     }
3155     else if (code == CM_ERROR_INVAL) {
3156         NTStatus = 0xC000000DL; /* Invalid parameter */
3157     }
3158     else if (code == CM_ERROR_BADFD) {
3159         NTStatus = 0xC0000008L; /* Invalid handle */
3160     }
3161     else if (code == CM_ERROR_BADFDOP) {
3162         NTStatus = 0xC0000022L; /* Access denied */
3163     }
3164     else if (code == CM_ERROR_EXISTS) {
3165         NTStatus = 0xC0000035L; /* Object name collision */
3166     }
3167     else if (code == CM_ERROR_NOTEMPTY) {
3168         NTStatus = 0xC0000101L; /* Directory not empty */
3169     }   
3170     else if (code == CM_ERROR_CROSSDEVLINK) {
3171         NTStatus = 0xC00000D4L; /* Not same device */
3172     }
3173     else if (code == CM_ERROR_NOTDIR) {
3174         NTStatus = 0xC0000103L; /* Not a directory */
3175     }
3176     else if (code == CM_ERROR_ISDIR) {
3177         NTStatus = 0xC00000BAL; /* File is a directory */
3178     }
3179     else if (code == CM_ERROR_BADOP) {
3180 #ifdef COMMENT
3181         /* I have no idea where this comes from */
3182         NTStatus = 0xC09820FFL; /* SMB no support */
3183 #else
3184         NTStatus = 0xC00000BBL;     /* Not supported */
3185 #endif /* COMMENT */
3186     }
3187     else if (code == CM_ERROR_BADSHARENAME) {
3188         NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3189     }
3190     else if (code == CM_ERROR_NOIPC) {
3191 #ifdef COMMENT
3192         NTStatus = 0xC0000022L; /* Access Denied */
3193 #else   
3194         NTStatus = 0xC000013DL; /* Remote Resources */
3195 #endif
3196     }
3197     else if (code == CM_ERROR_CLOCKSKEW) {
3198         NTStatus = 0xC0000133L; /* Time difference at DC */
3199     }
3200     else if (code == CM_ERROR_BADTID) {
3201         NTStatus = 0xC0982005L; /* SMB bad TID */
3202     }
3203     else if (code == CM_ERROR_USESTD) {
3204         NTStatus = 0xC09820FBL; /* SMB use standard */
3205     }
3206     else if (code == CM_ERROR_QUOTA) {
3207         NTStatus = 0xC0000044L; /* Quota exceeded */
3208     }
3209     else if (code == CM_ERROR_SPACE) {
3210         NTStatus = 0xC000007FL; /* Disk full */
3211     }
3212     else if (code == CM_ERROR_ATSYS) {
3213         NTStatus = 0xC0000033L; /* Object name invalid */
3214     }
3215     else if (code == CM_ERROR_BADNTFILENAME) {
3216         NTStatus = 0xC0000033L; /* Object name invalid */
3217     }
3218     else if (code == CM_ERROR_WOULDBLOCK) {
3219         NTStatus = 0xC00000D8L; /* Can't wait */
3220     }
3221     else if (code == CM_ERROR_SHARING_VIOLATION) {
3222         NTStatus = 0xC0000043L; /* Sharing violation */
3223     }
3224     else if (code == CM_ERROR_LOCK_CONFLICT) {
3225         NTStatus = 0xC0000054L; /* Lock conflict */
3226     }
3227     else if (code == CM_ERROR_PARTIALWRITE) {
3228         NTStatus = 0xC000007FL; /* Disk full */
3229     }
3230     else if (code == CM_ERROR_BUFFERTOOSMALL) {
3231         NTStatus = 0xC0000023L; /* Buffer too small */
3232     }
3233     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3234         NTStatus = 0xC0000035L; /* Object name collision */
3235     }   
3236     else if (code == CM_ERROR_BADPASSWORD) {
3237         NTStatus = 0xC000006DL; /* unknown username or bad password */
3238     }
3239     else if (code == CM_ERROR_BADLOGONTYPE) {
3240         NTStatus = 0xC000015BL; /* logon type not granted */
3241     }
3242     else if (code == CM_ERROR_GSSCONTINUE) {
3243         NTStatus = 0xC0000016L; /* more processing required */
3244     }
3245     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3246 #ifdef COMMENT
3247         NTStatus = 0xC0000280L; /* reparse point not resolved */
3248 #else
3249         NTStatus = 0xC0000022L; /* Access Denied */
3250 #endif
3251     }
3252     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3253         NTStatus = 0xC0000257L; /* Path Not Covered */
3254     } 
3255     else if (code == CM_ERROR_ALLBUSY) {
3256         NTStatus = 0xC000022DL; /* Retry */
3257     } 
3258     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3259         NTStatus = 0xC000003AL; /* Path not found */
3260     } 
3261     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3262         NTStatus = 0xC0000322L; /* No Kerberos key */
3263     } 
3264     else if (code == CM_ERROR_BAD_LEVEL) {
3265         NTStatus = 0xC0000148L; /* Invalid Level */
3266     } 
3267     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3268         NTStatus = 0xC000007EL; /* Range Not Locked */
3269     } 
3270     else if (code == CM_ERROR_NOSUCHDEVICE) {
3271         NTStatus = 0xC000000EL; /* No Such Device */
3272     }
3273     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3274         NTStatus = 0xC0000055L; /* Lock Not Granted */
3275     } else if (code == ENOMEM) {
3276         NTStatus = 0xC0000017L; /* Out of Memory */
3277     } else {
3278         NTStatus = 0xC0982001L; /* SMB non-specific error */
3279     }
3280
3281     *NTStatusp = NTStatus;
3282     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3283 }       
3284
3285 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3286                       unsigned char *classp)
3287 {
3288     unsigned char class;
3289     unsigned short error;
3290
3291     /* map CM_ERROR_* errors to SMB errors */
3292     if (code == CM_ERROR_NOSUCHCELL) {
3293         class = 1;
3294         error = 3;      /* bad path */
3295     }
3296     else if (code == CM_ERROR_NOSUCHVOLUME) {
3297         class = 1;
3298         error = 3;      /* bad path */
3299     }
3300     else if (code == CM_ERROR_TIMEDOUT) {
3301         class = 2;
3302         error = 81;     /* server is paused */
3303     }
3304     else if (code == CM_ERROR_RETRY) {
3305         class = 2;      /* shouldn't happen */
3306         error = 1;
3307     }
3308     else if (code == CM_ERROR_NOACCESS) {
3309         class = 2;
3310         error = 4;      /* bad access */
3311     }
3312     else if (code == CM_ERROR_READONLY) {
3313         class = 3;
3314         error = 19;     /* read only */
3315     }
3316     else if (code == CM_ERROR_NOSUCHFILE ||
3317              code == CM_ERROR_BPLUS_NOMATCH) {
3318         class = 1;
3319         error = 2;      /* ENOENT! */
3320     }
3321     else if (code == CM_ERROR_NOSUCHPATH) {
3322         class = 1;
3323         error = 3;      /* Bad path */
3324     }
3325     else if (code == CM_ERROR_TOOBIG) {
3326         class = 1;
3327         error = 11;     /* bad format */
3328     }
3329     else if (code == CM_ERROR_INVAL) {
3330         class = 2;      /* server non-specific error code */
3331         error = 1;
3332     }
3333     else if (code == CM_ERROR_BADFD) {
3334         class = 1;
3335         error = 6;      /* invalid file handle */
3336     }
3337     else if (code == CM_ERROR_BADFDOP) {
3338         class = 1;      /* invalid op on FD */
3339         error = 5;
3340     }
3341     else if (code == CM_ERROR_EXISTS) {
3342         class = 1;
3343         error = 80;     /* file already exists */
3344     }
3345     else if (code == CM_ERROR_NOTEMPTY) {
3346         class = 1;
3347         error = 5;      /* delete directory not empty */
3348     }
3349     else if (code == CM_ERROR_CROSSDEVLINK) {
3350         class = 1;
3351         error = 17;     /* EXDEV */
3352     }
3353     else if (code == CM_ERROR_NOTDIR) {
3354         class = 1;      /* bad path */
3355         error = 3;
3356     }
3357     else if (code == CM_ERROR_ISDIR) {
3358         class = 1;      /* access denied; DOS doesn't have a good match */
3359         error = 5;
3360     }       
3361     else if (code == CM_ERROR_BADOP) {
3362         class = 2;
3363         error = 65535;
3364     }
3365     else if (code == CM_ERROR_BADSHARENAME) {
3366         class = 2;
3367         error = 6;
3368     }
3369     else if (code == CM_ERROR_NOIPC) {
3370         class = 2;
3371         error = 4; /* bad access */
3372     }
3373     else if (code == CM_ERROR_CLOCKSKEW) {
3374         class = 1;      /* invalid function */
3375         error = 1;
3376     }
3377     else if (code == CM_ERROR_BADTID) {
3378         class = 2;
3379         error = 5;
3380     }
3381     else if (code == CM_ERROR_USESTD) {
3382         class = 2;
3383         error = 251;
3384     }
3385     else if (code == CM_ERROR_REMOTECONN) {
3386         class = 2;
3387         error = 82;
3388     }
3389     else if (code == CM_ERROR_QUOTA) {
3390         if (vcp->flags & SMB_VCFLAG_USEV3) {
3391             class = 3;
3392             error = 39; /* disk full */
3393         }
3394         else {
3395             class = 1;
3396             error = 5;  /* access denied */
3397         }
3398     }
3399     else if (code == CM_ERROR_SPACE) {
3400         if (vcp->flags & SMB_VCFLAG_USEV3) {
3401             class = 3;
3402             error = 39; /* disk full */
3403         }
3404         else {
3405             class = 1;
3406             error = 5;  /* access denied */
3407         }
3408     }
3409     else if (code == CM_ERROR_PARTIALWRITE) {
3410         class = 3;
3411         error = 39;     /* disk full */
3412     }
3413     else if (code == CM_ERROR_ATSYS) {
3414         class = 1;
3415         error = 2;      /* ENOENT */
3416     }
3417     else if (code == CM_ERROR_WOULDBLOCK) {
3418         class = 1;
3419         error = 33;     /* lock conflict */
3420     }
3421     else if (code == CM_ERROR_LOCK_CONFLICT) {
3422         class = 1;
3423         error = 33;     /* lock conflict */
3424     }
3425     else if (code == CM_ERROR_SHARING_VIOLATION) {
3426         class = 1;
3427         error = 33;     /* lock conflict */
3428     }
3429     else if (code == CM_ERROR_NOFILES) {
3430         class = 1;
3431         error = 18;     /* no files in search */
3432     }
3433     else if (code == CM_ERROR_RENAME_IDENTICAL) {
3434         class = 1;
3435         error = 183;     /* Samba uses this */
3436     }
3437     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3438         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3439         class = 2;
3440         error = 2; /* bad password */
3441     }
3442     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3443         class = 2;
3444         error = 3;     /* bad path */
3445     }
3446     else {
3447         class = 2;
3448         error = 1;
3449     }
3450
3451     *scodep = error;
3452     *classp = class;
3453     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3454 }       
3455
3456 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3457 {
3458     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3459     return CM_ERROR_BADOP;
3460 }
3461
3462 /* SMB_COM_ECHO */
3463 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3464 {
3465     unsigned short EchoCount, i;
3466     char *data, *outdata;
3467     int dataSize;
3468
3469     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3470
3471     for (i=1; i<=EchoCount; i++) {
3472         data = smb_GetSMBData(inp, &dataSize);
3473         smb_SetSMBParm(outp, 0, i);
3474         smb_SetSMBDataLength(outp, dataSize);
3475         outdata = smb_GetSMBData(outp, NULL);
3476         memcpy(outdata, data, dataSize);
3477         smb_SendPacket(vcp, outp);
3478     }
3479
3480     return 0;
3481 }
3482
3483 /* SMB_COM_READ_RAW */
3484 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3485 {
3486     osi_hyper_t offset;
3487     long count, minCount, finalCount;
3488     unsigned short fd;
3489     unsigned pid;
3490     smb_fid_t *fidp;
3491     smb_t *smbp = (smb_t*) inp;
3492     long code = 0;
3493     cm_user_t *userp = NULL;
3494     NCB *ncbp;
3495     int rc;
3496     char *rawBuf = NULL;
3497
3498     rawBuf = NULL;
3499     finalCount = 0;
3500
3501     fd = smb_GetSMBParm(inp, 0);
3502     count = smb_GetSMBParm(inp, 3);
3503     minCount = smb_GetSMBParm(inp, 4);
3504     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3505
3506     if (*inp->wctp == 10) {
3507         /* we were sent a request with 64-bit file offsets */
3508 #ifdef AFS_LARGEFILES
3509         offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3510
3511         if (LargeIntegerLessThanZero(offset)) {
3512             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3513             goto send1;
3514         }
3515 #else
3516         if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3517             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset.  Dropping request.");
3518             goto send1;
3519         } else {
3520             offset.HighPart = 0;
3521         }
3522 #endif
3523     } else {
3524         /* we were sent a request with 32-bit file offsets */
3525         offset.HighPart = 0;
3526     }
3527
3528     osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3529              fd, offset.HighPart, offset.LowPart, count);
3530
3531     fidp = smb_FindFID(vcp, fd, 0);
3532     if (!fidp)
3533         goto send1;
3534
3535     lock_ObtainMutex(&fidp->mx);
3536     if (!fidp->scp) {
3537         lock_ReleaseMutex(&fidp->mx);
3538         smb_ReleaseFID(fidp);
3539         return CM_ERROR_BADFD;
3540     }
3541
3542     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3543         lock_ReleaseMutex(&fidp->mx);
3544         smb_CloseFID(vcp, fidp, NULL, 0);
3545         code = CM_ERROR_NOSUCHFILE;
3546         goto send1a;
3547     }
3548
3549     pid = smbp->pid;
3550     {
3551         LARGE_INTEGER LOffset, LLength;
3552         cm_key_t key;
3553
3554         key = cm_GenerateKey(vcp->vcID, pid, fd);
3555
3556         LOffset.HighPart = offset.HighPart;
3557         LOffset.LowPart = offset.LowPart;
3558         LLength.HighPart = 0;
3559         LLength.LowPart = count;
3560
3561         lock_ObtainWrite(&fidp->scp->rw);
3562         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3563         lock_ReleaseWrite(&fidp->scp->rw);
3564     }    
3565     if (code) {
3566         lock_ReleaseMutex(&fidp->mx);
3567         goto send1a;
3568     }
3569
3570     lock_ObtainMutex(&smb_RawBufLock);
3571     if (smb_RawBufs) {
3572         /* Get a raw buf, from head of list */
3573         rawBuf = smb_RawBufs;
3574         smb_RawBufs = *(char **)smb_RawBufs;
3575     }
3576     lock_ReleaseMutex(&smb_RawBufLock);
3577     if (!rawBuf) {
3578         lock_ReleaseMutex(&fidp->mx);
3579         goto send1a;
3580     }
3581
3582     if (fidp->flags & SMB_FID_IOCTL)
3583     {
3584         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3585         if (rawBuf) {
3586             /* Give back raw buffer */
3587             lock_ObtainMutex(&smb_RawBufLock);
3588             *((char **) rawBuf) = smb_RawBufs;
3589             
3590             smb_RawBufs = rawBuf;
3591             lock_ReleaseMutex(&smb_RawBufLock);
3592         }
3593
3594         lock_ReleaseMutex(&fidp->mx);
3595         smb_ReleaseFID(fidp);
3596         return rc;
3597     }
3598     lock_ReleaseMutex(&fidp->mx);
3599
3600     userp = smb_GetUserFromVCP(vcp, inp);
3601
3602     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3603
3604     if (code != 0)
3605         goto send;
3606
3607   send:
3608     cm_ReleaseUser(userp);
3609
3610   send1a:
3611     smb_ReleaseFID(fidp);
3612
3613   send1:
3614     ncbp = outp->ncbp;
3615     memset((char *)ncbp, 0, sizeof(NCB));
3616
3617     ncbp->ncb_length = (unsigned short) finalCount;
3618     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3619     ncbp->ncb_lana_num = vcp->lana;
3620     ncbp->ncb_command = NCBSEND;
3621     ncbp->ncb_buffer = rawBuf;
3622
3623     code = Netbios(ncbp);
3624     if (code != 0)
3625         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3626
3627     if (rawBuf) {
3628         /* Give back raw buffer */
3629         lock_ObtainMutex(&smb_RawBufLock);
3630         *((char **) rawBuf) = smb_RawBufs;
3631
3632         smb_RawBufs = rawBuf;
3633         lock_ReleaseMutex(&smb_RawBufLock);
3634     }
3635
3636     return 0;
3637 }
3638
3639 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3640 {
3641     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3642                          ongoingOps - 1);
3643     return 0;
3644 }
3645
3646 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3647 {
3648     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3649                          ongoingOps - 1);
3650     return 0;
3651 }
3652
3653 /* SMB_COM_NEGOTIATE */
3654 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3655 {
3656     char *namep;
3657     char *datap;
3658     int coreProtoIndex;
3659     int v3ProtoIndex;
3660     int NTProtoIndex;
3661     int VistaProtoIndex;
3662     int protoIndex;                             /* index we're using */
3663     int namex;
3664     int dbytes;
3665     int entryLength;
3666     int tcounter;
3667     char protocol_array[10][1024];  /* protocol signature of the client */
3668     int caps;                       /* capabilities */
3669     time_t unixTime;
3670     afs_uint32 dosTime;
3671     TIME_ZONE_INFORMATION tzi;
3672
3673     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3674                          ongoingOps - 1);
3675
3676     namep = smb_GetSMBData(inp, &dbytes);
3677     namex = 0;
3678     tcounter = 0;
3679     coreProtoIndex = -1;                /* not found */
3680     v3ProtoIndex = -1;
3681     NTProtoIndex = -1;
3682     VistaProtoIndex = -1;
3683     while(namex < dbytes) {
3684         osi_Log1(smb_logp, "Protocol %s",
3685                   osi_LogSaveString(smb_logp, namep+1));
3686         strcpy(protocol_array[tcounter], namep+1);
3687
3688         /* namep points at the first protocol, or really, a 0x02
3689          * byte preceding the null-terminated ASCII name.
3690          */
3691         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3692             coreProtoIndex = tcounter;
3693         }       
3694         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3695             v3ProtoIndex = tcounter;
3696         }
3697         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3698             NTProtoIndex = tcounter;
3699         }
3700         else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3701             VistaProtoIndex = tcounter;
3702         }
3703
3704         /* compute size of protocol entry */
3705         entryLength = (int)strlen(namep+1);
3706         entryLength += 2;       /* 0x02 bytes and null termination */
3707
3708         /* advance over this protocol entry */
3709         namex += entryLength;
3710         namep += entryLength;
3711         tcounter++;             /* which proto entry we're looking at */
3712     }
3713
3714     lock_ObtainMutex(&vcp->mx);
3715 #if 0
3716     if (VistaProtoIndex != -1) {
3717         protoIndex = VistaProtoIndex;
3718         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3719     } else 
3720 #endif  
3721         if (NTProtoIndex != -1) {
3722         protoIndex = NTProtoIndex;
3723         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3724     }
3725     else if (v3ProtoIndex != -1) {
3726         protoIndex = v3ProtoIndex;
3727         vcp->flags |= SMB_VCFLAG_USEV3;
3728     }   
3729     else if (coreProtoIndex != -1) {
3730         protoIndex = coreProtoIndex;
3731         vcp->flags |= SMB_VCFLAG_USECORE;
3732     }   
3733     else protoIndex = -1;
3734     lock_ReleaseMutex(&vcp->mx);
3735
3736     if (protoIndex == -1)
3737         return CM_ERROR_INVAL;
3738     else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3739         smb_SetSMBParm(outp, 0, protoIndex);
3740         if (smb_authType != SMB_AUTH_NONE) {
3741             smb_SetSMBParmByte(outp, 1,
3742                                NEGOTIATE_SECURITY_USER_LEVEL |
3743                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
3744         } else {
3745             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3746         }
3747         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
3748         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3749         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
3750         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
3751         /* The session key is not a well documented field however most clients
3752          * will echo back the session key to the server.  Currently we are using
3753          * the same value for all sessions.  We should generate a random value
3754          * and store it into the vcp 
3755          */
3756         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
3757         smb_SetSMBParm(outp, 8, 1);
3758         /* 
3759          * Tried changing the capabilities to support for W2K - defect 117695
3760          * Maybe something else needs to be changed here?
3761          */
3762         /*
3763         if (isWindows2000) 
3764         smb_SetSMBParmLong(outp, 9, 0x43fd);
3765         else 
3766         smb_SetSMBParmLong(outp, 9, 0x251);
3767         */
3768         /* Capabilities: *
3769          * 32-bit error codes *
3770          * and NT Find *
3771          * and NT SMB's *
3772          * and raw mode 
3773          * and DFS
3774          * and Unicode */
3775         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3776 #ifdef DFS_SUPPORT
3777                NTNEGOTIATE_CAPABILITY_DFS |
3778 #endif
3779 #ifdef AFS_LARGEFILES
3780                NTNEGOTIATE_CAPABILITY_LARGEFILES |
3781 #endif
3782                NTNEGOTIATE_CAPABILITY_NTFIND |
3783                NTNEGOTIATE_CAPABILITY_RAWMODE |
3784                NTNEGOTIATE_CAPABILITY_NTSMB;
3785
3786         if ( smb_authType == SMB_AUTH_EXTENDED )
3787             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3788
3789 #ifdef SMB_UNICODE
3790         if ( smb_UseUnicode ) {
3791             caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3792         }
3793 #endif
3794
3795         smb_SetSMBParmLong(outp, 9, caps);
3796         time(&unixTime);
3797         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3798         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3799         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3800
3801         GetTimeZoneInformation(&tzi);
3802         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
3803
3804         if (smb_authType == SMB_AUTH_NTLM) {
3805             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3806             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3807             /* paste in encryption key */
3808             datap = smb_GetSMBData(outp, NULL);
3809             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3810             /* and the faux domain name */
3811             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3812                                   datap + MSV1_0_CHALLENGE_LENGTH,
3813                                   (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3814         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3815             void * secBlob;
3816             int secBlobLength;
3817
3818             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3819
3820             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3821
3822             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3823                         
3824             datap = smb_GetSMBData(outp, NULL);
3825             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3826
3827             if (secBlob) {
3828                 datap += sizeof(smb_ServerGUID);
3829                 memcpy(datap, secBlob, secBlobLength);
3830                 free(secBlob);
3831             }
3832         } else {
3833             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3834             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
3835         }
3836     }
3837     else if (v3ProtoIndex != -1) {
3838         smb_SetSMBParm(outp, 0, protoIndex);
3839
3840         /* NOTE: Extended authentication cannot be negotiated with v3
3841          * therefore we fail over to NTLM 
3842          */
3843         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3844             smb_SetSMBParm(outp, 1,
3845                            NEGOTIATE_SECURITY_USER_LEVEL |
3846                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
3847         } else {
3848             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3849         }
3850         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3851         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
3852         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3853         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
3854         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
3855         smb_SetSMBParm(outp, 7, 1);
3856         time(&unixTime);
3857         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3858         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
3859         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
3860
3861         GetTimeZoneInformation(&tzi);
3862         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
3863
3864         /* NOTE: Extended authentication cannot be negotiated with v3
3865          * therefore we fail over to NTLM 
3866          */
3867         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3868             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
3869             smb_SetSMBParm(outp, 12, 0);        /* resvd */
3870             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
3871             datap = smb_GetSMBData(outp, NULL);
3872             /* paste in a new encryption key */
3873             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3874             /* and the faux domain name */
3875             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3876                                   datap + MSV1_0_CHALLENGE_LENGTH,
3877                                   (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3878         } else {
3879             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3880             smb_SetSMBParm(outp, 12, 0); /* resvd */
3881             smb_SetSMBDataLength(outp, 0);
3882         }
3883     }
3884     else if (coreProtoIndex != -1) {     /* not really supported anymore */
3885         smb_SetSMBParm(outp, 0, protoIndex);
3886         smb_SetSMBDataLength(outp, 0);
3887     }
3888     return 0;
3889 }
3890
3891 void smb_CheckVCs(void)
3892 {
3893     smb_vc_t * vcp, *nextp;
3894     smb_packet_t * outp = smb_GetPacket();
3895     smb_t *smbp;
3896             
3897     lock_ObtainWrite(&smb_rctLock);
3898     for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp ) 
3899     {
3900         if (vcp->magic != SMB_VC_MAGIC)
3901             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
3902                        __FILE__, __LINE__);
3903
3904         /* on the first pass hold 'vcp' which was not held as 'nextp' */
3905         if (vcp != nextp)
3906             smb_HoldVCNoLock(vcp);
3907
3908         /* 
3909          * obtain a reference to 'nextp' now because we drop the
3910          * smb_rctLock later and the list contents could change 
3911          * or 'vcp' could be destroyed when released.
3912          */
3913         nextp = vcp->nextp;
3914         if (nextp)
3915             smb_HoldVCNoLock(nextp);
3916
3917         if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3918             smb_ReleaseVCNoLock(vcp);
3919             continue;
3920         }
3921
3922         smb_FormatResponsePacket(vcp, NULL, outp);
3923         smbp = (smb_t *)outp;
3924         outp->inCom = smbp->com = 0x2b /* Echo */;
3925         smbp->tid = 0xFFFF;
3926         smbp->pid = 0;
3927         smbp->uid = 0;
3928         smbp->mid = 0;
3929         smbp->res[0] = 0;
3930         smbp->res[1] = 0;
3931
3932         smb_SetSMBParm(outp, 0, 0);
3933         smb_SetSMBDataLength(outp, 0);
3934         lock_ReleaseWrite(&smb_rctLock);
3935
3936         smb_SendPacket(vcp, outp);
3937
3938         lock_ObtainWrite(&smb_rctLock);
3939         smb_ReleaseVCNoLock(vcp);
3940     }
3941     lock_ReleaseWrite(&smb_rctLock);
3942     smb_FreePacket(outp);
3943 }
3944
3945 void smb_Daemon(void *parmp)
3946 {
3947     afs_uint32 count = 0;
3948     smb_username_t    **unpp;
3949     time_t              now;
3950
3951     while(smbShutdownFlag == 0) {
3952         count++;
3953         thrd_Sleep(10000);
3954
3955         if (smbShutdownFlag == 1)
3956             break;
3957         
3958         if ((count % 72) == 0)  {       /* every five minutes */
3959             struct tm myTime;
3960             time_t old_localZero = smb_localZero;
3961                  
3962             /* Initialize smb_localZero */
3963             myTime.tm_isdst = -1;               /* compute whether on DST or not */
3964             myTime.tm_year = 70;
3965             myTime.tm_mon = 0;
3966             myTime.tm_mday = 1;
3967             myTime.tm_hour = 0;
3968             myTime.tm_min = 0;
3969             myTime.tm_sec = 0;
3970             smb_localZero = mktime(&myTime);
3971
3972 #ifndef USE_NUMERIC_TIME_CONV
3973             smb_CalculateNowTZ();
3974 #endif /* USE_NUMERIC_TIME_CONV */
3975 #ifdef AFS_FREELANCE
3976             if ( smb_localZero != old_localZero )
3977                 cm_noteLocalMountPointChange();
3978 #endif
3979
3980             smb_CheckVCs();
3981         }
3982
3983         /* GC smb_username_t objects that will no longer be used */
3984         now = osi_Time();
3985         lock_ObtainWrite(&smb_rctLock);
3986         for ( unpp=&usernamesp; *unpp; ) {
3987             int deleteOk = 0;
3988             smb_username_t *unp;
3989
3990             lock_ObtainMutex(&(*unpp)->mx);
3991             if ( (*unpp)->refCount > 0 || 
3992                  ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) || 
3993                  !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3994                 ;
3995             else if (!smb_LogoffTokenTransfer ||
3996                      ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3997                 deleteOk = 1;
3998             lock_ReleaseMutex(&(*unpp)->mx);
3999
4000             if (deleteOk) {
4001                 cm_user_t * userp;
4002
4003                 unp = *unpp;    
4004                 *unpp = unp->nextp;
4005                 unp->nextp = NULL;
4006                 lock_FinalizeMutex(&unp->mx);
4007                 userp = unp->userp;
4008                 free(unp->name);
4009                 free(unp->machine);
4010                 free(unp);
4011                 if (userp)
4012                     cm_ReleaseUser(userp);
4013             } else {
4014                 unpp = &(*unpp)->nextp;
4015             }
4016         }
4017         lock_ReleaseWrite(&smb_rctLock);
4018
4019         /* XXX GC dir search entries */
4020     }
4021 }
4022
4023 void smb_WaitingLocksDaemon()
4024 {
4025     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4026     smb_waitingLock_t *wl, *wlNext;
4027     int first;
4028     smb_vc_t *vcp;
4029     smb_packet_t *inp, *outp;
4030     NCB *ncbp;
4031     long code = 0;
4032
4033     while (smbShutdownFlag == 0) {
4034         lock_ObtainWrite(&smb_globalLock);
4035         nwlRequest = smb_allWaitingLocks;
4036         if (nwlRequest == NULL) {
4037             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4038             thrd_Sleep(1000);
4039             continue;
4040         } else {
4041             first = 1;
4042             osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4043         }
4044
4045         do {
4046             if (first)
4047                 first = 0;
4048             else
4049                 lock_ObtainWrite(&smb_globalLock);
4050
4051             osi_Log1(smb_logp, "    Checking waiting lock request %p", nwlRequest);
4052
4053             wlRequest = nwlRequest;
4054             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4055             lock_ReleaseWrite(&smb_globalLock);
4056
4057             code = 0;
4058
4059             for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4060                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4061                     continue;
4062
4063                 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4064                     code = CM_ERROR_LOCK_NOT_GRANTED;
4065                     break;
4066                 }
4067
4068                 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4069                 
4070                 /* wl->state is either _DONE or _WAITING.  _ERROR
4071                    would no longer be on the queue. */
4072                 code = cm_RetryLock( wl->lockp,
4073                                      !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4074
4075                 if (code == 0) {
4076                     wl->state = SMB_WAITINGLOCKSTATE_DONE;
4077                 } else if (code != CM_ERROR_WOULDBLOCK) {
4078                     wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4079                     break;
4080                 }
4081             }
4082
4083             if (code == CM_ERROR_WOULDBLOCK) {
4084
4085                 /* no progress */
4086                 if (wlRequest->msTimeout != 0xffffffff
4087                      && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4088                     goto endWait;
4089
4090                 continue;
4091             }
4092
4093           endWait:
4094
4095             if (code != 0) {
4096                 cm_scache_t * scp;
4097                 cm_req_t req;
4098
4099                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4100                          wlRequest);
4101
4102                 scp = wlRequest->scp;
4103                 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4104
4105                 smb_InitReq(&req);
4106
4107                 lock_ObtainWrite(&scp->rw);
4108
4109                 for (wl = wlRequest->locks; wl; wl = wlNext) {
4110                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4111                 
4112                     if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4113                         cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
4114                                   wl->LLength, wl->key, 0, NULL, &req);
4115
4116                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4117
4118                     free(wl);
4119                 }
4120                 
4121                 lock_ReleaseWrite(&scp->rw);
4122
4123             } else {
4124
4125                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4126                          wlRequest);
4127
4128                 for (wl = wlRequest->locks; wl; wl = wlNext) {
4129                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4130                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4131                     free(wl);
4132                 }
4133             }
4134
4135             vcp = wlRequest->vcp;
4136             inp = wlRequest->inp;
4137             outp = wlRequest->outp;
4138             ncbp = smb_GetNCB();
4139             ncbp->ncb_length = inp->ncb_length;
4140             inp->spacep = cm_GetSpace();
4141
4142             /* Remove waitingLock from list */
4143             lock_ObtainWrite(&smb_globalLock);
4144             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4145                          &wlRequest->q);
4146             lock_ReleaseWrite(&smb_globalLock);
4147
4148             /* Resume packet processing */
4149             if (code == 0)
4150                 smb_SetSMBDataLength(outp, 0);
4151             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4152             outp->resumeCode = code;
4153             outp->ncbp = ncbp;
4154             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4155
4156             /* Clean up */
4157             cm_FreeSpace(inp->spacep);
4158             smb_FreePacket(inp);
4159             smb_FreePacket(outp);
4160             smb_ReleaseVC(vcp);
4161             cm_ReleaseSCache(wlRequest->scp);
4162             smb_FreeNCB(ncbp);
4163             free(wlRequest);
4164         } while (nwlRequest && smbShutdownFlag == 0);
4165         thrd_Sleep(1000);
4166     }
4167 }
4168
4169 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4170 {
4171     osi_Log0(smb_logp, "SMB receive get disk attributes");
4172
4173     smb_SetSMBParm(outp, 0, 32000);
4174     smb_SetSMBParm(outp, 1, 64);
4175     smb_SetSMBParm(outp, 2, 1024);
4176     smb_SetSMBParm(outp, 3, 30000);
4177     smb_SetSMBParm(outp, 4, 0);
4178     smb_SetSMBDataLength(outp, 0);
4179     return 0;
4180 }
4181
4182 /* SMB_COM_TREE_CONNECT */
4183 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4184 {
4185     smb_tid_t *tidp;
4186     smb_user_t *uidp;
4187     unsigned short newTid;
4188     clientchar_t shareName[AFSPATHMAX];
4189     clientchar_t *sharePath;
4190     int shareFound;
4191     clientchar_t *tp;
4192     clientchar_t *pathp;
4193     cm_user_t *userp;
4194
4195     osi_Log0(smb_logp, "SMB receive tree connect");
4196
4197     /* parse input parameters */
4198     {
4199         char *tbp;
4200         tbp = smb_GetSMBData(inp, NULL);
4201         pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4202         if (!pathp)
4203             return CM_ERROR_BADSMB;
4204     }
4205     tp = cm_ClientStrRChr(pathp, '\\');
4206     if (!tp)
4207         return CM_ERROR_BADSMB;
4208     cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4209
4210     lock_ObtainMutex(&vcp->mx);
4211     newTid = vcp->tidCounter++;
4212     lock_ReleaseMutex(&vcp->mx);
4213
4214     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4215     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4216     if (!uidp)
4217         return CM_ERROR_BADSMB;
4218     userp = smb_GetUserFromUID(uidp);
4219     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4220     smb_ReleaseUID(uidp);
4221     if (!shareFound) {
4222         smb_ReleaseTID(tidp, FALSE);
4223         return CM_ERROR_BADSHARENAME;
4224     }
4225     lock_ObtainMutex(&tidp->mx);
4226     tidp->userp = userp;
4227     tidp->pathname = sharePath;
4228     lock_ReleaseMutex(&tidp->mx);
4229     smb_ReleaseTID(tidp, FALSE);
4230
4231     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4232     smb_SetSMBParm(rsp, 1, newTid);
4233     smb_SetSMBDataLength(rsp, 0);
4234
4235     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4236     return 0;
4237 }
4238
4239 /* set maskp to the mask part of the incoming path.
4240  * Mask is 11 bytes long (8.3 with the dot elided).
4241  * Returns true if succeeds with a valid name, otherwise it does
4242  * its best, but returns false.
4243  */
4244 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4245 {
4246     clientchar_t *tp;
4247     clientchar_t *up;
4248     int i;
4249     int tc;
4250     int valid8Dot3;
4251
4252     /* starts off valid */
4253     valid8Dot3 = 1;
4254
4255     /* mask starts out all blanks */
4256     memset(maskp, ' ', 11);
4257     maskp[11] = '\0';
4258
4259     /* find last backslash, or use whole thing if there is none */
4260     tp = cm_ClientStrRChr(pathp, '\\');
4261     if (!tp) 
4262         tp = pathp;
4263     else 
4264         tp++;   /* skip slash */
4265         
4266     up = maskp;
4267
4268     /* names starting with a dot are illegal */
4269     if (*tp == '.') 
4270         valid8Dot3 = 0;
4271
4272     for(i=0;; i++) {
4273         tc = *tp++;
4274         if (tc == 0) 
4275             return valid8Dot3;
4276         if (tc == '.' || tc == '"') 
4277             break;
4278         if (i < 8) 
4279             *up++ = tc;
4280         else
4281             valid8Dot3 = 0;
4282     }
4283         
4284     /* if we get here, tp point after the dot */
4285     up = maskp+8;       /* ext goes here */
4286     for(i=0;;i++) {
4287         tc = *tp++;
4288         if (tc == 0) 
4289             return valid8Dot3;
4290
4291         /* too many dots */
4292         if (tc == '.' || tc == '"') 
4293             valid8Dot3 = 0;
4294
4295         /* copy extension if not too long */
4296         if (i < 3) 
4297             *up++ = tc;
4298         else 
4299             valid8Dot3 = 0;
4300     }   
4301
4302     /* unreachable */
4303 }
4304
4305 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4306 {
4307     clientchar_t umask[11];
4308     int valid;
4309     int i;
4310     clientchar_t tc1;
4311     clientchar_t tc2;
4312     clientchar_t *tp1;
4313     clientchar_t *tp2;
4314
4315     /* XXX redo this, calling cm_MatchMask with a converted mask */
4316
4317     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4318     if (!valid) 
4319         return 0;
4320  
4321     /* otherwise, we have a valid 8.3 name; see if we have a match,
4322      * treating '?' as a wildcard in maskp (but not in the file name).
4323      */
4324     tp1 = umask;        /* real name, in mask format */
4325     tp2 = maskp;        /* mask, in mask format */
4326     for(i=0; i<11; i++) {
4327         tc1 = *tp1++;   /* clientchar_t from real name */
4328         tc2 = *tp2++;   /* clientchar_t from mask */
4329         tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4330         tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4331         if (tc1 == tc2) 
4332             continue;
4333         if (tc2 == '?' && tc1 != ' ') 
4334             continue;
4335         if (tc2 == '>') 
4336             continue;
4337         return 0;
4338     }
4339
4340     /* we got a match */
4341     return 1;
4342 }
4343
4344 clientchar_t *smb_FindMask(clientchar_t *pathp)
4345 {
4346     clientchar_t *tp;
4347         
4348     tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4349
4350     if (tp) 
4351         return tp+1;    /* skip the slash */
4352     else 
4353         return pathp;   /* no slash, return the entire path */
4354 }       
4355
4356 /* SMB_COM_SEARCH for a volume label
4357
4358    (This is called from smb_ReceiveCoreSearchDir() and not an actual
4359    dispatch function.) */
4360 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4361 {
4362     clientchar_t *pathp;
4363     unsigned char *tp;
4364     clientchar_t mask[12];
4365     unsigned char *statBlockp;
4366     unsigned char initStatBlock[21];
4367     int statLen;
4368         
4369     osi_Log0(smb_logp, "SMB receive search volume");
4370
4371     /* pull pathname and stat block out of request */
4372     tp = smb_GetSMBData(inp, NULL);
4373     pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4374                                 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4375     if (!pathp)
4376         return CM_ERROR_BADSMB;
4377     statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4378     osi_assertx(statBlockp != NULL, "null statBlock");
4379     if (statLen == 0) {
4380         statBlockp = initStatBlock;
4381         statBlockp[0] = 8;
4382     }
4383         
4384     /* for returning to caller */
4385     smb_Get8Dot3MaskFromPath(mask, pathp);
4386
4387     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
4388     tp = smb_GetSMBData(outp, NULL);
4389     *tp++ = 5;
4390     *tp++ = 43; /* bytes in a dir entry */
4391     *tp++ = 0;  /* high byte in counter */
4392
4393     /* now marshall the dir entry, starting with the search status */
4394     *tp++ = statBlockp[0];              /* Reserved */
4395     memcpy(tp, mask, 11); tp += 11;     /* FileName */
4396
4397     /* now pass back server use info, with 1st byte non-zero */
4398     *tp++ = 1;
4399     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
4400
4401     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
4402
4403     *tp++ = 0x8;                /* attribute: volume */
4404
4405     /* copy out time */
4406     *tp++ = 0;
4407     *tp++ = 0;
4408
4409     /* copy out date */