62640793526324c2a20f4ceb6e0fcb634e816e57
[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 (!locked)
1339         lock_ReleaseWrite(&smb_rctLock);
1340     if (userp)
1341         cm_ReleaseUser(userp);
1342     if (vcp)
1343         smb_ReleaseVCNoLock(vcp);
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_SearchCellFile(cellname, ftemp, 0, 0);
2099 #ifdef AFS_AFSDB_ENV
2100         if (code && cm_dnsEnabled) {
2101             int ttl;
2102             code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2103         }
2104 #endif
2105         if (cellname)
2106             free(cellname);
2107
2108         /* construct the path */
2109         if (code == 0) {
2110             clientchar_t temp[1024];
2111
2112             if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2113             cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2114                                 rw ? _C("/.%S/") : _C("/%S/"), temp);
2115             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2116             return 1;
2117         }
2118     }
2119     }
2120     /* failure */
2121     *pathNamep = NULL;
2122     return 0;
2123 }
2124
2125 /* Client-side offline caching policy types */
2126 #define CSC_POLICY_MANUAL 0
2127 #define CSC_POLICY_DOCUMENTS 1
2128 #define CSC_POLICY_PROGRAMS 2
2129 #define CSC_POLICY_DISABLE 3
2130
2131 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2132 {
2133     DWORD len;
2134     clientchar_t policy[1024];
2135     DWORD dwType;
2136     HKEY hkCSCPolicy;
2137     int  retval = CSC_POLICY_MANUAL;
2138
2139     RegCreateKeyEx( HKEY_LOCAL_MACHINE, 
2140                     AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2141                     0, 
2142                     "AFS", 
2143                     REG_OPTION_NON_VOLATILE,
2144                     KEY_READ,
2145                     NULL, 
2146                     &hkCSCPolicy,
2147                     NULL );
2148
2149     len = sizeof(policy);
2150     if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2151          len == 0) {
2152         retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2153     }
2154     else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2155     {
2156         retval = CSC_POLICY_DOCUMENTS;
2157     }
2158     else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2159     {
2160         retval = CSC_POLICY_PROGRAMS;
2161     }
2162     else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2163     {
2164         retval = CSC_POLICY_DISABLE;
2165     }
2166         
2167     RegCloseKey(hkCSCPolicy);
2168     return retval;
2169 }
2170
2171 /* find a dir search structure by cookie value, and return it held.
2172  * Must be called with smb_globalLock held.
2173  */
2174 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2175 {
2176     smb_dirSearch_t *dsp;
2177         
2178     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2179         if (dsp->cookie == cookie) {
2180             if (dsp != smb_firstDirSearchp) {
2181                 /* move to head of LRU queue, too, if we're not already there */
2182                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2183                     smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2184                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2185                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2186                 if (!smb_lastDirSearchp)
2187                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2188             }
2189             dsp->refCount++;
2190             break;
2191         }
2192     }
2193
2194     if (dsp == NULL) {
2195         osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2196         for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2197             osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2198         }
2199     }
2200     return dsp;
2201 }       
2202
2203 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2204 {
2205     lock_ObtainMutex(&dsp->mx);
2206     osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p", 
2207               dsp->cookie, dsp, dsp->scp);
2208     dsp->flags |= SMB_DIRSEARCH_DELETE;
2209     if (dsp->scp != NULL) {
2210         lock_ObtainWrite(&dsp->scp->rw);
2211         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2212             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2213             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2214             dsp->scp->bulkStatProgress = hzero;
2215         }       
2216         lock_ReleaseWrite(&dsp->scp->rw);
2217     }   
2218     lock_ReleaseMutex(&dsp->mx);
2219 }               
2220
2221 /* Must be called with the smb_globalLock held */
2222 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2223 {
2224     cm_scache_t *scp = NULL;
2225
2226     osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2227     if (dsp->refCount == 0) {
2228         lock_ObtainMutex(&dsp->mx);
2229         if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2230             if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2231                 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2232             osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2233             lock_ReleaseMutex(&dsp->mx);
2234             lock_FinalizeMutex(&dsp->mx);
2235             scp = dsp->scp;
2236             osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
2237                      dsp->cookie, dsp, scp);
2238             free(dsp);
2239         } else {
2240             lock_ReleaseMutex(&dsp->mx);
2241         }
2242     }
2243     /* do this now to avoid spurious locking hierarchy creation */
2244     if (scp) 
2245         cm_ReleaseSCache(scp);
2246 }       
2247
2248 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2249 {
2250     lock_ObtainWrite(&smb_globalLock);
2251     smb_ReleaseDirSearchNoLock(dsp);
2252     lock_ReleaseWrite(&smb_globalLock);
2253 }       
2254
2255 /* find a dir search structure by cookie value, and return it held */
2256 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2257 {
2258     smb_dirSearch_t *dsp;
2259
2260     lock_ObtainWrite(&smb_globalLock);
2261     dsp = smb_FindDirSearchNoLock(cookie);
2262     lock_ReleaseWrite(&smb_globalLock);
2263     return dsp;
2264 }
2265
2266 /* GC some dir search entries, in the address space expected by the specific protocol.
2267  * Must be called with smb_globalLock held; release the lock temporarily.
2268  */
2269 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
2270 void smb_GCDirSearches(int isV3)
2271 {
2272     smb_dirSearch_t *prevp;
2273     smb_dirSearch_t *dsp;
2274     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2275     int victimCount;
2276     int i;
2277         
2278     victimCount = 0;    /* how many have we got so far */
2279     for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2280         /* we'll move tp from queue, so
2281          * do this early.
2282          */
2283         prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q); 
2284         /* if no one is using this guy, and we're either in the new protocol,
2285          * or we're in the old one and this is a small enough ID to be useful
2286          * to the old protocol, GC this guy.
2287          */
2288         if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2289             /* hold and delete */
2290             lock_ObtainMutex(&dsp->mx);
2291             dsp->flags |= SMB_DIRSEARCH_DELETE;
2292             lock_ReleaseMutex(&dsp->mx);
2293             victimsp[victimCount++] = dsp;
2294             dsp->refCount++;
2295         }
2296
2297         /* don't do more than this */
2298         if (victimCount >= SMB_DIRSEARCH_GCMAX) 
2299             break;
2300     }
2301         
2302     /* now release them */
2303     for (i = 0; i < victimCount; i++) {
2304         smb_ReleaseDirSearchNoLock(victimsp[i]);
2305     }
2306 }
2307
2308 /* function for allocating a dir search entry.  We need these to remember enough context
2309  * since we don't get passed the path from call to call during a directory search.
2310  *
2311  * Returns a held dir search structure, and bumps the reference count on the vnode,
2312  * since it saves a pointer to the vnode.
2313  */
2314 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2315 {
2316     smb_dirSearch_t *dsp;
2317     int counter;
2318     int maxAllowed;
2319     int start;
2320     int wrapped = 0;
2321
2322     lock_ObtainWrite(&smb_globalLock);
2323     counter = 0;
2324
2325     /* what's the biggest ID allowed in this version of the protocol */
2326     /* TODO: do we really want a non v3 dir search request to wrap
2327        smb_dirSearchCounter? */
2328     maxAllowed = isV3 ? 65535 : 255;
2329     if (smb_dirSearchCounter > maxAllowed)
2330         smb_dirSearchCounter = 1;
2331
2332     start = smb_dirSearchCounter;
2333
2334     while (1) {
2335         /* twice so we have enough tries to find guys we GC after one pass;
2336          * 10 extra is just in case I mis-counted.
2337          */
2338         if (++counter > 2*maxAllowed+10) 
2339             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2340
2341         if (smb_dirSearchCounter > maxAllowed) {        
2342             smb_dirSearchCounter = 1;
2343         }
2344         if (smb_dirSearchCounter == start) {
2345             if (wrapped)
2346                 smb_GCDirSearches(isV3);
2347             wrapped++;
2348         }
2349         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2350         if (dsp) {
2351             /* don't need to watch for refcount zero and deleted, since
2352             * we haven't dropped the global lock.
2353             */
2354             dsp->refCount--;
2355             ++smb_dirSearchCounter;
2356             continue;
2357         }       
2358
2359         dsp = malloc(sizeof(*dsp));
2360         memset(dsp, 0, sizeof(*dsp));
2361         dsp->cookie = smb_dirSearchCounter;
2362         ++smb_dirSearchCounter;
2363         dsp->refCount = 1;
2364         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2365         dsp->lastTime = osi_Time();
2366         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2367         if (!smb_lastDirSearchp) 
2368             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2369     
2370         osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p", 
2371                  dsp->cookie, dsp);
2372         break;
2373     }   
2374     lock_ReleaseWrite(&smb_globalLock);
2375     return dsp;
2376 }
2377
2378 static smb_packet_t *smb_GetPacket(void)
2379 {
2380     smb_packet_t *tbp;
2381
2382     lock_ObtainWrite(&smb_globalLock);
2383     tbp = smb_packetFreeListp;
2384     if (tbp) 
2385         smb_packetFreeListp = tbp->nextp;
2386     lock_ReleaseWrite(&smb_globalLock);
2387     if (!tbp) {
2388         tbp = calloc(sizeof(*tbp),1);
2389         tbp->magic = SMB_PACKETMAGIC;
2390         tbp->ncbp = NULL;
2391         tbp->vcp = NULL;
2392         tbp->resumeCode = 0;
2393         tbp->inCount = 0;
2394         tbp->fid = 0;
2395         tbp->wctp = NULL;
2396         tbp->inCom = 0;
2397         tbp->oddByte = 0;
2398         tbp->ncb_length = 0;
2399         tbp->flags = 0;
2400         tbp->spacep = NULL;
2401         tbp->stringsp = NULL;
2402     }
2403     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2404
2405     return tbp;
2406 }
2407
2408 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2409 {
2410     smb_packet_t *tbp;
2411     tbp = smb_GetPacket();
2412     memcpy(tbp, pkt, sizeof(smb_packet_t));
2413     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2414     tbp->stringsp = NULL;
2415     if (tbp->vcp)
2416         smb_HoldVC(tbp->vcp);
2417     return tbp;
2418 }
2419
2420 static NCB *smb_GetNCB(void)
2421 {
2422     smb_ncb_t *tbp;
2423     NCB *ncbp;
2424
2425     lock_ObtainWrite(&smb_globalLock);
2426     tbp = smb_ncbFreeListp;
2427     if (tbp) 
2428         smb_ncbFreeListp = tbp->nextp;
2429     lock_ReleaseWrite(&smb_globalLock);
2430     if (!tbp) {
2431         tbp = calloc(sizeof(*tbp),1);
2432         tbp->magic = SMB_NCBMAGIC;
2433     }
2434         
2435     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2436
2437     memset(&tbp->ncb, 0, sizeof(NCB));
2438     ncbp = &tbp->ncb;
2439     return ncbp;
2440 }
2441
2442 static void FreeSMBStrings(smb_packet_t * pkt)
2443 {
2444     cm_space_t * s;
2445     cm_space_t * ns;
2446
2447     for (s = pkt->stringsp; s; s = ns) {
2448         ns = s->nextp;
2449         cm_FreeSpace(s);
2450     }
2451     pkt->stringsp = NULL;
2452 }
2453
2454 void smb_FreePacket(smb_packet_t *tbp)
2455 {
2456     smb_vc_t * vcp = NULL;
2457     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2458         
2459     lock_ObtainWrite(&smb_globalLock);
2460     tbp->nextp = smb_packetFreeListp;
2461     smb_packetFreeListp = tbp;
2462     tbp->magic = SMB_PACKETMAGIC;
2463     tbp->ncbp = NULL;
2464     vcp = tbp->vcp;
2465     tbp->vcp = NULL;
2466     tbp->resumeCode = 0;
2467     tbp->inCount = 0;
2468     tbp->fid = 0;
2469     tbp->wctp = NULL;
2470     tbp->inCom = 0;
2471     tbp->oddByte = 0;
2472     tbp->ncb_length = 0;
2473     tbp->flags = 0;
2474     FreeSMBStrings(tbp);
2475     lock_ReleaseWrite(&smb_globalLock);
2476
2477     if (vcp)
2478         smb_ReleaseVC(vcp);
2479 }
2480
2481 static void smb_FreeNCB(NCB *bufferp)
2482 {
2483     smb_ncb_t *tbp;
2484         
2485     tbp = (smb_ncb_t *) bufferp;
2486     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2487         
2488     lock_ObtainWrite(&smb_globalLock);
2489     tbp->nextp = smb_ncbFreeListp;
2490     smb_ncbFreeListp = tbp;
2491     lock_ReleaseWrite(&smb_globalLock);
2492 }
2493
2494 /* get a ptr to the data part of a packet, and its count */
2495 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2496 {
2497     int parmBytes;
2498     int dataBytes;
2499     unsigned char *afterParmsp;
2500
2501     parmBytes = *smbp->wctp << 1;
2502     afterParmsp = smbp->wctp + parmBytes + 1;
2503         
2504     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2505     if (nbytesp) *nbytesp = dataBytes;
2506         
2507     /* don't forget to skip the data byte count, since it follows
2508      * the parameters; that's where the "2" comes from below.
2509      */
2510     return (unsigned char *) (afterParmsp + 2);
2511 }
2512
2513 /* must set all the returned parameters before playing around with the
2514  * data region, since the data region is located past the end of the
2515  * variable number of parameters.
2516  */
2517 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2518 {
2519     unsigned char *afterParmsp;
2520
2521     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2522         
2523     *afterParmsp++ = dsize & 0xff;
2524     *afterParmsp = (dsize>>8) & 0xff;
2525 }       
2526
2527 /* return the parm'th parameter in the smbp packet */
2528 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2529 {
2530     int parmCount;
2531     unsigned char *parmDatap;
2532
2533     parmCount = *smbp->wctp;
2534
2535     if (parm >= parmCount) {
2536         char s[100];
2537
2538         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2539                 parm, parmCount, smbp->ncb_length);
2540         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2541                  parm, parmCount, smbp->ncb_length);
2542         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2543                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2544         osi_panic(s, __FILE__, __LINE__);
2545     }
2546     parmDatap = smbp->wctp + (2*parm) + 1;
2547         
2548     return parmDatap[0] + (parmDatap[1] << 8);
2549 }
2550
2551 /* return the parm'th parameter in the smbp packet */
2552 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2553 {
2554     int parmCount;
2555     unsigned char *parmDatap;
2556
2557     parmCount = *smbp->wctp;
2558
2559     if (parm >= parmCount) {
2560         char s[100];
2561
2562         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2563                 parm, parmCount, smbp->ncb_length);
2564         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2565                  parm, parmCount, smbp->ncb_length);
2566         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2567                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2568         osi_panic(s, __FILE__, __LINE__);
2569     }
2570     parmDatap = smbp->wctp + (2*parm) + 1;
2571         
2572     return parmDatap[0];
2573 }
2574
2575 /* return the parm'th parameter in the smbp packet */
2576 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2577 {
2578     int parmCount;
2579     unsigned char *parmDatap;
2580
2581     parmCount = *smbp->wctp;
2582
2583     if (parm + 1 >= parmCount) {
2584         char s[100];
2585
2586         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2587                 parm, parmCount, smbp->ncb_length);
2588         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2589                  parm, parmCount, smbp->ncb_length);
2590         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2591                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2592         osi_panic(s, __FILE__, __LINE__);
2593     }
2594     parmDatap = smbp->wctp + (2*parm) + 1;
2595         
2596     return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2597 }
2598
2599 /* return the parm'th parameter in the smbp packet */
2600 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2601 {
2602     int parmCount;
2603     unsigned char *parmDatap;
2604
2605     parmCount = *smbp->wctp;
2606
2607     if (parm * 2 + offset >= parmCount * 2) {
2608         char s[100];
2609
2610         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2611                 parm, offset, parmCount, smbp->ncb_length);
2612         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
2613                  __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2614         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2615                 parm, offset, parmCount, smbp->ncb_length);
2616         osi_panic(s, __FILE__, __LINE__);
2617     }
2618     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2619         
2620     return parmDatap[0] + (parmDatap[1] << 8);
2621 }
2622
2623 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2624 {
2625     unsigned char *parmDatap;
2626
2627     /* make sure we have enough slots */
2628     if (*smbp->wctp <= slot) 
2629         *smbp->wctp = slot+1;
2630         
2631     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2632     *parmDatap++ = parmValue & 0xff;
2633     *parmDatap = (parmValue>>8) & 0xff;
2634 }       
2635
2636 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2637 {
2638     unsigned char *parmDatap;
2639
2640     /* make sure we have enough slots */
2641     if (*smbp->wctp <= slot) 
2642         *smbp->wctp = slot+2;
2643
2644     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2645     *parmDatap++ = parmValue & 0xff;
2646     *parmDatap++ = (parmValue>>8) & 0xff;
2647     *parmDatap++ = (parmValue>>16) & 0xff;
2648     *parmDatap   = (parmValue>>24) & 0xff;
2649 }
2650
2651 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2652 {
2653     unsigned char *parmDatap;
2654     int i;
2655
2656     /* make sure we have enough slots */
2657     if (*smbp->wctp <= slot) 
2658         *smbp->wctp = slot+4;
2659
2660     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2661     for (i=0; i<8; i++)
2662         *parmDatap++ = *parmValuep++;
2663 }       
2664
2665 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2666 {
2667     unsigned char *parmDatap;
2668
2669     /* make sure we have enough slots */
2670     if (*smbp->wctp <= slot) {
2671         if (smbp->oddByte) {
2672             smbp->oddByte = 0;
2673             *smbp->wctp = slot+1;
2674         } else
2675             smbp->oddByte = 1;
2676     }
2677
2678     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2679     *parmDatap++ = parmValue & 0xff;
2680 }
2681
2682
2683
2684 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2685                             clientchar_t *inPathp)
2686 {
2687     clientchar_t *lastSlashp;
2688         
2689     lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2690     if (lastComponentp)
2691         *lastComponentp = lastSlashp;
2692     if (lastSlashp) {
2693         while (1) {
2694             if (inPathp == lastSlashp) 
2695                 break;
2696             *outPathp++ = *inPathp++;
2697         }
2698         *outPathp++ = 0;
2699     }
2700     else {
2701         *outPathp++ = 0;
2702     }
2703 }
2704
2705 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2706                                   char **chainpp, int flags)
2707 {
2708     size_t cb;
2709     afs_uint32 type = *inp++;
2710
2711     /* 
2712      * The first byte specifies the type of the input string.
2713      * CIFS TR 1.0 3.2.10.  This function only parses null terminated
2714      * strings.
2715      */
2716     switch (type) {
2717     /* Length Counted */
2718     case 0x1: /* Data Block */
2719     case 0x5: /* Variable Block */
2720         cb = *inp++ << 16 | *inp++;
2721         break;
2722
2723     /* Null-terminated string */
2724     case 0x4: /* ASCII */
2725     case 0x3: /* Pathname */
2726     case 0x2: /* Dialect */
2727         cb = sizeof(pktp->data) - (inp - pktp->data);
2728         if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2729 #ifdef DEBUG_UNICODE
2730             DebugBreak();
2731 #endif
2732             cb = sizeof(pktp->data);
2733         }
2734         break;
2735
2736     default:
2737         return NULL;            /* invalid input */
2738     }
2739
2740 #ifdef SMB_UNICODE
2741     if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2742         flags |= SMB_STRF_FORCEASCII;
2743 #endif
2744
2745     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2746 }
2747
2748 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2749                               char ** chainpp, int flags)
2750 {
2751     size_t cb;
2752
2753 #ifdef SMB_UNICODE
2754     if (!WANTS_UNICODE(pktp))
2755         flags |= SMB_STRF_FORCEASCII;
2756 #endif
2757
2758     cb = sizeof(pktp->data) - (inp - pktp->data);
2759     if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2760 #ifdef DEBUG_UNICODE
2761         DebugBreak();
2762 #endif
2763         cb = sizeof(pktp->data);
2764     }
2765     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2766                               flags | SMB_STRF_SRCNULTERM);
2767 }
2768
2769 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2770                                 size_t cb, char ** chainpp, int flags)
2771 {
2772 #ifdef SMB_UNICODE
2773     if (!WANTS_UNICODE(pktp))
2774         flags |= SMB_STRF_FORCEASCII;
2775 #endif
2776
2777     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2778 }
2779
2780 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2781                                  size_t cch, char ** chainpp, int flags)
2782 {
2783     size_t cb = cch;
2784
2785 #ifdef SMB_UNICODE
2786     if (!WANTS_UNICODE(pktp))
2787         flags |= SMB_STRF_FORCEASCII;
2788     else
2789         cb = cch * sizeof(wchar_t);
2790 #endif
2791
2792     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2793 }
2794
2795 clientchar_t *
2796 smb_ParseStringBuf(const unsigned char * bufbase,
2797                    cm_space_t ** stringspp,
2798                    unsigned char *inp, size_t *pcb_max,
2799                    char **chainpp, int flags)
2800 {
2801 #ifdef SMB_UNICODE
2802     if (!(flags & SMB_STRF_FORCEASCII)) {
2803         size_t cch_src;
2804         cm_space_t * spacep;
2805         int    null_terms = 0;
2806
2807         if (bufbase && ((inp - bufbase) % 2) != 0) {
2808             inp++;              /* unicode strings are always word aligned */
2809         }
2810
2811         if (*pcb_max > 0) {
2812             if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2813                                         &cch_src))) {
2814                 cch_src = *pcb_max / sizeof(wchar_t);
2815                 *pcb_max = 0;
2816                 null_terms = 0;
2817             } else {
2818                 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2819                 null_terms = 1;
2820             }
2821         } else {
2822             cch_src = 0;
2823         }
2824
2825         spacep = cm_GetSpace();
2826         spacep->nextp = *stringspp;
2827         *stringspp = spacep;
2828
2829         if (cch_src == 0) {
2830             if (chainpp) {
2831                 *chainpp = inp + sizeof(wchar_t);
2832             }
2833
2834             *(spacep->wdata) = 0;
2835             return spacep->wdata;
2836         }
2837
2838         StringCchCopyNW(spacep->wdata,
2839                         lengthof(spacep->wdata),
2840                         (const clientchar_t *) inp, cch_src);
2841
2842         if (chainpp)
2843             *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2844
2845         return spacep->wdata;
2846
2847     } else {
2848 #endif
2849         cm_space_t * spacep;
2850         int cchdest;
2851
2852         /* Not using Unicode */
2853         if (chainpp) {
2854             *chainpp = inp + strlen(inp) + 1;
2855         }
2856
2857         spacep = cm_GetSpace();
2858         spacep->nextp = *stringspp;
2859         *stringspp = spacep;
2860
2861         cchdest = lengthof(spacep->wdata);
2862         cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2863                        spacep->wdata, cchdest);
2864
2865         return spacep->wdata;
2866 #ifdef SMB_UNICODE
2867     }
2868 #endif
2869 }
2870
2871 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2872                             clientchar_t * str,
2873                             size_t * plen, int flags)
2874 {
2875     size_t buffersize;
2876     int align = 0;
2877
2878     if (outp == NULL) {
2879         /* we are only calculating the required size */
2880
2881         if (plen == NULL)
2882             return NULL;
2883
2884 #ifdef SMB_UNICODE
2885
2886         if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2887
2888             StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2889             if (!(flags & SMB_STRF_IGNORENUL))
2890                 *plen += sizeof(wchar_t);
2891
2892             return (unsigned char *) 1; /* return TRUE if we are using unicode */
2893         }
2894         else
2895 #endif
2896         {
2897             /* Storing ANSI */
2898
2899             size_t cch_str;
2900             size_t cch_dest;
2901
2902             cch_str = cm_ClientStrLen(str);
2903             cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2904
2905             if (plen)
2906                 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2907
2908             return NULL;
2909         }
2910
2911         /* Not reached. */
2912     }
2913
2914     /* if outp != NULL ... */
2915
2916     /* Number of bytes left in the buffer.
2917
2918        If outp lies inside the packet data buffer, we assume that the
2919        buffer is the packet data buffer.  Otherwise we assume that the
2920        buffer is sizeof(packet->data).
2921
2922     */
2923     if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2924         align = (int)((outp - pktp->data) % 2);
2925         buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2926     } else {
2927         align = (int)(((size_t) outp) % 2);
2928         buffersize = (int)sizeof(pktp->data);
2929     }
2930
2931 #ifdef SMB_UNICODE
2932
2933     if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2934         int nchars;
2935
2936         if (align)
2937             *outp++ = '\0';
2938
2939         if (*str == _C('\0')) {
2940
2941             if (buffersize < sizeof(wchar_t))
2942                 return NULL;
2943
2944             *((wchar_t *) outp) = L'\0';
2945             if (plen && !(flags & SMB_STRF_IGNORENUL))
2946                 *plen += sizeof(wchar_t);
2947             return outp + sizeof(wchar_t);
2948         }
2949
2950         nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2951         if (nchars == 0) {
2952             osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2953                      osi_LogSaveClientString(smb_logp, str),
2954                      GetLastError());
2955             return NULL;
2956         }
2957
2958         if (plen)
2959             *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2960
2961         return outp + sizeof(wchar_t) * nchars;
2962     }
2963     else
2964 #endif
2965     {
2966         /* Storing ANSI */
2967         size_t cch_dest;
2968
2969         cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2970
2971         if (plen)
2972             *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2973
2974         return outp + cch_dest;
2975     }
2976 }
2977
2978 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2979 {
2980     int tlen;
2981
2982     if (*inp++ != 0x5) 
2983         return NULL;
2984     tlen = inp[0] + (inp[1]<<8);
2985     inp += 2;           /* skip length field */
2986
2987     if (chainpp) {
2988         *chainpp = inp + tlen;
2989     }
2990         
2991     if (lengthp) 
2992         *lengthp = tlen;
2993         
2994     return inp;
2995 }       
2996
2997 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2998 {
2999     int tlen;
3000
3001     if (*inp++ != 0x1) return NULL;
3002     tlen = inp[0] + (inp[1]<<8);
3003     inp += 2;           /* skip length field */
3004         
3005     if (chainpp) {
3006         *chainpp = inp + tlen;
3007     }   
3008
3009     if (lengthp) *lengthp = tlen;
3010         
3011     return inp;
3012 }
3013
3014 /* format a packet as a response */
3015 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
3016 {
3017     smb_t *outp;
3018     smb_t *inSmbp;
3019
3020     outp = (smb_t *) op;
3021         
3022     /* zero the basic structure through the smb_wct field, and zero the data
3023      * size field, assuming that wct stays zero; otherwise, you have to 
3024      * explicitly set the data size field, too.
3025      */
3026     inSmbp = (smb_t *) inp;
3027     memset(outp, 0, sizeof(smb_t)+2);
3028     outp->id[0] = 0xff;
3029     outp->id[1] = 'S';
3030     outp->id[2] = 'M';
3031     outp->id[3] = 'B';
3032     if (inp) {
3033         outp->com = inSmbp->com;
3034         outp->tid = inSmbp->tid;
3035         outp->pid = inSmbp->pid;
3036         outp->uid = inSmbp->uid;
3037         outp->mid = inSmbp->mid;
3038         outp->res[0] = inSmbp->res[0];
3039         outp->res[1] = inSmbp->res[1];
3040         op->inCom = inSmbp->com;
3041     }
3042     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3043 #ifdef SEND_CANONICAL_PATHNAMES
3044     outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3045 #endif
3046     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3047 #ifdef SMB_UNICODE
3048     if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3049         outp->flg2 |= SMB_FLAGS2_UNICODE;
3050 #endif
3051
3052     /* copy fields in generic packet area */
3053     op->wctp = &outp->wct;
3054 }       
3055
3056 /* send a (probably response) packet; vcp tells us to whom to send it.
3057  * we compute the length by looking at wct and bcc fields.
3058  */
3059 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3060 {
3061     NCB *ncbp;
3062     int extra;
3063     long code = 0;
3064     unsigned char *tp;
3065     int localNCB = 0;
3066         
3067     ncbp = inp->ncbp;
3068     if (ncbp == NULL) {
3069         ncbp = smb_GetNCB();
3070         localNCB = 1;
3071     }
3072  
3073     memset((char *)ncbp, 0, sizeof(NCB));
3074
3075     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
3076     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
3077     extra += tp[0] + (tp[1]<<8);
3078     extra += (unsigned int)(inp->wctp - inp->data);     /* distance to last wct field */
3079     extra += 3;                 /* wct and length fields */
3080         
3081     ncbp->ncb_length = extra;   /* bytes to send */
3082     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
3083     ncbp->ncb_lana_num = vcp->lana;
3084     ncbp->ncb_command = NCBSEND;        /* op means send data */
3085     ncbp->ncb_buffer = (char *) inp;/* packet */
3086     code = Netbios(ncbp);
3087         
3088     if (code != 0) {
3089         const char * s = ncb_error_string(code);
3090         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3091         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3092
3093         lock_ObtainMutex(&vcp->mx);
3094         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3095             osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3096                       vcp, vcp->usersp);
3097             vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3098             lock_ReleaseMutex(&vcp->mx);
3099             lock_ObtainWrite(&smb_globalLock);
3100             dead_sessions[vcp->session] = TRUE;
3101             lock_ReleaseWrite(&smb_globalLock);
3102             smb_CleanupDeadVC(vcp);
3103         } else {
3104             lock_ReleaseMutex(&vcp->mx);
3105         }
3106     }
3107
3108     if (localNCB)
3109         smb_FreeNCB(ncbp);
3110 }
3111
3112 void smb_MapNTError(long code, unsigned long *NTStatusp)
3113 {
3114     unsigned long NTStatus;
3115
3116     /* map CM_ERROR_* errors to NT 32-bit status codes */
3117     /* NT Status codes are listed in ntstatus.h not winerror.h */
3118     if (code == 0) {
3119         NTStatus = 0;
3120     } 
3121     else if (code == CM_ERROR_NOSUCHCELL) {
3122         NTStatus = 0xC000000FL; /* No such file */
3123     }
3124     else if (code == CM_ERROR_NOSUCHVOLUME) {
3125         NTStatus = 0xC000000FL; /* No such file */
3126     }
3127     else if (code == CM_ERROR_TIMEDOUT) {
3128 #ifdef COMMENT
3129         NTStatus = 0xC00000CFL; /* Sharing Paused */
3130 #else
3131         NTStatus = 0x00000102L; /* Timeout */
3132 #endif
3133     }
3134     else if (code == CM_ERROR_RETRY) {
3135         NTStatus = 0xC000022DL; /* Retry */
3136     }
3137     else if (code == CM_ERROR_NOACCESS) {
3138         NTStatus = 0xC0000022L; /* Access denied */
3139     }
3140     else if (code == CM_ERROR_READONLY) {
3141         NTStatus = 0xC00000A2L; /* Write protected */
3142     }
3143     else if (code == CM_ERROR_NOSUCHFILE ||
3144              code == CM_ERROR_BPLUS_NOMATCH) {
3145         NTStatus = 0xC000000FL; /* No such file */
3146     }
3147     else if (code == CM_ERROR_NOSUCHPATH) {
3148         NTStatus = 0xC000003AL; /* Object path not found */
3149     }           
3150     else if (code == CM_ERROR_TOOBIG) {
3151         NTStatus = 0xC000007BL; /* Invalid image format */
3152     }
3153     else if (code == CM_ERROR_INVAL) {
3154         NTStatus = 0xC000000DL; /* Invalid parameter */
3155     }
3156     else if (code == CM_ERROR_BADFD) {
3157         NTStatus = 0xC0000008L; /* Invalid handle */
3158     }
3159     else if (code == CM_ERROR_BADFDOP) {
3160         NTStatus = 0xC0000022L; /* Access denied */
3161     }
3162     else if (code == CM_ERROR_EXISTS) {
3163         NTStatus = 0xC0000035L; /* Object name collision */
3164     }
3165     else if (code == CM_ERROR_NOTEMPTY) {
3166         NTStatus = 0xC0000101L; /* Directory not empty */
3167     }   
3168     else if (code == CM_ERROR_CROSSDEVLINK) {
3169         NTStatus = 0xC00000D4L; /* Not same device */
3170     }
3171     else if (code == CM_ERROR_NOTDIR) {
3172         NTStatus = 0xC0000103L; /* Not a directory */
3173     }
3174     else if (code == CM_ERROR_ISDIR) {
3175         NTStatus = 0xC00000BAL; /* File is a directory */
3176     }
3177     else if (code == CM_ERROR_BADOP) {
3178 #ifdef COMMENT
3179         /* I have no idea where this comes from */
3180         NTStatus = 0xC09820FFL; /* SMB no support */
3181 #else
3182         NTStatus = 0xC00000BBL;     /* Not supported */
3183 #endif /* COMMENT */
3184     }
3185     else if (code == CM_ERROR_BADSHARENAME) {
3186         NTStatus = 0xC00000CCL; /* Bad network name */
3187     }
3188     else if (code == CM_ERROR_NOIPC) {
3189 #ifdef COMMENT
3190         NTStatus = 0xC0000022L; /* Access Denied */
3191 #else   
3192         NTStatus = 0xC000013DL; /* Remote Resources */
3193 #endif
3194     }
3195     else if (code == CM_ERROR_CLOCKSKEW) {
3196         NTStatus = 0xC0000133L; /* Time difference at DC */
3197     }
3198     else if (code == CM_ERROR_BADTID) {
3199         NTStatus = 0xC0982005L; /* SMB bad TID */
3200     }
3201     else if (code == CM_ERROR_USESTD) {
3202         NTStatus = 0xC09820FBL; /* SMB use standard */
3203     }
3204     else if (code == CM_ERROR_QUOTA) {
3205         NTStatus = 0xC0000044L; /* Quota exceeded */
3206     }
3207     else if (code == CM_ERROR_SPACE) {
3208         NTStatus = 0xC000007FL; /* Disk full */
3209     }
3210     else if (code == CM_ERROR_ATSYS) {
3211         NTStatus = 0xC0000033L; /* Object name invalid */
3212     }
3213     else if (code == CM_ERROR_BADNTFILENAME) {
3214         NTStatus = 0xC0000033L; /* Object name invalid */
3215     }
3216     else if (code == CM_ERROR_WOULDBLOCK) {
3217         NTStatus = 0xC00000D8L; /* Can't wait */
3218     }
3219     else if (code == CM_ERROR_SHARING_VIOLATION) {
3220         NTStatus = 0xC0000043L; /* Sharing violation */
3221     }
3222     else if (code == CM_ERROR_LOCK_CONFLICT) {
3223         NTStatus = 0xC0000054L; /* Lock conflict */
3224     }
3225     else if (code == CM_ERROR_PARTIALWRITE) {
3226         NTStatus = 0xC000007FL; /* Disk full */
3227     }
3228     else if (code == CM_ERROR_BUFFERTOOSMALL) {
3229         NTStatus = 0xC0000023L; /* Buffer too small */
3230     }
3231     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3232         NTStatus = 0xC0000035L; /* Object name collision */
3233     }   
3234     else if (code == CM_ERROR_BADPASSWORD) {
3235         NTStatus = 0xC000006DL; /* unknown username or bad password */
3236     }
3237     else if (code == CM_ERROR_BADLOGONTYPE) {
3238         NTStatus = 0xC000015BL; /* logon type not granted */
3239     }
3240     else if (code == CM_ERROR_GSSCONTINUE) {
3241         NTStatus = 0xC0000016L; /* more processing required */
3242     }
3243     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3244 #ifdef COMMENT
3245         NTStatus = 0xC0000280L; /* reparse point not resolved */
3246 #else
3247         NTStatus = 0xC0000022L; /* Access Denied */
3248 #endif
3249     }
3250     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3251         NTStatus = 0xC0000257L; /* Path Not Covered */
3252     } 
3253     else if (code == CM_ERROR_ALLBUSY) {
3254         NTStatus = 0xC000022DL; /* Retry */
3255     } 
3256     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3257         NTStatus = 0xC00000BEL; /* Bad Network Path */
3258     } 
3259     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3260         NTStatus = 0xC0000322L; /* No Kerberos key */
3261     } 
3262     else if (code == CM_ERROR_BAD_LEVEL) {
3263         NTStatus = 0xC0000148L; /* Invalid Level */
3264     } 
3265     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3266         NTStatus = 0xC000007EL; /* Range Not Locked */
3267     } 
3268     else if (code == CM_ERROR_NOSUCHDEVICE) {
3269         NTStatus = 0xC000000EL; /* No Such Device */
3270     }
3271     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3272         NTStatus = 0xC0000055L; /* Lock Not Granted */
3273     } else if (code == ENOMEM) {
3274         NTStatus = 0xC0000017L; /* Out of Memory */
3275     } else {
3276         NTStatus = 0xC0982001L; /* SMB non-specific error */
3277     }
3278
3279     *NTStatusp = NTStatus;
3280     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3281 }       
3282
3283 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3284                       unsigned char *classp)
3285 {
3286     unsigned char class;
3287     unsigned short error;
3288
3289     /* map CM_ERROR_* errors to SMB errors */
3290     if (code == CM_ERROR_NOSUCHCELL) {
3291         class = 1;
3292         error = 3;      /* bad path */
3293     }
3294     else if (code == CM_ERROR_NOSUCHVOLUME) {
3295         class = 1;
3296         error = 3;      /* bad path */
3297     }
3298     else if (code == CM_ERROR_TIMEDOUT) {
3299         class = 2;
3300         error = 81;     /* server is paused */
3301     }
3302     else if (code == CM_ERROR_RETRY) {
3303         class = 2;      /* shouldn't happen */
3304         error = 1;
3305     }
3306     else if (code == CM_ERROR_NOACCESS) {
3307         class = 2;
3308         error = 4;      /* bad access */
3309     }
3310     else if (code == CM_ERROR_READONLY) {
3311         class = 3;
3312         error = 19;     /* read only */
3313     }
3314     else if (code == CM_ERROR_NOSUCHFILE ||
3315              code == CM_ERROR_BPLUS_NOMATCH) {
3316         class = 1;
3317         error = 2;      /* ENOENT! */
3318     }
3319     else if (code == CM_ERROR_NOSUCHPATH) {
3320         class = 1;
3321         error = 3;      /* Bad path */
3322     }
3323     else if (code == CM_ERROR_TOOBIG) {
3324         class = 1;
3325         error = 11;     /* bad format */
3326     }
3327     else if (code == CM_ERROR_INVAL) {
3328         class = 2;      /* server non-specific error code */
3329         error = 1;
3330     }
3331     else if (code == CM_ERROR_BADFD) {
3332         class = 1;
3333         error = 6;      /* invalid file handle */
3334     }
3335     else if (code == CM_ERROR_BADFDOP) {
3336         class = 1;      /* invalid op on FD */
3337         error = 5;
3338     }
3339     else if (code == CM_ERROR_EXISTS) {
3340         class = 1;
3341         error = 80;     /* file already exists */
3342     }
3343     else if (code == CM_ERROR_NOTEMPTY) {
3344         class = 1;
3345         error = 5;      /* delete directory not empty */
3346     }
3347     else if (code == CM_ERROR_CROSSDEVLINK) {
3348         class = 1;
3349         error = 17;     /* EXDEV */
3350     }
3351     else if (code == CM_ERROR_NOTDIR) {
3352         class = 1;      /* bad path */
3353         error = 3;
3354     }
3355     else if (code == CM_ERROR_ISDIR) {
3356         class = 1;      /* access denied; DOS doesn't have a good match */
3357         error = 5;
3358     }       
3359     else if (code == CM_ERROR_BADOP) {
3360         class = 2;
3361         error = 65535;
3362     }
3363     else if (code == CM_ERROR_BADSHARENAME) {
3364         class = 2;
3365         error = 6;
3366     }
3367     else if (code == CM_ERROR_NOIPC) {
3368         class = 2;
3369         error = 4; /* bad access */
3370     }
3371     else if (code == CM_ERROR_CLOCKSKEW) {
3372         class = 1;      /* invalid function */
3373         error = 1;
3374     }
3375     else if (code == CM_ERROR_BADTID) {
3376         class = 2;
3377         error = 5;
3378     }
3379     else if (code == CM_ERROR_USESTD) {
3380         class = 2;
3381         error = 251;
3382     }
3383     else if (code == CM_ERROR_REMOTECONN) {
3384         class = 2;
3385         error = 82;
3386     }
3387     else if (code == CM_ERROR_QUOTA) {
3388         if (vcp->flags & SMB_VCFLAG_USEV3) {
3389             class = 3;
3390             error = 39; /* disk full */
3391         }
3392         else {
3393             class = 1;
3394             error = 5;  /* access denied */
3395         }
3396     }
3397     else if (code == CM_ERROR_SPACE) {
3398         if (vcp->flags & SMB_VCFLAG_USEV3) {
3399             class = 3;
3400             error = 39; /* disk full */
3401         }
3402         else {
3403             class = 1;
3404             error = 5;  /* access denied */
3405         }
3406     }
3407     else if (code == CM_ERROR_PARTIALWRITE) {
3408         class = 3;
3409         error = 39;     /* disk full */
3410     }
3411     else if (code == CM_ERROR_ATSYS) {
3412         class = 1;
3413         error = 2;      /* ENOENT */
3414     }
3415     else if (code == CM_ERROR_WOULDBLOCK) {
3416         class = 1;
3417         error = 33;     /* lock conflict */
3418     }
3419     else if (code == CM_ERROR_LOCK_CONFLICT) {
3420         class = 1;
3421         error = 33;     /* lock conflict */
3422     }
3423     else if (code == CM_ERROR_SHARING_VIOLATION) {
3424         class = 1;
3425         error = 33;     /* lock conflict */
3426     }
3427     else if (code == CM_ERROR_NOFILES) {
3428         class = 1;
3429         error = 18;     /* no files in search */
3430     }
3431     else if (code == CM_ERROR_RENAME_IDENTICAL) {
3432         class = 1;
3433         error = 183;     /* Samba uses this */
3434     }
3435     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3436         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3437         class = 2;
3438         error = 2; /* bad password */
3439     }
3440     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3441         class = 2;
3442         error = 3;     /* bad path */
3443     }
3444     else {
3445         class = 2;
3446         error = 1;
3447     }
3448
3449     *scodep = error;
3450     *classp = class;
3451     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3452 }       
3453
3454 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3455 {
3456     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3457     return CM_ERROR_BADOP;
3458 }
3459
3460 /* SMB_COM_ECHO */
3461 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3462 {
3463     unsigned short EchoCount, i;
3464     char *data, *outdata;
3465     int dataSize;
3466
3467     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3468
3469     for (i=1; i<=EchoCount; i++) {
3470         data = smb_GetSMBData(inp, &dataSize);
3471         smb_SetSMBParm(outp, 0, i);
3472         smb_SetSMBDataLength(outp, dataSize);
3473         outdata = smb_GetSMBData(outp, NULL);
3474         memcpy(outdata, data, dataSize);
3475         smb_SendPacket(vcp, outp);
3476     }
3477
3478     return 0;
3479 }
3480
3481 /* SMB_COM_READ_RAW */
3482 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3483 {
3484     osi_hyper_t offset;
3485     long count, minCount, finalCount;
3486     unsigned short fd;
3487     unsigned pid;
3488     smb_fid_t *fidp;
3489     smb_t *smbp = (smb_t*) inp;
3490     long code = 0;
3491     cm_user_t *userp = NULL;
3492     NCB *ncbp;
3493     int rc;
3494     char *rawBuf = NULL;
3495
3496     rawBuf = NULL;
3497     finalCount = 0;
3498
3499     fd = smb_GetSMBParm(inp, 0);
3500     count = smb_GetSMBParm(inp, 3);
3501     minCount = smb_GetSMBParm(inp, 4);
3502     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3503
3504     if (*inp->wctp == 10) {
3505         /* we were sent a request with 64-bit file offsets */
3506 #ifdef AFS_LARGEFILES
3507         offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3508
3509         if (LargeIntegerLessThanZero(offset)) {
3510             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3511             goto send1;
3512         }
3513 #else
3514         if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3515             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset.  Dropping request.");
3516             goto send1;
3517         } else {
3518             offset.HighPart = 0;
3519         }
3520 #endif
3521     } else {
3522         /* we were sent a request with 32-bit file offsets */
3523         offset.HighPart = 0;
3524     }
3525
3526     osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3527              fd, offset.HighPart, offset.LowPart, count);
3528
3529     fidp = smb_FindFID(vcp, fd, 0);
3530     if (!fidp)
3531         goto send1;
3532
3533     lock_ObtainMutex(&fidp->mx);
3534     if (!fidp->scp) {
3535         lock_ReleaseMutex(&fidp->mx);
3536         smb_ReleaseFID(fidp);
3537         return CM_ERROR_BADFD;
3538     }
3539
3540     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3541         lock_ReleaseMutex(&fidp->mx);
3542         smb_CloseFID(vcp, fidp, NULL, 0);
3543         code = CM_ERROR_NOSUCHFILE;
3544         goto send1a;
3545     }
3546
3547     pid = smbp->pid;
3548     {
3549         LARGE_INTEGER LOffset, LLength;
3550         cm_key_t key;
3551
3552         key = cm_GenerateKey(vcp->vcID, pid, fd);
3553
3554         LOffset.HighPart = offset.HighPart;
3555         LOffset.LowPart = offset.LowPart;
3556         LLength.HighPart = 0;
3557         LLength.LowPart = count;
3558
3559         lock_ObtainWrite(&fidp->scp->rw);
3560         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3561         lock_ReleaseWrite(&fidp->scp->rw);
3562     }    
3563     if (code) {
3564         lock_ReleaseMutex(&fidp->mx);
3565         goto send1a;
3566     }
3567
3568     lock_ObtainMutex(&smb_RawBufLock);
3569     if (smb_RawBufs) {
3570         /* Get a raw buf, from head of list */
3571         rawBuf = smb_RawBufs;
3572         smb_RawBufs = *(char **)smb_RawBufs;
3573     }
3574     lock_ReleaseMutex(&smb_RawBufLock);
3575     if (!rawBuf) {
3576         lock_ReleaseMutex(&fidp->mx);
3577         goto send1a;
3578     }
3579
3580     if (fidp->flags & SMB_FID_IOCTL)
3581     {
3582         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3583         if (rawBuf) {
3584             /* Give back raw buffer */
3585             lock_ObtainMutex(&smb_RawBufLock);
3586             *((char **) rawBuf) = smb_RawBufs;
3587             
3588             smb_RawBufs = rawBuf;
3589             lock_ReleaseMutex(&smb_RawBufLock);
3590         }
3591
3592         lock_ReleaseMutex(&fidp->mx);
3593         smb_ReleaseFID(fidp);
3594         return rc;
3595     }
3596     lock_ReleaseMutex(&fidp->mx);
3597
3598     userp = smb_GetUserFromVCP(vcp, inp);
3599
3600     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3601
3602     if (code != 0)
3603         goto send;
3604
3605   send:
3606     cm_ReleaseUser(userp);
3607
3608   send1a:
3609     smb_ReleaseFID(fidp);
3610
3611   send1:
3612     ncbp = outp->ncbp;
3613     memset((char *)ncbp, 0, sizeof(NCB));
3614
3615     ncbp->ncb_length = (unsigned short) finalCount;
3616     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3617     ncbp->ncb_lana_num = vcp->lana;
3618     ncbp->ncb_command = NCBSEND;
3619     ncbp->ncb_buffer = rawBuf;
3620
3621     code = Netbios(ncbp);
3622     if (code != 0)
3623         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3624
3625     if (rawBuf) {
3626         /* Give back raw buffer */
3627         lock_ObtainMutex(&smb_RawBufLock);
3628         *((char **) rawBuf) = smb_RawBufs;
3629
3630         smb_RawBufs = rawBuf;
3631         lock_ReleaseMutex(&smb_RawBufLock);
3632     }
3633
3634     return 0;
3635 }
3636
3637 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3638 {
3639     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3640                          ongoingOps - 1);
3641     return 0;
3642 }
3643
3644 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3645 {
3646     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3647                          ongoingOps - 1);
3648     return 0;
3649 }
3650
3651 /* SMB_COM_NEGOTIATE */
3652 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3653 {
3654     char *namep;
3655     char *datap;
3656     int coreProtoIndex;
3657     int v3ProtoIndex;
3658     int NTProtoIndex;
3659     int VistaProtoIndex;
3660     int protoIndex;                             /* index we're using */
3661     int namex;
3662     int dbytes;
3663     int entryLength;
3664     int tcounter;
3665     char protocol_array[10][1024];  /* protocol signature of the client */
3666     int caps;                       /* capabilities */
3667     time_t unixTime;
3668     afs_uint32 dosTime;
3669     TIME_ZONE_INFORMATION tzi;
3670
3671     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3672                          ongoingOps - 1);
3673
3674     namep = smb_GetSMBData(inp, &dbytes);
3675     namex = 0;
3676     tcounter = 0;
3677     coreProtoIndex = -1;                /* not found */
3678     v3ProtoIndex = -1;
3679     NTProtoIndex = -1;
3680     VistaProtoIndex = -1;
3681     while(namex < dbytes) {
3682         osi_Log1(smb_logp, "Protocol %s",
3683                   osi_LogSaveString(smb_logp, namep+1));
3684         strcpy(protocol_array[tcounter], namep+1);
3685
3686         /* namep points at the first protocol, or really, a 0x02
3687          * byte preceding the null-terminated ASCII name.
3688          */
3689         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3690             coreProtoIndex = tcounter;
3691         }       
3692         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3693             v3ProtoIndex = tcounter;
3694         }
3695         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3696             NTProtoIndex = tcounter;
3697         }
3698         else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3699             VistaProtoIndex = tcounter;
3700         }
3701
3702         /* compute size of protocol entry */
3703         entryLength = (int)strlen(namep+1);
3704         entryLength += 2;       /* 0x02 bytes and null termination */
3705
3706         /* advance over this protocol entry */
3707         namex += entryLength;
3708         namep += entryLength;
3709         tcounter++;             /* which proto entry we're looking at */
3710     }
3711
3712     lock_ObtainMutex(&vcp->mx);
3713 #if 0
3714     if (VistaProtoIndex != -1) {
3715         protoIndex = VistaProtoIndex;
3716         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3717     } else 
3718 #endif  
3719         if (NTProtoIndex != -1) {
3720         protoIndex = NTProtoIndex;
3721         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3722     }
3723     else if (v3ProtoIndex != -1) {
3724         protoIndex = v3ProtoIndex;
3725         vcp->flags |= SMB_VCFLAG_USEV3;
3726     }   
3727     else if (coreProtoIndex != -1) {
3728         protoIndex = coreProtoIndex;
3729         vcp->flags |= SMB_VCFLAG_USECORE;
3730     }   
3731     else protoIndex = -1;
3732     lock_ReleaseMutex(&vcp->mx);
3733
3734     if (protoIndex == -1)
3735         return CM_ERROR_INVAL;
3736     else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3737         smb_SetSMBParm(outp, 0, protoIndex);
3738         if (smb_authType != SMB_AUTH_NONE) {
3739             smb_SetSMBParmByte(outp, 1,
3740                                NEGOTIATE_SECURITY_USER_LEVEL |
3741                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
3742         } else {
3743             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3744         }
3745         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
3746         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3747         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
3748         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
3749         /* The session key is not a well documented field however most clients
3750          * will echo back the session key to the server.  Currently we are using
3751          * the same value for all sessions.  We should generate a random value
3752          * and store it into the vcp 
3753          */
3754         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
3755         smb_SetSMBParm(outp, 8, 1);
3756         /* 
3757          * Tried changing the capabilities to support for W2K - defect 117695
3758          * Maybe something else needs to be changed here?
3759          */
3760         /*
3761         if (isWindows2000) 
3762         smb_SetSMBParmLong(outp, 9, 0x43fd);
3763         else 
3764         smb_SetSMBParmLong(outp, 9, 0x251);
3765         */
3766         /* Capabilities: *
3767          * 32-bit error codes *
3768          * and NT Find *
3769          * and NT SMB's *
3770          * and raw mode 
3771          * and DFS
3772          * and Unicode */
3773         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3774 #ifdef DFS_SUPPORT
3775                NTNEGOTIATE_CAPABILITY_DFS |
3776 #endif
3777 #ifdef AFS_LARGEFILES
3778                NTNEGOTIATE_CAPABILITY_LARGEFILES |
3779 #endif
3780                NTNEGOTIATE_CAPABILITY_NTFIND |
3781                NTNEGOTIATE_CAPABILITY_RAWMODE |
3782                NTNEGOTIATE_CAPABILITY_NTSMB;
3783
3784         if ( smb_authType == SMB_AUTH_EXTENDED )
3785             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3786
3787 #ifdef SMB_UNICODE
3788         if ( smb_UseUnicode ) {
3789             caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3790         }
3791 #endif
3792
3793         smb_SetSMBParmLong(outp, 9, caps);
3794         time(&unixTime);
3795         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3796         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3797         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3798
3799         GetTimeZoneInformation(&tzi);
3800         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
3801
3802         if (smb_authType == SMB_AUTH_NTLM) {
3803             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3804             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3805             /* paste in encryption key */
3806             datap = smb_GetSMBData(outp, NULL);
3807             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3808             /* and the faux domain name */
3809             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3810                                   datap + MSV1_0_CHALLENGE_LENGTH,
3811                                   (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3812         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3813             void * secBlob;
3814             int secBlobLength;
3815
3816             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3817
3818             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3819
3820             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3821                         
3822             datap = smb_GetSMBData(outp, NULL);
3823             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3824
3825             if (secBlob) {
3826                 datap += sizeof(smb_ServerGUID);
3827                 memcpy(datap, secBlob, secBlobLength);
3828                 free(secBlob);
3829             }
3830         } else {
3831             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3832             smb_SetSMBDataLength(outp, 0);   /* Perhaps we should specify 8 bytes anyway */
3833         }
3834     }
3835     else if (v3ProtoIndex != -1) {
3836         smb_SetSMBParm(outp, 0, protoIndex);
3837
3838         /* NOTE: Extended authentication cannot be negotiated with v3
3839          * therefore we fail over to NTLM 
3840          */
3841         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3842             smb_SetSMBParm(outp, 1,
3843                            NEGOTIATE_SECURITY_USER_LEVEL |
3844                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
3845         } else {
3846             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3847         }
3848         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3849         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
3850         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3851         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
3852         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
3853         smb_SetSMBParm(outp, 7, 1);
3854         time(&unixTime);
3855         smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3856         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
3857         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
3858
3859         GetTimeZoneInformation(&tzi);
3860         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
3861
3862         /* NOTE: Extended authentication cannot be negotiated with v3
3863          * therefore we fail over to NTLM 
3864          */
3865         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3866             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
3867             smb_SetSMBParm(outp, 12, 0);        /* resvd */
3868             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
3869             datap = smb_GetSMBData(outp, NULL);
3870             /* paste in a new encryption key */
3871             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3872             /* and the faux domain name */
3873             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3874                                   datap + MSV1_0_CHALLENGE_LENGTH,
3875                                   (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3876         } else {
3877             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3878             smb_SetSMBParm(outp, 12, 0); /* resvd */
3879             smb_SetSMBDataLength(outp, 0);
3880         }
3881     }
3882     else if (coreProtoIndex != -1) {     /* not really supported anymore */
3883         smb_SetSMBParm(outp, 0, protoIndex);
3884         smb_SetSMBDataLength(outp, 0);
3885     }
3886     return 0;
3887 }
3888
3889 void smb_CheckVCs(void)
3890 {
3891     smb_vc_t * vcp, *nextp;
3892     smb_packet_t * outp = smb_GetPacket();
3893     smb_t *smbp;
3894             
3895     lock_ObtainWrite(&smb_rctLock);
3896     for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp ) 
3897     {
3898         if (vcp->magic != SMB_VC_MAGIC)
3899             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp", 
3900                        __FILE__, __LINE__);
3901
3902         /* on the first pass hold 'vcp' which was not held as 'nextp' */
3903         if (vcp != nextp)
3904             smb_HoldVCNoLock(vcp);
3905
3906         /* 
3907          * obtain a reference to 'nextp' now because we drop the
3908          * smb_rctLock later and the list contents could change 
3909          * or 'vcp' could be destroyed when released.
3910          */
3911         nextp = vcp->nextp;
3912         if (nextp)
3913             smb_HoldVCNoLock(nextp);
3914
3915         if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
3916             smb_ReleaseVCNoLock(vcp);
3917             continue;
3918         }
3919
3920         smb_FormatResponsePacket(vcp, NULL, outp);
3921         smbp = (smb_t *)outp;
3922         outp->inCom = smbp->com = 0x2b /* Echo */;
3923         smbp->tid = 0xFFFF;
3924         smbp->pid = 0;
3925         smbp->uid = 0;
3926         smbp->mid = 0;
3927         smbp->res[0] = 0;
3928         smbp->res[1] = 0;
3929
3930         smb_SetSMBParm(outp, 0, 0);
3931         smb_SetSMBDataLength(outp, 0);
3932         lock_ReleaseWrite(&smb_rctLock);
3933
3934         smb_SendPacket(vcp, outp);
3935
3936         lock_ObtainWrite(&smb_rctLock);
3937         smb_ReleaseVCNoLock(vcp);
3938     }
3939     lock_ReleaseWrite(&smb_rctLock);
3940     smb_FreePacket(outp);
3941 }
3942
3943 void smb_Daemon(void *parmp)
3944 {
3945     afs_uint32 count = 0;
3946     smb_username_t    **unpp;
3947     time_t              now;
3948
3949     while(smbShutdownFlag == 0) {
3950         count++;
3951         thrd_Sleep(10000);
3952
3953         if (smbShutdownFlag == 1)
3954             break;
3955         
3956         if ((count % 72) == 0)  {       /* every five minutes */
3957             struct tm myTime;
3958             time_t old_localZero = smb_localZero;
3959                  
3960             /* Initialize smb_localZero */
3961             myTime.tm_isdst = -1;               /* compute whether on DST or not */
3962             myTime.tm_year = 70;
3963             myTime.tm_mon = 0;
3964             myTime.tm_mday = 1;
3965             myTime.tm_hour = 0;
3966             myTime.tm_min = 0;
3967             myTime.tm_sec = 0;
3968             smb_localZero = mktime(&myTime);
3969
3970 #ifndef USE_NUMERIC_TIME_CONV
3971             smb_CalculateNowTZ();
3972 #endif /* USE_NUMERIC_TIME_CONV */
3973 #ifdef AFS_FREELANCE
3974             if ( smb_localZero != old_localZero )
3975                 cm_noteLocalMountPointChange();
3976 #endif
3977
3978             smb_CheckVCs();
3979         }
3980
3981         /* GC smb_username_t objects that will no longer be used */
3982         now = osi_Time();
3983         lock_ObtainWrite(&smb_rctLock);
3984         for ( unpp=&usernamesp; *unpp; ) {
3985             int deleteOk = 0;
3986             smb_username_t *unp;
3987
3988             lock_ObtainMutex(&(*unpp)->mx);
3989             if ( (*unpp)->refCount > 0 || 
3990                  ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) || 
3991                  !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3992                 ;
3993             else if (!smb_LogoffTokenTransfer ||
3994                      ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3995                 deleteOk = 1;
3996             lock_ReleaseMutex(&(*unpp)->mx);
3997
3998             if (deleteOk) {
3999                 cm_user_t * userp;
4000
4001                 unp = *unpp;    
4002                 *unpp = unp->nextp;
4003                 unp->nextp = NULL;
4004                 lock_FinalizeMutex(&unp->mx);
4005                 userp = unp->userp;
4006                 free(unp->name);
4007                 free(unp->machine);
4008                 free(unp);
4009                 if (userp)
4010                     cm_ReleaseUser(userp);
4011             } else {
4012                 unpp = &(*unpp)->nextp;
4013             }
4014         }
4015         lock_ReleaseWrite(&smb_rctLock);
4016
4017         /* XXX GC dir search entries */
4018     }
4019 }
4020
4021 void smb_WaitingLocksDaemon()
4022 {
4023     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4024     smb_waitingLock_t *wl, *wlNext;
4025     int first;
4026     smb_vc_t *vcp;
4027     smb_packet_t *inp, *outp;
4028     NCB *ncbp;
4029     long code = 0;
4030
4031     while (smbShutdownFlag == 0) {
4032         lock_ObtainWrite(&smb_globalLock);
4033         nwlRequest = smb_allWaitingLocks;
4034         if (nwlRequest == NULL) {
4035             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4036             thrd_Sleep(1000);
4037             continue;
4038         } else {
4039             first = 1;
4040             osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4041         }
4042
4043         do {
4044             if (first)
4045                 first = 0;
4046             else
4047                 lock_ObtainWrite(&smb_globalLock);
4048
4049             osi_Log1(smb_logp, "    Checking waiting lock request %p", nwlRequest);
4050
4051             wlRequest = nwlRequest;
4052             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4053             lock_ReleaseWrite(&smb_globalLock);
4054
4055             code = 0;
4056
4057             for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4058                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4059                     continue;
4060
4061                 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4062                     code = CM_ERROR_LOCK_NOT_GRANTED;
4063                     break;
4064                 }
4065
4066                 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4067                 
4068                 /* wl->state is either _DONE or _WAITING.  _ERROR
4069                    would no longer be on the queue. */
4070                 code = cm_RetryLock( wl->lockp,
4071                                      !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4072
4073                 if (code == 0) {
4074                     wl->state = SMB_WAITINGLOCKSTATE_DONE;
4075                 } else if (code != CM_ERROR_WOULDBLOCK) {
4076                     wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4077                     break;
4078                 }
4079             }
4080
4081             if (code == CM_ERROR_WOULDBLOCK) {
4082
4083                 /* no progress */
4084                 if (wlRequest->msTimeout != 0xffffffff
4085                      && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4086                     goto endWait;
4087
4088                 continue;
4089             }
4090
4091           endWait:
4092
4093             if (code != 0) {
4094                 cm_scache_t * scp;
4095                 cm_req_t req;
4096
4097                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4098                          wlRequest);
4099
4100                 scp = wlRequest->scp;
4101                 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4102
4103                 smb_InitReq(&req);
4104
4105                 lock_ObtainWrite(&scp->rw);
4106
4107                 for (wl = wlRequest->locks; wl; wl = wlNext) {
4108                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4109                 
4110                     if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4111                         cm_Unlock(scp, wlRequest->lockType, wl->LOffset, 
4112                                   wl->LLength, wl->key, 0, NULL, &req);
4113
4114                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4115
4116                     free(wl);
4117                 }
4118                 
4119                 lock_ReleaseWrite(&scp->rw);
4120
4121             } else {
4122
4123                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4124                          wlRequest);
4125
4126                 for (wl = wlRequest->locks; wl; wl = wlNext) {
4127                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4128                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4129                     free(wl);
4130                 }
4131             }
4132
4133             vcp = wlRequest->vcp;
4134             inp = wlRequest->inp;
4135             outp = wlRequest->outp;
4136             ncbp = smb_GetNCB();
4137             ncbp->ncb_length = inp->ncb_length;
4138             inp->spacep = cm_GetSpace();
4139
4140             /* Remove waitingLock from list */
4141             lock_ObtainWrite(&smb_globalLock);
4142             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4143                          &wlRequest->q);
4144             lock_ReleaseWrite(&smb_globalLock);
4145
4146             /* Resume packet processing */
4147             if (code == 0)
4148                 smb_SetSMBDataLength(outp, 0);
4149             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4150             outp->resumeCode = code;
4151             outp->ncbp = ncbp;
4152             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4153
4154             /* Clean up */
4155             cm_FreeSpace(inp->spacep);
4156             smb_FreePacket(inp);
4157             smb_FreePacket(outp);
4158             smb_ReleaseVC(vcp);
4159             cm_ReleaseSCache(wlRequest->scp);
4160             smb_FreeNCB(ncbp);
4161             free(wlRequest);
4162         } while (nwlRequest && smbShutdownFlag == 0);
4163         thrd_Sleep(1000);
4164     }
4165 }
4166
4167 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4168 {
4169     osi_Log0(smb_logp, "SMB receive get disk attributes");
4170
4171     smb_SetSMBParm(outp, 0, 32000);
4172     smb_SetSMBParm(outp, 1, 64);
4173     smb_SetSMBParm(outp, 2, 1024);
4174     smb_SetSMBParm(outp, 3, 30000);
4175     smb_SetSMBParm(outp, 4, 0);
4176     smb_SetSMBDataLength(outp, 0);
4177     return 0;
4178 }
4179
4180 /* SMB_COM_TREE_CONNECT */
4181 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4182 {
4183     smb_tid_t *tidp;
4184     smb_user_t *uidp;
4185     unsigned short newTid;
4186     clientchar_t shareName[AFSPATHMAX];
4187     clientchar_t *sharePath;
4188     int shareFound;
4189     clientchar_t *tp;
4190     clientchar_t *pathp;
4191     cm_user_t *userp;
4192
4193     osi_Log0(smb_logp, "SMB receive tree connect");
4194
4195     /* parse input parameters */
4196     {
4197         char *tbp;
4198         tbp = smb_GetSMBData(inp, NULL);
4199         pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4200         if (!pathp)
4201             return CM_ERROR_BADSMB;
4202     }
4203     tp = cm_ClientStrRChr(pathp, '\\');
4204     if (!tp)
4205         return CM_ERROR_BADSMB;
4206     cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4207
4208     lock_ObtainMutex(&vcp->mx);
4209     newTid = vcp->tidCounter++;
4210     lock_ReleaseMutex(&vcp->mx);
4211
4212     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4213     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4214     if (!uidp)
4215         return CM_ERROR_BADSMB;
4216     userp = smb_GetUserFromUID(uidp);
4217     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4218     smb_ReleaseUID(uidp);
4219     if (!shareFound) {
4220         smb_ReleaseTID(tidp, FALSE);
4221         return CM_ERROR_BADSHARENAME;
4222     }
4223     lock_ObtainMutex(&tidp->mx);
4224     tidp->userp = userp;
4225     tidp->pathname = sharePath;
4226     lock_ReleaseMutex(&tidp->mx);
4227     smb_ReleaseTID(tidp, FALSE);
4228
4229     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4230     smb_SetSMBParm(rsp, 1, newTid);
4231     smb_SetSMBDataLength(rsp, 0);
4232
4233     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4234     return 0;
4235 }
4236
4237 /* set maskp to the mask part of the incoming path.
4238  * Mask is 11 bytes long (8.3 with the dot elided).
4239  * Returns true if succeeds with a valid name, otherwise it does
4240  * its best, but returns false.
4241  */
4242 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4243 {
4244     clientchar_t *tp;
4245     clientchar_t *up;
4246     int i;
4247     int tc;
4248     int valid8Dot3;
4249
4250     /* starts off valid */
4251     valid8Dot3 = 1;
4252
4253     /* mask starts out all blanks */
4254     memset(maskp, ' ', 11);
4255     maskp[11] = '\0';
4256
4257     /* find last backslash, or use whole thing if there is none */
4258     tp = cm_ClientStrRChr(pathp, '\\');
4259     if (!tp) 
4260         tp = pathp;
4261     else 
4262         tp++;   /* skip slash */
4263         
4264     up = maskp;
4265
4266     /* names starting with a dot are illegal */
4267     if (*tp == '.') 
4268         valid8Dot3 = 0;
4269
4270     for(i=0;; i++) {
4271         tc = *tp++;
4272         if (tc == 0) 
4273             return valid8Dot3;
4274         if (tc == '.' || tc == '"') 
4275             break;
4276         if (i < 8) 
4277             *up++ = tc;
4278         else
4279             valid8Dot3 = 0;
4280     }
4281         
4282     /* if we get here, tp point after the dot */
4283     up = maskp+8;       /* ext goes here */
4284     for(i=0;;i++) {
4285         tc = *tp++;
4286         if (tc == 0) 
4287             return valid8Dot3;
4288
4289         /* too many dots */
4290         if (tc == '.' || tc == '"') 
4291             valid8Dot3 = 0;
4292
4293         /* copy extension if not too long */
4294         if (i < 3) 
4295             *up++ = tc;
4296         else 
4297             valid8Dot3 = 0;
4298     }   
4299
4300     /* unreachable */
4301 }
4302
4303 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4304 {
4305     clientchar_t umask[11];
4306     int valid;
4307     int i;
4308     clientchar_t tc1;
4309     clientchar_t tc2;
4310     clientchar_t *tp1;
4311     clientchar_t *tp2;
4312
4313     /* XXX redo this, calling cm_MatchMask with a converted mask */
4314
4315     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4316     if (!valid) 
4317         return 0;
4318  
4319     /* otherwise, we have a valid 8.3 name; see if we have a match,
4320      * treating '?' as a wildcard in maskp (but not in the file name).
4321      */
4322     tp1 = umask;        /* real name, in mask format */
4323     tp2 = maskp;        /* mask, in mask format */
4324     for(i=0; i<11; i++) {
4325         tc1 = *tp1++;   /* clientchar_t from real name */
4326         tc2 = *tp2++;   /* clientchar_t from mask */
4327         tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4328         tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4329         if (tc1 == tc2) 
4330             continue;
4331         if (tc2 == '?' && tc1 != ' ') 
4332             continue;
4333         if (tc2 == '>') 
4334             continue;
4335         return 0;
4336     }
4337
4338     /* we got a match */
4339     return 1;
4340 }
4341
4342 clientchar_t *smb_FindMask(clientchar_t *pathp)
4343 {
4344     clientchar_t *tp;
4345         
4346     tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4347
4348     if (tp) 
4349         return tp+1;    /* skip the slash */
4350     else 
4351         return pathp;   /* no slash, return the entire path */
4352 }       
4353
4354 /* SMB_COM_SEARCH for a volume label
4355
4356    (This is called from smb_ReceiveCoreSearchDir() and not an actual
4357    dispatch function.) */
4358 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4359 {
4360     clientchar_t *pathp;
4361     unsigned char *tp;
4362     clientchar_t mask[12];
4363     unsigned char *statBlockp;
4364     unsigned char initStatBlock[21];
4365     int statLen;
4366         
4367     osi_Log0(smb_logp, "SMB receive search volume");
4368
4369     /* pull pathname and stat block out of request */
4370     tp = smb_GetSMBData(inp, NULL);
4371     pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4372                                 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4373     if (!pathp)
4374         return CM_ERROR_BADSMB;
4375     statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4376     osi_assertx(statBlockp != NULL, "null statBlock");
4377     if (statLen == 0) {
4378         statBlockp = initStatBlock;
4379         statBlockp[0] = 8;
4380     }
4381         
4382     /* for returning to caller */
4383     smb_Get8Dot3MaskFromPath(mask, pathp);
4384
4385     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
4386     tp = smb_GetSMBData(outp, NULL);
4387     *tp++ = 5;
4388     *tp++ = 43; /* bytes in a dir entry */
4389     *tp++ = 0;  /* high byte in counter */
4390
4391     /* now marshall the dir entry, starting with the search status */
4392     *tp++ = statBlockp[0];              /* Reserved */
4393     memcpy(tp, mask, 11); tp += 11;     /* FileName */
4394
4395     /* now pass back server use info, with 1st byte non-zero */
4396     *tp++ = 1;
4397     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
4398
4399     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
4400
4401     *tp++ = 0x8;                /* attribute: volume */
4402
4403     /* copy out time */
4404     *tp++ = 0;
4405     *tp++ = 0;
4406
4407     /* copy out date */
4408     *tp++ = 18;
4409     *tp++ = 178;
4410
4411   &