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