Windows: Improve SMB detection of Local System account
[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     if (uidp->unp->flags & SMB_USERNAMEFLAG_SID) {
1245         isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, uidp->unp->name);
1246         return isSystem;
1247     }
1248
1249     /*
1250      * The input name is not a SID for the user.  See if we can
1251      * obtain the SID for the specified name.  If we can, use
1252      * that instead of the name provided for the comparison.
1253      */
1254
1255     LookupAccountNameW( NULL /* System Name to begin Search */,
1256                         uidp->unp->name,
1257                         NULL, &dwSize1,
1258                         NULL, &dwSize2,
1259                         &snu);
1260     gle = GetLastError();
1261     if (gle == ERROR_INSUFFICIENT_BUFFER) {
1262         pSid = malloc(dwSize1);
1263         /*
1264          * Although dwSize2 is supposed to include the terminating
1265          * NUL character, on Win7 it does not.
1266          */
1267         pszRefDomain = malloc((dwSize2 + 1) * sizeof(wchar_t));
1268     }
1269
1270     if ( pSid && pszRefDomain ) {
1271         memset(pSid, 0, dwSize1);
1272
1273         if (LookupAccountNameW( NULL /* System Name to begin Search */,
1274                                 uidp->unp->name,
1275                                 pSid, &dwSize1,
1276                                 pszRefDomain, &dwSize2,
1277                                 &snu))
1278             ConvertSidToStringSidW(pSid, &secSidString);
1279     }
1280
1281     if (secSidString) {
1282         isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, secSidString);
1283         LocalFree(secSidString);
1284     }
1285
1286     if (pSid)
1287         free(pSid);
1288     if (pszRefDomain)
1289         free(pszRefDomain);
1290
1291     return isSystem;
1292 }
1293
1294 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1295                                    afs_uint32 flags)
1296 {
1297     smb_username_t *unp= NULL;
1298
1299     lock_ObtainWrite(&smb_rctLock);
1300     for(unp = usernamesp; unp; unp = unp->nextp) {
1301         if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1302             cm_ClientStrCmpI(unp->machine, machine) == 0) {
1303             unp->refCount++;
1304             break;
1305         }
1306     }
1307     if (!unp && (flags & SMB_FLAG_CREATE)) {
1308         unp = malloc(sizeof(*unp));
1309         memset(unp, 0, sizeof(*unp));
1310         unp->refCount = 1;
1311         unp->nextp = usernamesp;
1312         unp->name = cm_ClientStrDup(usern);
1313         unp->machine = cm_ClientStrDup(machine);
1314         usernamesp = unp;
1315         lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1316         if (flags & SMB_FLAG_AFSLOGON)
1317             unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1318     }
1319
1320     lock_ReleaseWrite(&smb_rctLock);
1321     return unp;
1322 }       
1323
1324 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1325 {
1326     smb_user_t *uidp= NULL;
1327
1328     lock_ObtainWrite(&smb_rctLock);
1329     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1330         if (!uidp->unp) 
1331             continue;
1332         if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1333             uidp->refCount++;
1334             osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1335                      vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1336             break;
1337         } else
1338             continue;
1339     }           
1340     lock_ReleaseWrite(&smb_rctLock);
1341     return uidp;
1342 }       
1343
1344 void smb_ReleaseUsername(smb_username_t *unp)
1345 {
1346     smb_username_t *up;
1347     smb_username_t **lupp;
1348     cm_user_t *userp = NULL;
1349     time_t      now = osi_Time();
1350
1351     lock_ObtainWrite(&smb_rctLock);
1352     osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1353     if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1354         (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1355         lupp = &usernamesp;
1356         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1357             if (up == unp) 
1358                 break;
1359         }
1360         osi_assertx(up != NULL, "null smb_username_t");
1361         *lupp = up->nextp;
1362         up->nextp = NULL;                       /* do not remove this */
1363         lock_FinalizeMutex(&unp->mx);
1364         userp = unp->userp;
1365         free(unp->name);
1366         free(unp->machine);
1367         free(unp);
1368     }
1369     lock_ReleaseWrite(&smb_rctLock);
1370     if (userp)
1371         cm_ReleaseUser(userp);
1372 }       
1373
1374 void smb_HoldUIDNoLock(smb_user_t *uidp)
1375 {
1376     lock_AssertWrite(&smb_rctLock);
1377     uidp->refCount++;
1378 }
1379
1380 void smb_ReleaseUID(smb_user_t *uidp)
1381 {
1382     smb_user_t *up;
1383     smb_user_t **lupp;
1384     smb_username_t *unp = NULL;
1385
1386     lock_ObtainWrite(&smb_rctLock);
1387     osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1388     if (uidp->refCount == 0) {
1389         lupp = &uidp->vcp->usersp;
1390         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1391             if (up == uidp) 
1392                 break;
1393         }
1394         osi_assertx(up != NULL, "null smb_user_t");
1395         *lupp = up->nextp;
1396         lock_FinalizeMutex(&uidp->mx);
1397         unp = uidp->unp;
1398         smb_ReleaseVCNoLock(uidp->vcp);
1399         uidp->vcp = NULL;
1400         free(uidp);
1401     }           
1402     lock_ReleaseWrite(&smb_rctLock);
1403
1404     if (unp) {
1405         if (unp->userp)
1406             cm_ReleaseUserVCRef(unp->userp);
1407         smb_ReleaseUsername(unp);
1408     }
1409 }       
1410
1411 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1412 {
1413     cm_user_t *up = NULL;
1414
1415     if (!uidp)
1416         return NULL;
1417     
1418     lock_ObtainMutex(&uidp->mx);
1419     if (uidp->unp) {
1420         up = uidp->unp->userp;
1421         cm_HoldUser(up);
1422     }
1423     lock_ReleaseMutex(&uidp->mx);
1424
1425     return up;
1426 }
1427
1428
1429 /* retrieve a held reference to a user structure corresponding to an incoming
1430  * request.
1431  * corresponding release function is cm_ReleaseUser.
1432  */
1433 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1434 {
1435     smb_user_t *uidp;
1436     cm_user_t *up = NULL;
1437     smb_t *smbp;
1438
1439     smbp = (smb_t *) inp;
1440     uidp = smb_FindUID(vcp, smbp->uid, 0);
1441     if (!uidp)
1442         return NULL;
1443     
1444     up = smb_GetUserFromUID(uidp);
1445
1446     smb_ReleaseUID(uidp);
1447     return up;
1448 }
1449
1450 /*
1451  * Return a pointer to a pathname extracted from a TID structure.  The
1452  * TID structure is not held; assume it won't go away.
1453  */
1454 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1455 {
1456     smb_tid_t *tidp;
1457     long code = 0;
1458
1459     tidp = smb_FindTID(vcp, tid, 0);
1460     if (!tidp) {
1461         *treepath = NULL;
1462     } else {
1463         if (tidp->flags & SMB_TIDFLAG_IPC) {
1464             code = CM_ERROR_TIDIPC;
1465             /* tidp->pathname would be NULL, but that's fine */
1466         }
1467         *treepath = tidp->pathname;
1468         smb_ReleaseTID(tidp, FALSE);
1469     }
1470     return code;
1471 }
1472
1473 /* check to see if we have a chained fid, that is, a fid that comes from an
1474  * OpenAndX message that ran earlier in this packet.  In this case, the fid
1475  * field in a read, for example, request, isn't set, since the value is
1476  * supposed to be inherited from the openAndX call.
1477  */
1478 int smb_ChainFID(int fid, smb_packet_t *inp)
1479 {
1480     if (inp->fid == 0 || inp->inCount == 0) 
1481         return fid;
1482     else 
1483         return inp->fid;
1484 }
1485
1486 /* are we a priv'd user?  What does this mean on NT? */
1487 int smb_SUser(cm_user_t *userp)
1488 {
1489     return 1;
1490 }
1491
1492 /* find a file ID.  If we pass in 0 we select an unused File ID.
1493  * If the SMB_FLAG_CREATE flag is set, we allocate a new  
1494  * smb_fid_t data structure if desired File ID cannot be found.
1495  */
1496 #ifdef DEBUG_SMB_REFCOUNT
1497 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1498 #else
1499 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1500 #endif
1501 {
1502     smb_fid_t *fidp;
1503     int newFid = 0;
1504         
1505     if (fid == 0) {
1506         if (!(flags & SMB_FLAG_CREATE))
1507             return NULL;
1508         newFid = 1;
1509     }
1510
1511     lock_ObtainWrite(&smb_rctLock);
1512     if (newFid)
1513         fid = vcp->fidCounter;
1514   retry:
1515
1516     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1517         if (fidp->refCount == 0 && fidp->deleteOk) {
1518             fidp->refCount++;
1519             lock_ReleaseWrite(&smb_rctLock);
1520             smb_ReleaseFID(fidp);
1521             lock_ObtainWrite(&smb_rctLock);
1522             /*
1523              * We dropped the smb_rctLock so the fid value we are using
1524              * may now be used by another thread.  Start over with the
1525              * current vcp->fidCounter.
1526              */
1527             if (newFid)
1528                 fid = vcp->fidCounter;
1529             goto retry;
1530         }
1531         if (fid == fidp->fid) {
1532             if (newFid) {
1533                 osi_Log1(smb_logp, "smb_FindFID New Fid Requested.  fid %d found -- retrying ...", fid);
1534                 fid++;
1535                 if (fid == 0xFFFF) {
1536                     osi_Log1(smb_logp,
1537                              "New FID number wraps on vcp 0x%x", vcp);
1538                     fid = 1;
1539                 }
1540                 goto retry;
1541             }
1542             fidp->refCount++;
1543             break;
1544         }
1545     }
1546
1547     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1548         char eventName[MAX_PATH];
1549         EVENT_HANDLE event;
1550
1551         if (!newFid)
1552             osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1553         else
1554             osi_Log1(smb_logp, "smb_FindFID New Fid Requested.  Creating fid %d", fid);
1555
1556         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1557         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1558         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1559             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1560             thrd_CloseHandle(event);
1561             fid++;
1562             if (fid == 0xFFFF) {
1563                 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1564                 fid = 1;
1565             }
1566             goto retry;
1567         }
1568
1569         fidp = malloc(sizeof(*fidp));
1570         memset(fidp, 0, sizeof(*fidp));
1571         osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1572         fidp->refCount = 1;
1573         fidp->vcp = vcp;
1574         smb_HoldVCNoLock(vcp);
1575         lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1576         fidp->fid = fid;
1577         fidp->curr_chunk = fidp->prev_chunk = -2;
1578         fidp->raw_write_event = event;
1579         if (newFid) {
1580             vcp->fidCounter = fid+1;
1581             if (vcp->fidCounter == 0xFFFF) {
1582                 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1583                          vcp);
1584                 vcp->fidCounter = 1;
1585             }
1586         }
1587     }
1588
1589 #ifdef DEBUG_SMB_REFCOUNT
1590     if (fidp) {
1591         afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1592         osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1593     }
1594 #endif
1595     lock_ReleaseWrite(&smb_rctLock);
1596     return fidp;
1597 }
1598
1599
1600 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1601 #ifdef DEBUG_SMB_REFCOUNT
1602 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1603 #else
1604 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1605 #endif
1606 {
1607     smb_fid_t *fidp = NULL, *nextp = NULL;
1608         
1609     if (!scp)
1610         return NULL;
1611
1612     /* 
1613      * If the fidp->scp changes out from under us then
1614      * we must not grab a refCount.  It means the *fidp
1615      * was processed by smb_CloseFID() and the *fidp is 
1616      * no longer valid for use.
1617      */
1618     lock_ObtainWrite(&smb_rctLock);
1619         for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1620         nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1621         if (nextp)
1622             nextp->refCount++;
1623
1624         if (scp == fidp->scp) {
1625             lock_ReleaseWrite(&smb_rctLock);
1626             lock_ObtainMutex(&fidp->mx);
1627             lock_ObtainWrite(&smb_rctLock);
1628             if (scp == fidp->scp) {
1629                 lock_ReleaseMutex(&fidp->mx);
1630                 break;
1631             }
1632             lock_ReleaseMutex(&fidp->mx);
1633         }
1634
1635         if (fidp->refCount > 1) {
1636             fidp->refCount--;
1637         } else {
1638             lock_ReleaseWrite(&smb_rctLock);
1639             smb_ReleaseFID(fidp);
1640             lock_ObtainWrite(&smb_rctLock);
1641         }
1642     }
1643
1644     if (nextp) {
1645         if (nextp->refCount > 1) {
1646             nextp->refCount--;
1647         } else {
1648             lock_ReleaseWrite(&smb_rctLock);
1649             smb_ReleaseFID(nextp);
1650             lock_ObtainWrite(&smb_rctLock);
1651         }
1652     }
1653
1654 #ifdef DEBUG_SMB_REFCOUNT
1655     if (fidp) {
1656         afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1657         osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1658       }
1659 #endif
1660     lock_ReleaseWrite(&smb_rctLock);
1661     return (fidp);
1662 }
1663
1664 #ifdef DEBUG_SMB_REFCOUNT
1665 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1666 #else
1667 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1668 #endif
1669 {
1670     lock_AssertWrite(&smb_rctLock);
1671     fidp->refCount++;
1672 #ifdef DEBUG_SMB_REFCOUNT
1673     afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1674     osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1675 #endif
1676 }
1677
1678
1679 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1680 /* the smb_fid_t->mx and smb_rctLock must not be held */
1681 #ifdef DEBUG_SMB_REFCOUNT
1682 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1683 #else
1684 void smb_ReleaseFID(smb_fid_t *fidp)
1685 #endif
1686 {
1687     cm_scache_t *scp = NULL;
1688     cm_user_t *userp = NULL;
1689     smb_vc_t *vcp = NULL;
1690     smb_ioctl_t *ioctlp;
1691
1692     lock_ObtainMutex(&fidp->mx);
1693     lock_ObtainWrite(&smb_rctLock);
1694     osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1695 #ifdef DEBUG_SMB_REFCOUNT
1696     afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1697     osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1698 #endif
1699     if (fidp->refCount == 0) {
1700         if (fidp->deleteOk) {
1701             vcp = fidp->vcp;
1702             fidp->vcp = NULL;
1703             scp = fidp->scp;    /* release after lock is released */
1704             if (scp) {
1705                 lock_ObtainWrite(&scp->rw);
1706                 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1707                 lock_ReleaseWrite(&scp->rw);
1708                 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1709                 fidp->scp = NULL;
1710             }
1711             userp = fidp->userp;
1712             fidp->userp = NULL;
1713
1714             if (vcp->fidsp) 
1715                 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1716             thrd_CloseHandle(fidp->raw_write_event);
1717
1718             /* and see if there is ioctl stuff to free */
1719             ioctlp = fidp->ioctlp;
1720             if (ioctlp) {
1721                 if (ioctlp->prefix)
1722                 cm_FreeSpace(ioctlp->prefix);
1723                 if (ioctlp->ioctl.inAllocp)
1724                     free(ioctlp->ioctl.inAllocp);
1725                 if (ioctlp->ioctl.outAllocp)
1726                     free(ioctlp->ioctl.outAllocp);
1727                 free(ioctlp);
1728             }
1729
1730             smb_CleanupRPCFid(fidp);
1731
1732             lock_ReleaseMutex(&fidp->mx);
1733             lock_FinalizeMutex(&fidp->mx);
1734             free(fidp);
1735             fidp = NULL;
1736
1737             if (vcp)
1738                 smb_ReleaseVCNoLock(vcp);
1739         }
1740     }
1741     if (fidp)
1742         lock_ReleaseMutex(&fidp->mx);
1743
1744     lock_ReleaseWrite(&smb_rctLock);
1745
1746     /* now release the scache structure */
1747     if (scp) 
1748         cm_ReleaseSCache(scp);
1749
1750     if (userp)
1751         cm_ReleaseUser(userp);
1752 }       
1753
1754 /*
1755  * Case-insensitive search for one string in another;
1756  * used to find variable names in submount pathnames.
1757  */
1758 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1759 {
1760     clientchar_t *cursor;
1761
1762     for (cursor = str1; *cursor; cursor++)
1763         if (cm_ClientStrCmpI(cursor, str2) == 0)
1764             return cursor;
1765
1766     return NULL;
1767 }
1768
1769 /*
1770  * Substitute a variable value for its name in a submount pathname.  Variable
1771  * name has been identified by smb_stristr() and is in substr.  Variable name
1772  * length (plus one) is in substr_size.  Variable value is in newstr.
1773  */
1774 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1775                       unsigned int substr_size, clientchar_t *newstr)
1776 {
1777     clientchar_t temp[1024];
1778
1779     cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1780     cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1781     cm_ClientStrCat(str1, cchstr1, temp);
1782 }
1783
1784 clientchar_t VNUserName[] = _C("%USERNAME%");
1785 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1786 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1787 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1788
1789 typedef struct smb_findShare_rock {
1790     clientchar_t * shareName;
1791     clientchar_t * match;
1792     int matchType;
1793 } smb_findShare_rock_t;
1794
1795 #define SMB_FINDSHARE_EXACT_MATCH 1
1796 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1797
1798 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1799                        osi_hyper_t *offp)
1800 {
1801     int matchType = 0;
1802     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1803     normchar_t normName[MAX_PATH];
1804
1805     if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1806         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1807                  osi_LogSaveString(smb_logp, dep->name));
1808         return 0;
1809     }
1810
1811     if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1812         if(!cm_ClientStrCmpI(normName, vrock->shareName))
1813             matchType = SMB_FINDSHARE_EXACT_MATCH;
1814         else
1815             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1816         if(vrock->match) 
1817             free(vrock->match);
1818         vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1819         vrock->matchType = matchType;
1820
1821         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1822             return CM_ERROR_STOPNOW;
1823     }
1824     return 0;
1825 }
1826
1827
1828 /* find a shareName in the table of submounts */
1829 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1830                   clientchar_t *shareName,
1831                   clientchar_t **pathNamep)
1832 {
1833     DWORD cblen;
1834     DWORD cchlen;
1835     clientchar_t pathName[1024];
1836     clientchar_t *var;
1837     DWORD sizeTemp;
1838     clientchar_t *p, *q;
1839     fschar_t *cellname = NULL;
1840     HKEY parmKey;
1841     DWORD code;
1842     DWORD allSubmount = 1;
1843
1844     /* if allSubmounts == 0, only return the //mountRoot/all share 
1845      * if in fact it has been been created in the subMounts table.  
1846      * This is to allow sites that want to restrict access to the 
1847      * world to do so.
1848      */
1849     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1850                         0, KEY_QUERY_VALUE, &parmKey);
1851     if (code == ERROR_SUCCESS) {
1852         cblen = sizeof(allSubmount);
1853         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1854                                (BYTE *) &allSubmount, &cblen);
1855         if (code != ERROR_SUCCESS) {
1856             allSubmount = 1;
1857         }
1858         RegCloseKey (parmKey);
1859     }
1860
1861     if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1862         *pathNamep = NULL;
1863         return 1;
1864     }
1865
1866     /* In case, the all share is disabled we need to still be able
1867      * to handle ioctl requests 
1868      */
1869     if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1870         *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1871         return 1;
1872     }
1873
1874     if (MSRPC_IsWellKnownService(shareName) ||
1875         cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1876         cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1877         ) {
1878         *pathNamep = NULL;
1879         return 0;
1880     }
1881
1882     /* Check for volume references
1883      * 
1884      * They look like <cell>{%,#}<volume>
1885      */
1886     if (cm_ClientStrChr(shareName, '%') != NULL ||
1887         cm_ClientStrChr(shareName, '#') != NULL) {
1888         clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1889         /* make room for '/@vol:' + mountchar + NULL terminator*/
1890
1891         osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1892                  osi_LogSaveClientString(smb_logp, shareName));
1893
1894         cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1895                             _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1896         cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1897
1898         *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1899         if (*pathNamep) {
1900             cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1901             cm_ClientStrLwr(*pathNamep);
1902             osi_Log1(smb_logp, "   returning pathname [%S]",
1903                      osi_LogSaveClientString(smb_logp, *pathNamep));
1904
1905             return 1;
1906         } else {
1907             return 0;
1908         }
1909     }
1910
1911     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1912                         0, KEY_QUERY_VALUE, &parmKey);
1913     if (code == ERROR_SUCCESS) {
1914         cblen = sizeof(pathName);
1915         code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1916                                 (BYTE *) pathName, &cblen);
1917         if (code != ERROR_SUCCESS)
1918             cblen = 0;
1919         RegCloseKey (parmKey);
1920     } else {
1921         cblen = 0;
1922     }
1923     cchlen = cblen / sizeof(clientchar_t);
1924     if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1925         /* We can accept either unix or PC style AFS pathnames.  Convert
1926          * Unix-style to PC style here for internal use. 
1927          */
1928         p = pathName;
1929         cchlen = lengthof(pathName);
1930
1931         /* within this code block, we maintain, cchlen = writeable
1932            buffer length of p */
1933
1934         if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1935             p += cm_mountRootCLen;  /* skip mount path */
1936             cchlen -= (DWORD)(p - pathName);
1937         }
1938
1939         q = p;
1940         while (*q) {
1941             if (*q == _C('/')) *q = _C('\\');    /* change to \ */
1942             q++;
1943         }
1944
1945         while (1)
1946         {
1947             clientchar_t temp[1024];
1948
1949             if (var = smb_stristr(p, VNUserName)) {
1950                 if (uidp && uidp->unp)
1951                     smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1952                 else
1953                     smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1954             }
1955             else if (var = smb_stristr(p, VNLCUserName)) 
1956             {
1957                 if (uidp && uidp->unp)
1958                     cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1959                 else 
1960                     cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1961                 cm_ClientStrLwr(temp);
1962                 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1963             }
1964             else if (var = smb_stristr(p, VNComputerName)) 
1965             {
1966                 sizeTemp = lengthof(temp);
1967                 GetComputerNameW(temp, &sizeTemp);
1968                 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1969             }
1970             else if (var = smb_stristr(p, VNLCComputerName)) 
1971             {
1972                 sizeTemp = lengthof(temp);
1973                 GetComputerName((LPTSTR)temp, &sizeTemp);
1974                 cm_ClientStrLwr(temp);
1975                 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1976             }
1977             else     
1978                 break;
1979         }
1980         *pathNamep = cm_ClientStrDup(p);
1981         return 1;
1982     } 
1983     else
1984     {
1985         /* First lookup shareName in root.afs */
1986         cm_req_t req;
1987         smb_findShare_rock_t vrock;
1988         osi_hyper_t thyper;
1989         fschar_t ftemp[1024];
1990         clientchar_t * p = shareName; 
1991         int rw = 0;
1992         cm_scache_t * rscp;
1993         cm_user_t *userp;
1994
1995         /*  attempt to locate a partial match in root.afs.  This is because
1996             when using the ANSI RAP calls, the share name is limited to 13 chars
1997             and hence is truncated. Of course we prefer exact matches. */
1998         smb_InitReq(&req);
1999         thyper.HighPart = 0;
2000         thyper.LowPart = 0;
2001
2002         vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
2003         if (vrock.shareName == NULL) 
2004             return 0;
2005         vrock.match = NULL;
2006         vrock.matchType = 0;
2007
2008         userp = (uidp? (uidp->unp ? uidp->unp->userp : cm_rootUserp) : cm_rootUserp);
2009         rscp = cm_RootSCachep(userp, &req);
2010         cm_HoldSCache(rscp);
2011         code = cm_ApplyDir(rscp, smb_FindShareProc, &vrock, &thyper,
2012                            userp, &req, NULL);
2013         cm_ReleaseSCache(rscp);
2014
2015         free(vrock.shareName);
2016         vrock.shareName = NULL;
2017
2018         if (vrock.matchType) {
2019             cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
2020             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2021             free(vrock.match);
2022             return 1;
2023         }
2024
2025         /* if we get here, there was no match for the share in root.afs */
2026         /* so try to create  \\<netbiosName>\<cellname>  */
2027         if ( *p == '.' ) {
2028             p++;
2029             rw = 1;
2030         }
2031         /* Get the full name for this cell */
2032         cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2033         code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
2034         if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
2035             code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2036         if (code && cm_dnsEnabled) {
2037             int ttl;
2038             code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2039         }
2040         if (cellname)
2041             free(cellname);
2042
2043         /* construct the path */
2044         if (code == 0) {
2045             clientchar_t temp[1024];
2046
2047             if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2048             cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2049                                 rw ? _C("/.%S/") : _C("/%S/"), temp);
2050             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2051             return 1;
2052         }
2053     }
2054     }
2055     /* failure */
2056     *pathNamep = NULL;
2057     return 0;
2058 }
2059
2060 /* Client-side offline caching policy types */
2061 #define CSC_POLICY_MANUAL 0
2062 #define CSC_POLICY_DOCUMENTS 1
2063 #define CSC_POLICY_PROGRAMS 2
2064 #define CSC_POLICY_DISABLE 3
2065
2066 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2067 {
2068     DWORD len;
2069     clientchar_t policy[1024];
2070     DWORD dwType;
2071     HKEY hkCSCPolicy;
2072     int  retval = CSC_POLICY_MANUAL;
2073
2074     if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2075                         AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2076                         0,
2077                         "AFS",
2078                         REG_OPTION_NON_VOLATILE,
2079                         KEY_READ,
2080                         NULL,
2081                         &hkCSCPolicy,
2082                         NULL ) != ERROR_SUCCESS)
2083         retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2084
2085     len = sizeof(policy);
2086     if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2087          len == 0) {
2088         retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2089     }
2090     else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2091     {
2092         retval = CSC_POLICY_MANUAL;
2093     }
2094     else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2095     {
2096         retval = CSC_POLICY_DOCUMENTS;
2097     }
2098     else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2099     {
2100         retval = CSC_POLICY_PROGRAMS;
2101     }
2102     else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2103     {
2104         retval = CSC_POLICY_DISABLE;
2105     }
2106         
2107     RegCloseKey(hkCSCPolicy);
2108     return retval;
2109 }
2110
2111 /* find a dir search structure by cookie value, and return it held.
2112  * Must be called with smb_globalLock held.
2113  */
2114 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2115 {
2116     smb_dirSearch_t *dsp;
2117         
2118     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2119         if (dsp->cookie == cookie) {
2120             if (dsp != smb_firstDirSearchp) {
2121                 /* move to head of LRU queue, too, if we're not already there */
2122                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2123                     smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2124                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2125                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2126                 if (!smb_lastDirSearchp)
2127                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2128             }
2129             dsp->refCount++;
2130             break;
2131         }
2132     }
2133
2134     if (dsp == NULL) {
2135         osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2136         for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2137             osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2138         }
2139     }
2140     return dsp;
2141 }       
2142
2143 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2144 {
2145     lock_ObtainMutex(&dsp->mx);
2146     osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p", 
2147               dsp->cookie, dsp, dsp->scp);
2148     dsp->flags |= SMB_DIRSEARCH_DELETE;
2149     if (dsp->scp != NULL) {
2150         lock_ObtainWrite(&dsp->scp->rw);
2151         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2152             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2153             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2154             dsp->scp->bulkStatProgress = hzero;
2155         }       
2156         lock_ReleaseWrite(&dsp->scp->rw);
2157     }   
2158     lock_ReleaseMutex(&dsp->mx);
2159 }               
2160
2161 /* Must be called with the smb_globalLock held */
2162 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2163 {
2164     cm_scache_t *scp = NULL;
2165
2166     osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2167     if (dsp->refCount == 0) {
2168         lock_ObtainMutex(&dsp->mx);
2169         if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2170             if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2171                 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2172             osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2173             lock_ReleaseMutex(&dsp->mx);
2174             lock_FinalizeMutex(&dsp->mx);
2175             scp = dsp->scp;
2176             osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p", 
2177                      dsp->cookie, dsp, scp);
2178             free(dsp);
2179         } else {
2180             lock_ReleaseMutex(&dsp->mx);
2181         }
2182     }
2183     /* do this now to avoid spurious locking hierarchy creation */
2184     if (scp) 
2185         cm_ReleaseSCache(scp);
2186 }       
2187
2188 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2189 {
2190     lock_ObtainWrite(&smb_globalLock);
2191     smb_ReleaseDirSearchNoLock(dsp);
2192     lock_ReleaseWrite(&smb_globalLock);
2193 }       
2194
2195 /* find a dir search structure by cookie value, and return it held */
2196 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2197 {
2198     smb_dirSearch_t *dsp;
2199
2200     lock_ObtainWrite(&smb_globalLock);
2201     dsp = smb_FindDirSearchNoLock(cookie);
2202     lock_ReleaseWrite(&smb_globalLock);
2203     return dsp;
2204 }
2205
2206 /* GC some dir search entries, in the address space expected by the specific protocol.
2207  * Must be called with smb_globalLock held; release the lock temporarily.
2208  */
2209 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
2210 void smb_GCDirSearches(int isV3)
2211 {
2212     smb_dirSearch_t *prevp;
2213     smb_dirSearch_t *dsp;
2214     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2215     int victimCount;
2216     int i;
2217         
2218     victimCount = 0;    /* how many have we got so far */
2219     for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2220         /* we'll move tp from queue, so
2221          * do this early.
2222          */
2223         prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q); 
2224         /* if no one is using this guy, and we're either in the new protocol,
2225          * or we're in the old one and this is a small enough ID to be useful
2226          * to the old protocol, GC this guy.
2227          */
2228         if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2229             /* hold and delete */
2230             lock_ObtainMutex(&dsp->mx);
2231             dsp->flags |= SMB_DIRSEARCH_DELETE;
2232             lock_ReleaseMutex(&dsp->mx);
2233             victimsp[victimCount++] = dsp;
2234             dsp->refCount++;
2235         }
2236
2237         /* don't do more than this */
2238         if (victimCount >= SMB_DIRSEARCH_GCMAX) 
2239             break;
2240     }
2241         
2242     /* now release them */
2243     for (i = 0; i < victimCount; i++) {
2244         smb_ReleaseDirSearchNoLock(victimsp[i]);
2245     }
2246 }
2247
2248 /* function for allocating a dir search entry.  We need these to remember enough context
2249  * since we don't get passed the path from call to call during a directory search.
2250  *
2251  * Returns a held dir search structure, and bumps the reference count on the vnode,
2252  * since it saves a pointer to the vnode.
2253  */
2254 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2255 {
2256     smb_dirSearch_t *dsp;
2257     int counter;
2258     int maxAllowed;
2259     int start;
2260     int wrapped = 0;
2261
2262     lock_ObtainWrite(&smb_globalLock);
2263     counter = 0;
2264
2265     /* what's the biggest ID allowed in this version of the protocol */
2266     /* TODO: do we really want a non v3 dir search request to wrap
2267        smb_dirSearchCounter? */
2268     maxAllowed = isV3 ? 65535 : 255;
2269     if (smb_dirSearchCounter > maxAllowed)
2270         smb_dirSearchCounter = 1;
2271
2272     start = smb_dirSearchCounter;
2273
2274     while (1) {
2275         /* twice so we have enough tries to find guys we GC after one pass;
2276          * 10 extra is just in case I mis-counted.
2277          */
2278         if (++counter > 2*maxAllowed+10) 
2279             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2280
2281         if (smb_dirSearchCounter > maxAllowed) {        
2282             smb_dirSearchCounter = 1;
2283         }
2284         if (smb_dirSearchCounter == start) {
2285             if (wrapped)
2286                 smb_GCDirSearches(isV3);
2287             wrapped++;
2288         }
2289         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2290         if (dsp) {
2291             /* don't need to watch for refcount zero and deleted, since
2292             * we haven't dropped the global lock.
2293             */
2294             dsp->refCount--;
2295             ++smb_dirSearchCounter;
2296             continue;
2297         }       
2298
2299         dsp = malloc(sizeof(*dsp));
2300         memset(dsp, 0, sizeof(*dsp));
2301         dsp->cookie = smb_dirSearchCounter;
2302         ++smb_dirSearchCounter;
2303         dsp->refCount = 1;
2304         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2305         dsp->lastTime = osi_Time();
2306         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2307         if (!smb_lastDirSearchp) 
2308             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2309     
2310         osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p", 
2311                  dsp->cookie, dsp);
2312         break;
2313     }   
2314     lock_ReleaseWrite(&smb_globalLock);
2315     return dsp;
2316 }
2317
2318 static smb_packet_t *smb_GetPacket(void)
2319 {
2320     smb_packet_t *tbp;
2321
2322     lock_ObtainWrite(&smb_globalLock);
2323     tbp = smb_packetFreeListp;
2324     if (tbp) 
2325         smb_packetFreeListp = tbp->nextp;
2326     lock_ReleaseWrite(&smb_globalLock);
2327     if (!tbp) {
2328         tbp = calloc(sizeof(*tbp),1);
2329         tbp->magic = SMB_PACKETMAGIC;
2330         tbp->ncbp = NULL;
2331         tbp->vcp = NULL;
2332         tbp->resumeCode = 0;
2333         tbp->inCount = 0;
2334         tbp->fid = 0;
2335         tbp->wctp = NULL;
2336         tbp->inCom = 0;
2337         tbp->oddByte = 0;
2338         tbp->ncb_length = 0;
2339         tbp->flags = 0;
2340         tbp->spacep = NULL;
2341         tbp->stringsp = NULL;
2342     }
2343     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2344
2345     return tbp;
2346 }
2347
2348 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2349 {
2350     smb_packet_t *tbp;
2351     tbp = smb_GetPacket();
2352     memcpy(tbp, pkt, sizeof(smb_packet_t));
2353     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2354     tbp->stringsp = NULL;
2355     if (tbp->vcp)
2356         smb_HoldVC(tbp->vcp);
2357     return tbp;
2358 }
2359
2360 static NCB *smb_GetNCB(void)
2361 {
2362     smb_ncb_t *tbp;
2363     NCB *ncbp;
2364
2365     lock_ObtainWrite(&smb_globalLock);
2366     tbp = smb_ncbFreeListp;
2367     if (tbp) 
2368         smb_ncbFreeListp = tbp->nextp;
2369     lock_ReleaseWrite(&smb_globalLock);
2370     if (!tbp) {
2371         tbp = calloc(sizeof(*tbp),1);
2372         tbp->magic = SMB_NCBMAGIC;
2373     }
2374         
2375     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2376
2377     memset(&tbp->ncb, 0, sizeof(NCB));
2378     ncbp = &tbp->ncb;
2379     return ncbp;
2380 }
2381
2382 static void FreeSMBStrings(smb_packet_t * pkt)
2383 {
2384     cm_space_t * s;
2385     cm_space_t * ns;
2386
2387     for (s = pkt->stringsp; s; s = ns) {
2388         ns = s->nextp;
2389         cm_FreeSpace(s);
2390     }
2391     pkt->stringsp = NULL;
2392 }
2393
2394 void smb_FreePacket(smb_packet_t *tbp)
2395 {
2396     smb_vc_t * vcp = NULL;
2397     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2398         
2399     lock_ObtainWrite(&smb_globalLock);
2400     tbp->nextp = smb_packetFreeListp;
2401     smb_packetFreeListp = tbp;
2402     tbp->magic = SMB_PACKETMAGIC;
2403     tbp->ncbp = NULL;
2404     vcp = tbp->vcp;
2405     tbp->vcp = NULL;
2406     tbp->resumeCode = 0;
2407     tbp->inCount = 0;
2408     tbp->fid = 0;
2409     tbp->wctp = NULL;
2410     tbp->inCom = 0;
2411     tbp->oddByte = 0;
2412     tbp->ncb_length = 0;
2413     tbp->flags = 0;
2414     FreeSMBStrings(tbp);
2415     lock_ReleaseWrite(&smb_globalLock);
2416
2417     if (vcp)
2418         smb_ReleaseVC(vcp);
2419 }
2420
2421 static void smb_FreeNCB(NCB *bufferp)
2422 {
2423     smb_ncb_t *tbp;
2424         
2425     tbp = (smb_ncb_t *) bufferp;
2426     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2427         
2428     lock_ObtainWrite(&smb_globalLock);
2429     tbp->nextp = smb_ncbFreeListp;
2430     smb_ncbFreeListp = tbp;
2431     lock_ReleaseWrite(&smb_globalLock);
2432 }
2433
2434 /* get a ptr to the data part of a packet, and its count */
2435 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2436 {
2437     int parmBytes;
2438     int dataBytes;
2439     unsigned char *afterParmsp;
2440
2441     parmBytes = *smbp->wctp << 1;
2442     afterParmsp = smbp->wctp + parmBytes + 1;
2443         
2444     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2445     if (nbytesp) *nbytesp = dataBytes;
2446         
2447     /* don't forget to skip the data byte count, since it follows
2448      * the parameters; that's where the "2" comes from below.
2449      */
2450     return (unsigned char *) (afterParmsp + 2);
2451 }
2452
2453 /* must set all the returned parameters before playing around with the
2454  * data region, since the data region is located past the end of the
2455  * variable number of parameters.
2456  */
2457 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2458 {
2459     unsigned char *afterParmsp;
2460
2461     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2462         
2463     *afterParmsp++ = dsize & 0xff;
2464     *afterParmsp = (dsize>>8) & 0xff;
2465 }       
2466
2467 /* return the parm'th parameter in the smbp packet */
2468 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2469 {
2470     int parmCount;
2471     unsigned char *parmDatap;
2472
2473     parmCount = *smbp->wctp;
2474
2475     if (parm >= parmCount) {
2476         char s[100];
2477
2478         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2479                 parm, parmCount, smbp->ncb_length);
2480         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2481                  parm, parmCount, smbp->ncb_length);
2482         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2483                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2484         osi_panic(s, __FILE__, __LINE__);
2485     }
2486     parmDatap = smbp->wctp + (2*parm) + 1;
2487         
2488     return parmDatap[0] + (parmDatap[1] << 8);
2489 }
2490
2491 /* return the parm'th parameter in the smbp packet */
2492 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2493 {
2494     int parmCount;
2495     unsigned char *parmDatap;
2496
2497     parmCount = *smbp->wctp;
2498
2499     if (parm >= parmCount) {
2500         char s[100];
2501
2502         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2503                 parm, parmCount, smbp->ncb_length);
2504         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2505                  parm, parmCount, smbp->ncb_length);
2506         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2507                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2508         osi_panic(s, __FILE__, __LINE__);
2509     }
2510     parmDatap = smbp->wctp + (2*parm) + 1;
2511         
2512     return parmDatap[0];
2513 }
2514
2515 /* return the parm'th parameter in the smbp packet */
2516 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2517 {
2518     int parmCount;
2519     unsigned char *parmDatap;
2520
2521     parmCount = *smbp->wctp;
2522
2523     if (parm + 1 >= parmCount) {
2524         char s[100];
2525
2526         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2527                 parm, parmCount, smbp->ncb_length);
2528         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2529                  parm, parmCount, smbp->ncb_length);
2530         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM, 
2531                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2532         osi_panic(s, __FILE__, __LINE__);
2533     }
2534     parmDatap = smbp->wctp + (2*parm) + 1;
2535         
2536     return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2537 }
2538
2539 /* return the parm'th parameter in the smbp packet */
2540 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2541 {
2542     int parmCount;
2543     unsigned char *parmDatap;
2544
2545     parmCount = *smbp->wctp;
2546
2547     if (parm * 2 + offset >= parmCount * 2) {
2548         char s[100];
2549
2550         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2551                 parm, offset, parmCount, smbp->ncb_length);
2552         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET, 
2553                  __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2554         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2555                 parm, offset, parmCount, smbp->ncb_length);
2556         osi_panic(s, __FILE__, __LINE__);
2557     }
2558     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2559         
2560     return parmDatap[0] + (parmDatap[1] << 8);
2561 }
2562
2563 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2564 {
2565     unsigned char *parmDatap;
2566
2567     /* make sure we have enough slots */
2568     if (*smbp->wctp <= slot) 
2569         *smbp->wctp = slot+1;
2570         
2571     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2572     *parmDatap++ = parmValue & 0xff;
2573     *parmDatap = (parmValue>>8) & 0xff;
2574 }       
2575
2576 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2577 {
2578     unsigned char *parmDatap;
2579
2580     /* make sure we have enough slots */
2581     if (*smbp->wctp <= slot) 
2582         *smbp->wctp = slot+2;
2583
2584     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2585     *parmDatap++ = parmValue & 0xff;
2586     *parmDatap++ = (parmValue>>8) & 0xff;
2587     *parmDatap++ = (parmValue>>16) & 0xff;
2588     *parmDatap   = (parmValue>>24) & 0xff;
2589 }
2590
2591 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2592 {
2593     unsigned char *parmDatap;
2594     int i;
2595
2596     /* make sure we have enough slots */
2597     if (*smbp->wctp <= slot) 
2598         *smbp->wctp = slot+4;
2599
2600     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2601     for (i=0; i<8; i++)
2602         *parmDatap++ = *parmValuep++;
2603 }       
2604
2605 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2606 {
2607     unsigned char *parmDatap;
2608
2609     /* make sure we have enough slots */
2610     if (*smbp->wctp <= slot) {
2611         if (smbp->oddByte) {
2612             smbp->oddByte = 0;
2613             *smbp->wctp = slot+1;
2614         } else
2615             smbp->oddByte = 1;
2616     }
2617
2618     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2619     *parmDatap++ = parmValue & 0xff;
2620 }
2621
2622
2623
2624 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2625                             clientchar_t *inPathp)
2626 {
2627     clientchar_t *lastSlashp;
2628     clientchar_t *streamp = NULL;
2629     clientchar_t *typep = NULL;
2630
2631     lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2632     if (lastComponentp) {
2633         *lastComponentp = lastSlashp;
2634     }
2635     if (lastSlashp) {
2636         /*
2637          * If the name contains a stream name and a type
2638          * and the stream name is the nul-string and the
2639          * type is $DATA, then strip "::$DATA" from the
2640          * last component string that is returned.
2641          *
2642          * Otherwise, return the full path name and allow
2643          * the file name to be rejected because it contains
2644          * a colon.
2645          */
2646         typep = cm_ClientStrRChr(lastSlashp, L':');
2647         if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2648             *typep = '\0';
2649             streamp = cm_ClientStrRChr(lastSlashp, L':');
2650             if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2651                 *streamp = '\0';
2652             } else
2653                 *typep = ':';
2654             osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2655                      osi_LogSaveClientString(smb_logp,streamp),
2656                      osi_LogSaveClientString(smb_logp,typep));
2657         }
2658
2659         while (1) {
2660             if (inPathp == lastSlashp) 
2661                 break;
2662             *outPathp++ = *inPathp++;
2663         }
2664         *outPathp++ = 0;
2665     }
2666     else {
2667         *outPathp++ = 0;
2668     }
2669 }
2670
2671 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2672                                   char **chainpp, int flags)
2673 {
2674     size_t cb;
2675     afs_uint32 type = *inp++;
2676
2677     /* 
2678      * The first byte specifies the type of the input string.
2679      * CIFS TR 1.0 3.2.10.  This function only parses null terminated
2680      * strings.
2681      */
2682     switch (type) {
2683     /* Length Counted */
2684     case 0x1: /* Data Block */
2685     case 0x5: /* Variable Block */
2686         cb = *inp++ << 16 | *inp++;
2687         break;
2688
2689     /* Null-terminated string */
2690     case 0x4: /* ASCII */
2691     case 0x3: /* Pathname */
2692     case 0x2: /* Dialect */
2693         cb = sizeof(pktp->data) - (inp - pktp->data);
2694         if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2695 #ifdef DEBUG_UNICODE
2696             DebugBreak();
2697 #endif
2698             cb = sizeof(pktp->data);
2699         }
2700         break;
2701
2702     default:
2703         return NULL;            /* invalid input */
2704     }
2705
2706 #ifdef SMB_UNICODE
2707     if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2708         flags |= SMB_STRF_FORCEASCII;
2709 #endif
2710
2711     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2712 }
2713
2714 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2715                               char ** chainpp, int flags)
2716 {
2717     size_t cb;
2718
2719 #ifdef SMB_UNICODE
2720     if (!WANTS_UNICODE(pktp))
2721         flags |= SMB_STRF_FORCEASCII;
2722 #endif
2723
2724     cb = sizeof(pktp->data) - (inp - pktp->data);
2725     if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2726 #ifdef DEBUG_UNICODE
2727         DebugBreak();
2728 #endif
2729         cb = sizeof(pktp->data);
2730     }
2731     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2732                               flags | SMB_STRF_SRCNULTERM);
2733 }
2734
2735 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2736                                 size_t cb, char ** chainpp, int flags)
2737 {
2738 #ifdef SMB_UNICODE
2739     if (!WANTS_UNICODE(pktp))
2740         flags |= SMB_STRF_FORCEASCII;
2741 #endif
2742
2743     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2744 }
2745
2746 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2747                                  size_t cch, char ** chainpp, int flags)
2748 {
2749     size_t cb = cch;
2750
2751 #ifdef SMB_UNICODE
2752     if (!WANTS_UNICODE(pktp))
2753         flags |= SMB_STRF_FORCEASCII;
2754     else
2755         cb = cch * sizeof(wchar_t);
2756 #endif
2757
2758     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2759 }
2760
2761 clientchar_t *
2762 smb_ParseStringBuf(const unsigned char * bufbase,
2763                    cm_space_t ** stringspp,
2764                    unsigned char *inp, size_t *pcb_max,
2765                    char **chainpp, int flags)
2766 {
2767 #ifdef SMB_UNICODE
2768     if (!(flags & SMB_STRF_FORCEASCII)) {
2769         size_t cch_src;
2770         cm_space_t * spacep;
2771         int    null_terms = 0;
2772
2773         if (bufbase && ((inp - bufbase) % 2) != 0) {
2774             inp++;              /* unicode strings are always word aligned */
2775         }
2776
2777         if (*pcb_max > 0) {
2778             if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2779                                         &cch_src))) {
2780                 cch_src = *pcb_max / sizeof(wchar_t);
2781                 *pcb_max = 0;
2782                 null_terms = 0;
2783             } else {
2784                 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2785                 null_terms = 1;
2786             }
2787         } else {
2788             cch_src = 0;
2789         }
2790
2791         spacep = cm_GetSpace();
2792         spacep->nextp = *stringspp;
2793         *stringspp = spacep;
2794
2795         if (cch_src == 0) {
2796             if (chainpp) {
2797                 *chainpp = inp + sizeof(wchar_t);
2798             }
2799
2800             *(spacep->wdata) = 0;
2801             return spacep->wdata;
2802         }
2803
2804         StringCchCopyNW(spacep->wdata,
2805                         lengthof(spacep->wdata),
2806                         (const clientchar_t *) inp, cch_src);
2807
2808         if (chainpp)
2809             *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2810
2811         return spacep->wdata;
2812
2813     } else {
2814 #endif
2815         cm_space_t * spacep;
2816         int cchdest;
2817
2818         /* Not using Unicode */
2819         if (chainpp) {
2820             *chainpp = inp + strlen(inp) + 1;
2821         }
2822
2823         spacep = cm_GetSpace();
2824         spacep->nextp = *stringspp;
2825         *stringspp = spacep;
2826
2827         cchdest = lengthof(spacep->wdata);
2828         cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2829                        spacep->wdata, cchdest);
2830
2831         return spacep->wdata;
2832 #ifdef SMB_UNICODE
2833     }
2834 #endif
2835 }
2836
2837 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2838                             clientchar_t * str,
2839                             size_t * plen, int flags)
2840 {
2841     size_t buffersize;
2842     int align = 0;
2843
2844     if (outp == NULL) {
2845         /* we are only calculating the required size */
2846
2847         if (plen == NULL)
2848             return NULL;
2849
2850 #ifdef SMB_UNICODE
2851
2852         if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2853
2854             StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2855             if (!(flags & SMB_STRF_IGNORENUL))
2856                 *plen += sizeof(wchar_t);
2857
2858             return (unsigned char *) 1; /* return TRUE if we are using unicode */
2859         }
2860         else
2861 #endif
2862         {
2863             /* Storing ANSI */
2864
2865             size_t cch_str;
2866             size_t cch_dest;
2867
2868             cch_str = cm_ClientStrLen(str);
2869             cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2870
2871             if (plen)
2872                 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2873
2874             return NULL;
2875         }
2876
2877         /* Not reached. */
2878     }
2879
2880     /* if outp != NULL ... */
2881
2882     /* Number of bytes left in the buffer.
2883
2884        If outp lies inside the packet data buffer, we assume that the
2885        buffer is the packet data buffer.  Otherwise we assume that the
2886        buffer is sizeof(packet->data).
2887
2888     */
2889     if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2890         align = (int)((outp - pktp->data) % 2);
2891         buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2892     } else {
2893         align = (int)(((size_t) outp) % 2);
2894         buffersize = (int)sizeof(pktp->data);
2895     }
2896
2897 #ifdef SMB_UNICODE
2898
2899     if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2900         int nchars;
2901
2902         if (align)
2903             *outp++ = '\0';
2904
2905         if (*str == _C('\0')) {
2906
2907             if (buffersize < sizeof(wchar_t))
2908                 return NULL;
2909
2910             *((wchar_t *) outp) = L'\0';
2911             if (plen && !(flags & SMB_STRF_IGNORENUL))
2912                 *plen += sizeof(wchar_t);
2913             return outp + sizeof(wchar_t);
2914         }
2915
2916         nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2917         if (nchars == 0) {
2918             osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2919                      osi_LogSaveClientString(smb_logp, str),
2920                      GetLastError());
2921             return NULL;
2922         }
2923
2924         if (plen)
2925             *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2926
2927         return outp + sizeof(wchar_t) * nchars;
2928     }
2929     else
2930 #endif
2931     {
2932         /* Storing ANSI */
2933         size_t cch_dest;
2934
2935         cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2936
2937         if (plen)
2938             *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2939
2940         return outp + cch_dest;
2941     }
2942 }
2943
2944 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2945 {
2946     int tlen;
2947
2948     if (*inp++ != 0x5) 
2949         return NULL;
2950     tlen = inp[0] + (inp[1]<<8);
2951     inp += 2;           /* skip length field */
2952
2953     if (chainpp) {
2954         *chainpp = inp + tlen;
2955     }
2956         
2957     if (lengthp) 
2958         *lengthp = tlen;
2959         
2960     return inp;
2961 }       
2962
2963 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2964 {
2965     int tlen;
2966
2967     if (*inp++ != 0x1) return NULL;
2968     tlen = inp[0] + (inp[1]<<8);
2969     inp += 2;           /* skip length field */
2970         
2971     if (chainpp) {
2972         *chainpp = inp + tlen;
2973     }   
2974
2975     if (lengthp) *lengthp = tlen;
2976         
2977     return inp;
2978 }
2979
2980 /* format a packet as a response */
2981 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2982 {
2983     smb_t *outp;
2984     smb_t *inSmbp;
2985
2986     outp = (smb_t *) op;
2987         
2988     /* zero the basic structure through the smb_wct field, and zero the data
2989      * size field, assuming that wct stays zero; otherwise, you have to 
2990      * explicitly set the data size field, too.
2991      */
2992     inSmbp = (smb_t *) inp;
2993     memset(outp, 0, sizeof(smb_t)+2);
2994     outp->id[0] = 0xff;
2995     outp->id[1] = 'S';
2996     outp->id[2] = 'M';
2997     outp->id[3] = 'B';
2998     if (inp) {
2999         outp->com = inSmbp->com;
3000         outp->tid = inSmbp->tid;
3001         outp->pid = inSmbp->pid;
3002         outp->uid = inSmbp->uid;
3003         outp->mid = inSmbp->mid;
3004         outp->res[0] = inSmbp->res[0];
3005         outp->res[1] = inSmbp->res[1];
3006         op->inCom = inSmbp->com;
3007     }
3008     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3009 #ifdef SEND_CANONICAL_PATHNAMES
3010     outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3011 #endif
3012     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3013 #ifdef SMB_UNICODE
3014     if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3015         outp->flg2 |= SMB_FLAGS2_UNICODE;
3016 #endif
3017
3018     /* copy fields in generic packet area */
3019     op->wctp = &outp->wct;
3020 }       
3021
3022 /* send a (probably response) packet; vcp tells us to whom to send it.
3023  * we compute the length by looking at wct and bcc fields.
3024  */
3025 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3026 {
3027     NCB *ncbp;
3028     int extra;
3029     long code = 0;
3030     unsigned char *tp;
3031     int localNCB = 0;
3032         
3033     ncbp = inp->ncbp;
3034     if (ncbp == NULL) {
3035         ncbp = smb_GetNCB();
3036         localNCB = 1;
3037     }
3038  
3039     memset(ncbp, 0, sizeof(NCB));
3040
3041     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
3042     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
3043     extra += tp[0] + (tp[1]<<8);
3044     extra += (unsigned int)(inp->wctp - inp->data);     /* distance to last wct field */
3045     extra += 3;                 /* wct and length fields */
3046         
3047     ncbp->ncb_length = extra;   /* bytes to send */
3048     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
3049     ncbp->ncb_lana_num = vcp->lana;
3050     ncbp->ncb_command = NCBSEND;        /* op means send data */
3051     ncbp->ncb_buffer = (char *) inp;/* packet */
3052     code = Netbios(ncbp);
3053         
3054     if (code != 0) {
3055         const char * s = ncb_error_string(code);
3056         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3057         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3058
3059         lock_ObtainMutex(&vcp->mx);
3060         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3061             osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3062                       vcp, vcp->usersp);
3063             vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3064             lock_ReleaseMutex(&vcp->mx);
3065             lock_ObtainWrite(&smb_globalLock);
3066             dead_sessions[vcp->session] = TRUE;
3067             lock_ReleaseWrite(&smb_globalLock);
3068             smb_CleanupDeadVC(vcp);
3069         } else {
3070             lock_ReleaseMutex(&vcp->mx);
3071         }
3072     }
3073
3074     if (localNCB)
3075         smb_FreeNCB(ncbp);
3076 }
3077
3078 void smb_MapNTError(long code, unsigned long *NTStatusp)
3079 {
3080     unsigned long NTStatus;
3081
3082     /* map CM_ERROR_* errors to NT 32-bit status codes */
3083     /* NT Status codes are listed in ntstatus.h not winerror.h */
3084     if (code == 0) {
3085         NTStatus = 0;
3086     } 
3087     else if (code == CM_ERROR_NOSUCHCELL) {
3088         NTStatus = 0xC0000034L; /* Name not found */
3089     }
3090     else if (code == CM_ERROR_NOSUCHVOLUME) {
3091         NTStatus = 0xC0000034L; /* Name not found */
3092     }
3093     else if (code == CM_ERROR_TIMEDOUT) {
3094 #ifdef COMMENT
3095         NTStatus = 0xC00000CFL; /* Sharing Paused */
3096
3097         /* Do not send Timeout to the SMB redirector.
3098          * It causes the redirector to drop the connection */
3099         NTStatus = 0x00000102L; /* Timeout */
3100         /* do not send Retry to the SMB redirector.
3101          * It believes the error comes from the transport
3102          * layer not from the SMB server. */
3103         NTStatus = 0xC000022DL; /* Retry */
3104 #else
3105         NTStatus = 0xC00000B5L; /* I/O Timeout */
3106 #endif
3107     }
3108     else if (code == CM_ERROR_RETRY) {
3109 #ifdef COMMENT
3110         NTStatus = 0xC000022DL; /* Retry */
3111 #else
3112         NTStatus = 0xC00000B5L; /* I/O Timeout */
3113 #endif
3114     }
3115     else if (code == CM_ERROR_NOACCESS) {
3116         NTStatus = 0xC0000022L; /* Access denied */
3117     }
3118     else if (code == CM_ERROR_READONLY) {
3119         NTStatus = 0xC00000A2L; /* Write protected */
3120     }
3121     else if (code == CM_ERROR_NOSUCHFILE ||
3122              code == CM_ERROR_BPLUS_NOMATCH) {
3123         NTStatus = 0xC0000034L; /* Name not found */
3124     }
3125     else if (code == CM_ERROR_NOSUCHPATH) {
3126         NTStatus = 0xC000003AL; /* Object path not found */
3127     }           
3128     else if (code == CM_ERROR_TOOBIG) {
3129         NTStatus = 0xC000007BL; /* Invalid image format */
3130     }
3131     else if (code == CM_ERROR_INVAL) {
3132         NTStatus = 0xC000000DL; /* Invalid parameter */
3133     }
3134     else if (code == CM_ERROR_BADFD) {
3135         NTStatus = 0xC0000008L; /* Invalid handle */
3136     }
3137     else if (code == CM_ERROR_BADFDOP) {
3138         NTStatus = 0xC0000022L; /* Access denied */
3139     }
3140     else if (code == CM_ERROR_UNKNOWN) {
3141         NTStatus = 0xC0000022L; /* Access denied */
3142     }
3143     else if (code == CM_ERROR_EXISTS) {
3144         NTStatus = 0xC0000035L; /* Object name collision */
3145     }
3146     else if (code == CM_ERROR_NOTEMPTY) {
3147         NTStatus = 0xC0000101L; /* Directory not empty */
3148     }   
3149     else if (code == CM_ERROR_CROSSDEVLINK) {
3150         NTStatus = 0xC00000D4L; /* Not same device */
3151     }
3152     else if (code == CM_ERROR_NOTDIR) {
3153         NTStatus = 0xC0000103L; /* Not a directory */
3154     }
3155     else if (code == CM_ERROR_ISDIR) {
3156         NTStatus = 0xC00000BAL; /* File is a directory */
3157     }
3158     else if (code == CM_ERROR_BADOP) {
3159 #ifdef COMMENT
3160         /* I have no idea where this comes from */
3161         NTStatus = 0xC09820FFL; /* SMB no support */
3162 #else
3163         NTStatus = 0xC00000BBL;     /* Not supported */
3164 #endif /* COMMENT */
3165     }
3166     else if (code == CM_ERROR_BADSHARENAME) {
3167         NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3168     }
3169     else if (code == CM_ERROR_NOIPC) {
3170 #ifdef COMMENT
3171         NTStatus = 0xC0000022L; /* Access Denied */
3172 #else   
3173         NTStatus = 0xC000013DL; /* Remote Resources */
3174 #endif
3175     }
3176     else if (code == CM_ERROR_CLOCKSKEW ||
3177              code == RXKADNOAUTH) {
3178         NTStatus = 0xC0000133L; /* Time difference at DC */
3179     }
3180     else if (code == CM_ERROR_BADTID) {
3181         NTStatus = 0xC0982005L; /* SMB bad TID */
3182     }
3183     else if (code == CM_ERROR_USESTD) {
3184         NTStatus = 0xC09820FBL; /* SMB use standard */
3185     }
3186     else if (code == CM_ERROR_QUOTA) {
3187         NTStatus = 0xC0000044L; /* Quota exceeded */
3188     }
3189     else if (code == CM_ERROR_SPACE) {
3190         NTStatus = 0xC000007FL; /* Disk full */
3191     }
3192     else if (code == CM_ERROR_ATSYS) {
3193         NTStatus = 0xC0000033L; /* Object name invalid */
3194     }
3195     else if (code == CM_ERROR_BADNTFILENAME) {
3196         NTStatus = 0xC0000033L; /* Object name invalid */
3197     }
3198     else if (code == CM_ERROR_WOULDBLOCK) {
3199         NTStatus = 0xC00000D8L; /* Can't wait */
3200     }
3201     else if (code == CM_ERROR_SHARING_VIOLATION) {
3202         NTStatus = 0xC0000043L; /* Sharing violation */
3203     }
3204     else if (code == CM_ERROR_LOCK_CONFLICT) {
3205         NTStatus = 0xC0000054L; /* Lock conflict */
3206     }
3207     else if (code == CM_ERROR_PARTIALWRITE) {
3208         NTStatus = 0xC000007FL; /* Disk full */
3209     }
3210     else if (code == CM_ERROR_BUFFERTOOSMALL) {
3211         NTStatus = 0xC0000023L; /* Buffer too small */
3212     }
3213     else if (code == CM_ERROR_BUFFER_OVERFLOW) {
3214         NTStatus = 0x80000005L; /* Buffer overflow */
3215     }
3216     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3217         NTStatus = 0xC0000035L; /* Object name collision */
3218     }   
3219     else if (code == CM_ERROR_BADPASSWORD) {
3220         NTStatus = 0xC000006DL; /* unknown username or bad password */
3221     }
3222     else if (code == CM_ERROR_BADLOGONTYPE) {
3223         NTStatus = 0xC000015BL; /* logon type not granted */
3224     }
3225     else if (code == CM_ERROR_GSSCONTINUE) {
3226         NTStatus = 0xC0000016L; /* more processing required */
3227     }
3228     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3229 #ifdef COMMENT
3230         NTStatus = 0xC0000280L; /* reparse point not resolved */
3231 #else
3232         NTStatus = 0xC0000022L; /* Access Denied */
3233 #endif
3234     }
3235     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3236         NTStatus = 0xC0000257L; /* Path Not Covered */
3237     } 
3238     else if (code == CM_ERROR_ALLBUSY) {
3239 #ifdef COMMENT
3240         NTStatus = 0xC000022DL; /* Retry */
3241 #else
3242         NTStatus = 0xC0020018L; /* RPC_NT_SERVER_TOO_BUSY */
3243 #endif
3244     }
3245     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3246 #ifdef COMMENT
3247         NTStatus = 0xC000003AL; /* Path not found */
3248 #else
3249         NTStatus = 0xC0020017L; /* RPC_NT_SERVER_UNAVAILABLE */
3250 #endif
3251     }
3252     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3253         NTStatus = 0xC0000322L; /* No Kerberos key */
3254     } 
3255     else if (code == CM_ERROR_BAD_LEVEL) {
3256         NTStatus = 0xC0000148L; /* Invalid Level */
3257     } 
3258     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3259         NTStatus = 0xC000007EL; /* Range Not Locked */
3260     } 
3261     else if (code == CM_ERROR_NOSUCHDEVICE) {
3262         NTStatus = 0xC000000EL; /* No Such Device */
3263     }
3264     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3265         NTStatus = 0xC0000055L; /* Lock Not Granted */
3266     }
3267     else if (code == ENOMEM) {
3268         NTStatus = 0xC0000017L; /* Out of Memory */
3269     }
3270     else if (code == CM_ERROR_RPC_MOREDATA) {
3271         NTStatus = 0x80000005L; /* Buffer overflow */
3272     }
3273     else  {
3274         NTStatus = 0xC0982001L; /* SMB non-specific error */
3275     }
3276
3277     *NTStatusp = NTStatus;
3278     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3279 }       
3280
3281 /* 
3282  * NTSTATUS <-> Win32 Error Translation 
3283  * http://support.microsoft.com/kb/113996 
3284  */
3285 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3286 {
3287     unsigned long Win32E;
3288
3289     /* map CM_ERROR_* errors to Win32 32-bit error codes */
3290     if (code == 0) {
3291         Win32E = 0;
3292     } 
3293     else if (code == CM_ERROR_NOSUCHCELL) {
3294         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3295     }
3296     else if (code == CM_ERROR_NOSUCHVOLUME) {
3297         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3298     }
3299     else if (code == CM_ERROR_TIMEDOUT) {
3300 #ifdef COMMENT
3301         Win32E = ERROR_SHARING_PAUSED;  /* Sharing Paused */
3302 #else
3303         Win32E = ERROR_UNEXP_NET_ERR;   /* Timeout */
3304 #endif
3305     }
3306     else if (code == CM_ERROR_RETRY) {
3307         Win32E = ERROR_RETRY;           /* Retry */
3308     }
3309     else if (code == CM_ERROR_NOACCESS) {
3310         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3311     }
3312     else if (code == CM_ERROR_READONLY) {
3313         Win32E = ERROR_WRITE_PROTECT;   /* Write protected */
3314     }
3315     else if (code == CM_ERROR_NOSUCHFILE ||
3316              code == CM_ERROR_BPLUS_NOMATCH) {
3317         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3318     }
3319     else if (code == CM_ERROR_NOSUCHPATH) {
3320         Win32E = ERROR_PATH_NOT_FOUND;  /* Object path not found */
3321     }           
3322     else if (code == CM_ERROR_TOOBIG) {
3323         Win32E = ERROR_BAD_EXE_FORMAT;  /* Invalid image format */
3324     }
3325     else if (code == CM_ERROR_INVAL) {
3326         Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3327     }
3328     else if (code == CM_ERROR_BADFD) {
3329         Win32E = ERROR_INVALID_HANDLE;  /* Invalid handle */
3330     }
3331     else if (code == CM_ERROR_BADFDOP) {
3332         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3333     }
3334     else if (code == CM_ERROR_UNKNOWN) {
3335         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3336     }
3337     else if (code == CM_ERROR_EXISTS) {
3338         Win32E = ERROR_ALREADY_EXISTS;  /* Object name collision */
3339     }
3340     else if (code == CM_ERROR_NOTEMPTY) {
3341         Win32E = ERROR_DIR_NOT_EMPTY;   /* Directory not empty */
3342     }   
3343     else if (code == CM_ERROR_CROSSDEVLINK) {
3344         Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3345     }
3346     else if (code == CM_ERROR_NOTDIR) {
3347         Win32E = ERROR_DIRECTORY;       /* Not a directory */
3348     }
3349     else if (code == CM_ERROR_ISDIR) {
3350         Win32E = ERROR_ACCESS_DENIED;   /* File is a directory */
3351     }
3352     else if (code == CM_ERROR_BADOP) {
3353         Win32E = ERROR_NOT_SUPPORTED;   /* Not supported */
3354     }
3355     else if (code == CM_ERROR_BADSHARENAME) {
3356         Win32E = ERROR_BAD_NETPATH;     /* Bad network path (server valid, share bad) */
3357     }
3358     else if (code == CM_ERROR_NOIPC) {
3359 #ifdef COMMENT
3360         Win32E = ERROR_ACCESS_DENIED;   /* Access Denied */
3361 #else   
3362         Win32E = ERROR_REM_NOT_LIST;    /* Remote Resources */
3363 #endif
3364     }
3365     else if (code == CM_ERROR_CLOCKSKEW ||
3366              code == RXKADNOAUTH) {
3367         Win32E = ERROR_TIME_SKEW;       /* Time difference at DC */
3368     }
3369     else if (code == CM_ERROR_BADTID) {
3370         Win32E = ERROR_FILE_NOT_FOUND;  /* SMB bad TID */
3371     }
3372     else if (code == CM_ERROR_USESTD) {
3373         Win32E = ERROR_ACCESS_DENIED;   /* SMB use standard */
3374     }
3375     else if (code == CM_ERROR_QUOTA) {
3376         Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3377     }
3378     else if (code == CM_ERROR_SPACE) {
3379         Win32E = ERROR_DISK_FULL;       /* Disk full */
3380     }
3381     else if (code == CM_ERROR_ATSYS) {
3382         Win32E = ERROR_INVALID_NAME;    /* Object name invalid */
3383     }
3384     else if (code == CM_ERROR_BADNTFILENAME) {
3385         Win32E = ERROR_INVALID_NAME;    /* Object name invalid */
3386     }
3387     else if (code == CM_ERROR_WOULDBLOCK) {
3388         Win32E = WAIT_TIMEOUT;          /* Can't wait */
3389     }
3390     else if (code == CM_ERROR_SHARING_VIOLATION) {
3391         Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3392     }
3393     else if (code == CM_ERROR_LOCK_CONFLICT) {
3394         Win32E = ERROR_LOCK_VIOLATION;   /* Lock conflict */
3395     }
3396     else if (code == CM_ERROR_PARTIALWRITE) {
3397         Win32E = ERROR_DISK_FULL;       /* Disk full */
3398     }
3399     else if (code == CM_ERROR_BUFFERTOOSMALL) {
3400         Win32E = ERROR_INSUFFICIENT_BUFFER;     /* Buffer too small */
3401     }
3402     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3403         Win32E = ERROR_ALREADY_EXISTS;  /* Object name collision */
3404     }   
3405     else if (code == CM_ERROR_BADPASSWORD) {
3406         Win32E = ERROR_LOGON_FAILURE;   /* unknown username or bad password */
3407     }
3408     else if (code == CM_ERROR_BADLOGONTYPE) {
3409         Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3410     }
3411     else if (code == CM_ERROR_GSSCONTINUE) {
3412         Win32E = ERROR_MORE_DATA;       /* more processing required */
3413     }
3414     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3415 #ifdef COMMENT
3416         Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3417 #else
3418         Win32E = ERROR_ACCESS_DENIED;   /* Access Denied */
3419 #endif
3420     }
3421     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3422         Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3423     } 
3424     else if (code == CM_ERROR_ALLBUSY) {
3425         Win32E = ERROR_RETRY;           /* Retry */
3426     } 
3427     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3428         Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3429     } 
3430     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3431         Win32E = SEC_E_NO_KERB_KEY;     /* No Kerberos key */
3432     } 
3433     else if (code == CM_ERROR_BAD_LEVEL) {
3434         Win32E = ERROR_INVALID_LEVEL;   /* Invalid Level */
3435     } 
3436     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3437         Win32E = ERROR_NOT_LOCKED;      /* Range Not Locked */
3438     } 
3439     else if (code == CM_ERROR_NOSUCHDEVICE) {
3440         Win32E = ERROR_FILE_NOT_FOUND;  /* No Such Device */
3441     }
3442     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3443         Win32E = ERROR_LOCK_VIOLATION;  /* Lock Not Granted */
3444     }
3445     else if (code == ENOMEM) {
3446         Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3447     }
3448     else if (code == CM_ERROR_RPC_MOREDATA) {
3449         Win32E = ERROR_MORE_DATA;       /* Buffer overflow */
3450     }
3451     else  {
3452         Win32E = ERROR_GEN_FAILURE;     /* SMB non-specific error */
3453     }
3454
3455     *Win32Ep = Win32E;
3456     osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3457 }       
3458
3459 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3460                       unsigned char *classp)
3461 {
3462     unsigned char class;
3463     unsigned short error;
3464
3465     /* map CM_ERROR_* errors to SMB errors */
3466     if (code == CM_ERROR_NOSUCHCELL) {
3467         class = 1;
3468         error = 3;      /* bad path */
3469     }
3470     else if (code == CM_ERROR_NOSUCHVOLUME) {
3471         class = 1;
3472         error = 3;      /* bad path */
3473     }
3474     else if (code == CM_ERROR_TIMEDOUT) {
3475         class = 2;
3476         error = 81;     /* server is paused */
3477     }
3478     else if (code == CM_ERROR_RETRY) {
3479         class = 2;      /* shouldn't happen */
3480         error = 1;
3481     }
3482     else if (code == CM_ERROR_NOACCESS) {
3483         class = 2;
3484         error = 4;      /* bad access */
3485     }
3486     else if (code == CM_ERROR_READONLY) {
3487         class = 3;
3488         error = 19;     /* read only */
3489     }
3490     else if (code == CM_ERROR_NOSUCHFILE ||
3491              code == CM_ERROR_BPLUS_NOMATCH) {
3492         class = 1;
3493         error = 2;      /* ENOENT! */
3494     }
3495     else if (code == CM_ERROR_NOSUCHPATH) {
3496         class = 1;
3497         error = 3;      /* Bad path */
3498     }
3499     else if (code == CM_ERROR_TOOBIG) {
3500         class = 1;
3501         error = 11;     /* bad format */
3502     }
3503     else if (code == CM_ERROR_INVAL) {
3504         class = 2;      /* server non-specific error code */
3505         error = 1;
3506     }
3507     else if (code == CM_ERROR_BADFD) {
3508         class = 1;
3509         error = 6;      /* invalid file handle */
3510     }
3511     else if (code == CM_ERROR_BADFDOP) {
3512         class = 1;      /* invalid op on FD */
3513         error = 5;
3514     }
3515     else if (code == CM_ERROR_EXISTS) {
3516         class = 1;
3517         error = 80;     /* file already exists */
3518     }
3519     else if (code == CM_ERROR_NOTEMPTY) {
3520         class = 1;
3521         error = 5;      /* delete directory not empty */
3522     }
3523     else if (code == CM_ERROR_CROSSDEVLINK) {
3524         class = 1;
3525         error = 17;     /* EXDEV */
3526     }
3527     else if (code == CM_ERROR_NOTDIR) {
3528         class = 1;      /* bad path */
3529         error = 3;
3530     }
3531     else if (code == CM_ERROR_ISDIR) {
3532         class = 1;      /* access denied; DOS doesn't have a good match */
3533         error = 5;
3534     }       
3535     else if (code == CM_ERROR_BADOP) {
3536         class = 2;
3537         error = 65535;
3538     }
3539     else if (code == CM_ERROR_BADSHARENAME) {
3540         class = 2;
3541         error = 6;
3542     }
3543     else if (code == CM_ERROR_NOIPC) {
3544         class = 2;
3545         error = 4; /* bad access */
3546     }
3547     else if (code == CM_ERROR_CLOCKSKEW) {
3548         class = 1;      /* invalid function */
3549         error = 1;
3550     }
3551     else if (code == CM_ERROR_BADTID) {
3552         class = 2;
3553         error = 5;
3554     }
3555     else if (code == CM_ERROR_USESTD) {
3556         class = 2;
3557         error = 251;
3558     }
3559     else if (code == CM_ERROR_REMOTECONN) {
3560         class = 2;
3561         error = 82;
3562     }
3563     else if (code == CM_ERROR_QUOTA) {
3564         if (vcp->flags & SMB_VCFLAG_USEV3) {
3565             class = 3;
3566             error = 39; /* disk full */
3567         }
3568         else {
3569             class = 1;
3570             error = 5;  /* access denied */
3571         }
3572     }
3573     else if (code == CM_ERROR_SPACE) {
3574         if (vcp->flags & SMB_VCFLAG_USEV3) {
3575             class = 3;
3576             error = 39; /* disk full */
3577         }
3578         else {
3579             class = 1;
3580             error = 5;  /* access denied */
3581         }
3582     }
3583     else if (code == CM_ERROR_PARTIALWRITE) {
3584         class = 3;
3585         error = 39;     /* disk full */
3586     }
3587     else if (code == CM_ERROR_ATSYS) {
3588         class = 1;
3589         error = 2;      /* ENOENT */
3590     }
3591     else if (code == CM_ERROR_WOULDBLOCK) {
3592         class = 1;
3593         error = 33;     /* lock conflict */
3594     }
3595     else if (code == CM_ERROR_LOCK_CONFLICT) {
3596         class = 1;
3597         error = 33;     /* lock conflict */
3598     }
3599     else if (code == CM_ERROR_SHARING_VIOLATION) {
3600         class = 1;
3601         error = 33;     /* lock conflict */
3602     }
3603     else if (code == CM_ERROR_NOFILES) {
3604         class = 1;
3605         error = 18;     /* no files in search */
3606     }
3607     else if (code == CM_ERROR_RENAME_IDENTICAL) {
3608         class = 1;
3609         error = 183;     /* Samba uses this */
3610     }
3611     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3612         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3613         class = 2;
3614         error = 2; /* bad password */
3615     }
3616     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3617         class = 2;
3618         error = 3;     /* bad path */
3619     }
3620     else {
3621         class = 2;
3622         error = 1;
3623     }
3624
3625     *scodep = error;
3626     *classp = class;
3627     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3628 }       
3629
3630 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3631 {
3632     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3633     return CM_ERROR_BADOP;
3634 }
3635
3636 /* SMB_COM_ECHO */
3637 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3638 {
3639     unsigned short EchoCount, i;
3640     char *data, *outdata;
3641     int dataSize;
3642
3643     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3644
3645     for (i=1; i<=EchoCount; i++) {
3646         data = smb_GetSMBData(inp, &dataSize);
3647         smb_SetSMBParm(outp, 0, i);
3648         smb_SetSMBDataLength(outp, dataSize);
3649         outdata = smb_GetSMBData(outp, NULL);
3650         memcpy(outdata, data, dataSize);
3651         smb_SendPacket(vcp, outp);
3652     }
3653
3654     return 0;
3655 }
3656
3657 /* SMB_COM_READ_RAW */
3658 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3659 {
3660     osi_hyper_t offset;
3661     long count, minCount, finalCount;
3662     unsigned short fd;
3663     unsigned pid;
3664     smb_fid_t *fidp;
3665     smb_t *smbp = (smb_t*) inp;
3666     long code = 0;
3667     cm_user_t *userp = NULL;
3668     NCB *ncbp;
3669     int rc;
3670     char *rawBuf = NULL;
3671
3672     rawBuf = NULL;
3673     finalCount = 0;
3674
3675     fd = smb_GetSMBParm(inp, 0);
3676     count = smb_GetSMBParm(inp, 3);
3677     minCount = smb_GetSMBParm(inp, 4);
3678     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3679
3680     if (*inp->wctp == 10) {
3681         /* we were sent a request with 64-bit file offsets */
3682 #ifdef AFS_LARGEFILES
3683         offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3684
3685         if (LargeIntegerLessThanZero(offset)) {
3686             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3687             goto send1;
3688         }
3689 #else
3690         if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3691             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset.  Dropping request.");
3692             goto send1;
3693         } else {
3694             offset.HighPart = 0;
3695         }
3696 #endif
3697     } else {
3698         /* we were sent a request with 32-bit file offsets */
3699         offset.HighPart = 0;
3700     }
3701
3702     osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3703              fd, offset.HighPart, offset.LowPart, count);
3704
3705     fidp = smb_FindFID(vcp, fd, 0);
3706     if (!fidp) {
3707         osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3708                  vcp, fd);
3709         goto send1;
3710     }
3711     lock_ObtainMutex(&fidp->mx);
3712     if (!fidp->scp) {
3713         lock_ReleaseMutex(&fidp->mx);
3714         smb_ReleaseFID(fidp);
3715         return CM_ERROR_BADFD;
3716     }
3717
3718     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED)&nb