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