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