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