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