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