clang-10: use AFS_FALLTHROUGH for case fallthrough
[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) {
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, afs_uint32 redir)
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         if (redir)
3098             NTStatus = 0xC0020052L; /* RPC_NT_COMM_FAILURE */
3099         else {
3100 #ifdef COMMENT
3101             NTStatus = 0xC00000CFL;     /* Sharing Paused */
3102
3103             /* Do not send Timeout to the SMB redirector.
3104              * It causes the redirector to drop the connection */
3105             NTStatus = 0x00000102L; /* Timeout */
3106             /* do not send Retry to the SMB redirector.
3107              * It believes the error comes from the transport
3108              * layer not from the SMB server. */
3109             NTStatus = 0xC000022DL;     /* Retry */
3110 #else
3111             NTStatus = 0xC00000B5L;     /* I/O Timeout */
3112 #endif
3113         }
3114     }
3115     else if (code == CM_ERROR_RETRY) {
3116         if (redir)
3117             NTStatus = 0xC000022DL;     /* Retry */
3118         else {
3119 #ifdef COMMENT
3120             NTStatus = 0xC000022DL;     /* Retry */
3121 #else
3122             NTStatus = 0xC00000B5L; /* I/O Timeout */
3123 #endif
3124         }
3125     }
3126     else if (code == CM_ERROR_NOACCESS) {
3127         NTStatus = 0xC0000022L; /* Access denied */
3128     }
3129     else if (code == CM_ERROR_READONLY) {
3130         NTStatus = 0xC00000A2L; /* Write protected */
3131     }
3132     else if (code == CM_ERROR_NOSUCHFILE ||
3133              code == CM_ERROR_BPLUS_NOMATCH) {
3134         NTStatus = 0xC0000034L; /* Name not found */
3135     }
3136     else if (code == CM_ERROR_NOSUCHPATH) {
3137         NTStatus = 0xC000003AL; /* Object path not found */
3138     }
3139     else if (code == CM_ERROR_TOOBIG) {
3140         NTStatus = 0xC000007BL; /* Invalid image format */
3141     }
3142     else if (code == CM_ERROR_INVAL) {
3143         NTStatus = 0xC000000DL; /* Invalid parameter */
3144     }
3145     else if (code == CM_ERROR_INVAL_NET_RESP) {
3146         NTStatus = 0xC00000C3L; /* Invalid network response */
3147     }
3148     else if (code == CM_ERROR_BADFD) {
3149         NTStatus = 0xC0000008L; /* Invalid handle */
3150     }
3151     else if (code == CM_ERROR_BADFDOP) {
3152         NTStatus = 0xC0000022L; /* Access denied */
3153     }
3154     else if (code == CM_ERROR_UNKNOWN) {
3155         NTStatus = 0xC0000022L; /* Access denied */
3156     }
3157     else if (code == CM_ERROR_EXISTS) {
3158         NTStatus = 0xC0000035L; /* Object name collision */
3159     }
3160     else if (code == CM_ERROR_NOTEMPTY) {
3161         NTStatus = 0xC0000101L; /* Directory not empty */
3162     }
3163     else if (code == CM_ERROR_CROSSDEVLINK) {
3164         NTStatus = 0xC00000D4L; /* Not same device */
3165     }
3166     else if (code == CM_ERROR_NOTDIR) {
3167         NTStatus = 0xC0000103L; /* Not a directory */
3168     }
3169     else if (code == CM_ERROR_ISDIR) {
3170         NTStatus = 0xC00000BAL; /* File is a directory */
3171     }
3172     else if (code == CM_ERROR_BADOP) {
3173 #ifdef COMMENT
3174         /* I have no idea where this comes from */
3175         NTStatus = 0xC09820FFL; /* SMB no support */
3176 #else
3177         NTStatus = 0xC00000BBL;     /* Not supported */
3178 #endif /* COMMENT */
3179     }
3180     else if (code == CM_ERROR_BADSHARENAME) {
3181         NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3182     }
3183     else if (code == CM_ERROR_NOIPC) {
3184 #ifdef COMMENT
3185         NTStatus = 0xC0000022L; /* Access Denied */
3186 #else
3187         NTStatus = 0xC000013DL; /* Remote Resources */
3188 #endif
3189     }
3190     else if (code == CM_ERROR_CLOCKSKEW ||
3191              code == RXKADNOAUTH) {
3192         NTStatus = 0xC0000133L; /* Time difference at DC */
3193     }
3194     else if (code == CM_ERROR_BADTID) {
3195         NTStatus = 0xC0982005L; /* SMB bad TID */
3196     }
3197     else if (code == CM_ERROR_USESTD) {
3198         NTStatus = 0xC09820FBL; /* SMB use standard */
3199     }
3200     else if (code == CM_ERROR_QUOTA) {
3201         /*
3202          * AFS Redirector does not support Windows quota
3203          * interface.  Always report disk full instead.
3204          */
3205         if (redir)
3206             NTStatus = 0xC000007FL;     /* Disk full */
3207         else
3208             NTStatus = 0xC0000044L;     /* Quota exceeded */
3209     }
3210     else if (code == CM_ERROR_SPACE) {
3211         NTStatus = 0xC000007FL; /* Disk full */
3212     }
3213     else if (code == CM_ERROR_ATSYS) {
3214         NTStatus = 0xC0000033L; /* Object name invalid */
3215     }
3216     else if (code == CM_ERROR_BADNTFILENAME) {
3217         NTStatus = 0xC0000033L; /* Object name invalid */
3218     }
3219     else if (code == CM_ERROR_WOULDBLOCK) {
3220         NTStatus = 0xC00000D8L; /* Can't wait */
3221     }
3222     else if (code == CM_ERROR_SHARING_VIOLATION) {
3223         NTStatus = 0xC0000043L; /* Sharing violation */
3224     }
3225     else if (code == CM_ERROR_LOCK_CONFLICT) {
3226         NTStatus = 0xC0000054L; /* Lock conflict */
3227     }
3228     else if (code == CM_ERROR_PARTIALWRITE) {
3229         NTStatus = 0xC000007FL; /* Disk full */
3230     }
3231     else if (code == CM_ERROR_BUFFERTOOSMALL) {
3232         NTStatus = 0xC0000023L; /* Buffer too small */
3233     }
3234     else if (code == CM_ERROR_BUFFER_OVERFLOW) {
3235         NTStatus = 0x80000005L; /* Buffer overflow */
3236     }
3237     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3238         NTStatus = 0xC0000035L; /* Object name collision */
3239     }
3240     else if (code == CM_ERROR_BADPASSWORD) {
3241         NTStatus = 0xC000006DL; /* unknown username or bad password */
3242     }
3243     else if (code == CM_ERROR_BADLOGONTYPE) {
3244         NTStatus = 0xC000015BL; /* logon type not granted */
3245     }
3246     else if (code == CM_ERROR_GSSCONTINUE) {
3247         NTStatus = 0xC0000016L; /* more processing required */
3248     }
3249     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3250 #ifdef COMMENT
3251         NTStatus = 0xC0000280L; /* reparse point not resolved */
3252 #else
3253         NTStatus = 0xC0000022L; /* Access Denied */
3254 #endif
3255     }
3256     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3257         NTStatus = 0xC0000257L; /* Path Not Covered */
3258     }
3259     else if (code == CM_ERROR_ALLBUSY) {
3260 #ifdef COMMENT
3261         NTStatus = 0xC000022DL; /* Retry */
3262 #else
3263         NTStatus = 0xC0020018L; /* RPC_NT_SERVER_TOO_BUSY */
3264 #endif
3265     }
3266     else if (code == CM_ERROR_ALLOFFLINE ||
3267              code == CM_ERROR_ALLDOWN ||
3268              code == CM_ERROR_EMPTY) {
3269 #ifdef COMMENT
3270         NTStatus = 0xC000003AL; /* Path not found */
3271 #else
3272         NTStatus = 0xC0020017L; /* RPC_NT_SERVER_UNAVAILABLE */
3273 #endif
3274     }
3275     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3276         NTStatus = 0xC0000322L; /* No Kerberos key */
3277     }
3278     else if (code == CM_ERROR_BAD_LEVEL) {
3279         NTStatus = 0xC0000148L; /* Invalid Level */
3280     }
3281     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3282         NTStatus = 0xC000007EL; /* Range Not Locked */
3283     }
3284     else if (code == CM_ERROR_NOSUCHDEVICE) {
3285         NTStatus = 0xC000000EL; /* No Such Device */
3286     }
3287     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3288         NTStatus = 0xC0000055L; /* Lock Not Granted */
3289     }
3290     else if (code == ENOMEM) {
3291         NTStatus = 0xC0000017L; /* Out of Memory */
3292     }
3293     else if (code == EIO) {
3294         NTStatus = 0xC000016AL; /* Disk Operation Failure */
3295     }
3296     else if (code == CM_ERROR_RPC_MOREDATA) {
3297         NTStatus = 0x80000005L; /* Buffer overflow */
3298     }
3299     else {
3300         char foo[256];
3301         sprintf(foo, "No mapping for 0x%X using 0xC0982001\r\n", code);
3302         OutputDebugString(foo);
3303         NTStatus = 0xC0982001L; /* SMB non-specific error */
3304     }
3305
3306     *NTStatusp = NTStatus;
3307     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3308 }
3309
3310 /*
3311  * NTSTATUS <-> Win32 Error Translation
3312  * http://support.microsoft.com/kb/113996
3313  */
3314 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3315 {
3316     unsigned long Win32E;
3317
3318     /* map CM_ERROR_* errors to Win32 32-bit error codes */
3319     if (code == 0) {
3320         Win32E = 0;
3321     }
3322     else if (code == CM_ERROR_NOSUCHCELL) {
3323         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3324     }
3325     else if (code == CM_ERROR_NOSUCHVOLUME) {
3326         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3327     }
3328     else if (code == CM_ERROR_TIMEDOUT) {
3329 #ifdef COMMENT
3330         Win32E = ERROR_SHARING_PAUSED;  /* Sharing Paused */
3331 #else
3332         Win32E = ERROR_UNEXP_NET_ERR;   /* Timeout */
3333 #endif
3334     }
3335     else if (code == CM_ERROR_RETRY) {
3336         Win32E = ERROR_RETRY;           /* Retry */
3337     }
3338     else if (code == CM_ERROR_NOACCESS) {
3339         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3340     }
3341     else if (code == CM_ERROR_READONLY) {
3342         Win32E = ERROR_WRITE_PROTECT;   /* Write protected */
3343     }
3344     else if (code == CM_ERROR_NOSUCHFILE ||
3345              code == CM_ERROR_BPLUS_NOMATCH) {
3346         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3347     }
3348     else if (code == CM_ERROR_NOSUCHPATH) {
3349         Win32E = ERROR_PATH_NOT_FOUND;  /* Object path not found */
3350     }
3351     else if (code == CM_ERROR_TOOBIG) {
3352         Win32E = ERROR_BAD_EXE_FORMAT;  /* Invalid image format */
3353     }
3354     else if (code == CM_ERROR_INVAL) {
3355         Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3356     }
3357     else if (code == CM_ERROR_BADFD) {
3358         Win32E = ERROR_INVALID_HANDLE;  /* Invalid handle */
3359     }
3360     else if (code == CM_ERROR_BADFDOP) {
3361         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3362     }
3363     else if (code == CM_ERROR_UNKNOWN) {
3364         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3365     }
3366     else if (code == CM_ERROR_EXISTS) {
3367         Win32E = ERROR_ALREADY_EXISTS;  /* Object name collision */
3368     }
3369     else if (code == CM_ERROR_NOTEMPTY) {
3370         Win32E = ERROR_DIR_NOT_EMPTY;   /* Directory not empty */
3371     }
3372     else if (code == CM_ERROR_CROSSDEVLINK) {
3373         Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3374     }
3375     else if (code == CM_ERROR_NOTDIR) {
3376         Win32E = ERROR_DIRECTORY;       /* Not a directory */
3377     }
3378     else if (code == CM_ERROR_ISDIR) {
3379         Win32E = ERROR_ACCESS_DENIED;   /* File is a directory */
3380     }
3381     else if (code == CM_ERROR_BADOP) {
3382         Win32E = ERROR_NOT_SUPPORTED;   /* Not supported */
3383     }
3384     else if (code == CM_ERROR_BADSHARENAME) {
3385         Win32E = ERROR_BAD_NETPATH;     /* Bad network path (server valid, share bad) */
3386     }
3387     else if (code == CM_ERROR_NOIPC) {
3388 #ifdef COMMENT
3389         Win32E = ERROR_ACCESS_DENIED;   /* Access Denied */
3390 #else
3391         Win32E = ERROR_REM_NOT_LIST;    /* Remote Resources */
3392 #endif
3393     }
3394     else if (code == CM_ERROR_CLOCKSKEW ||
3395              code == RXKADNOAUTH) {
3396         Win32E = ERROR_TIME_SKEW;       /* Time difference at DC */
3397     }
3398     else if (code == CM_ERROR_BADTID) {
3399         Win32E = ERROR_FILE_NOT_FOUND;  /* SMB bad TID */
3400     }
3401     else if (code == CM_ERROR_USESTD) {
3402         Win32E = ERROR_ACCESS_DENIED;   /* SMB use standard */
3403     }
3404     else if (code == CM_ERROR_QUOTA) {
3405         Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3406     }
3407     else if (code == CM_ERROR_SPACE) {
3408         Win32E = ERROR_DISK_FULL;       /* Disk full */
3409     }
3410     else if (code == CM_ERROR_ATSYS) {
3411         Win32E = ERROR_INVALID_NAME;    /* Object name invalid */
3412     }
3413     else if (code == CM_ERROR_BADNTFILENAME) {
3414         Win32E = ERROR_INVALID_NAME;    /* Object name invalid */
3415     }
3416     else if (code == CM_ERROR_WOULDBLOCK) {
3417         Win32E = WAIT_TIMEOUT;          /* Can't wait */
3418     }
3419     else if (code == CM_ERROR_SHARING_VIOLATION) {
3420         Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3421     }
3422     else if (code == CM_ERROR_LOCK_CONFLICT) {
3423         Win32E = ERROR_LOCK_VIOLATION;   /* Lock conflict */
3424     }
3425     else if (code == CM_ERROR_PARTIALWRITE) {
3426         Win32E = ERROR_DISK_FULL;       /* Disk full */
3427     }
3428     else if (code == CM_ERROR_BUFFERTOOSMALL) {
3429         Win32E = ERROR_INSUFFICIENT_BUFFER;     /* Buffer too small */
3430     }
3431     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3432         Win32E = ERROR_ALREADY_EXISTS;  /* Object name collision */
3433     }
3434     else if (code == CM_ERROR_BADPASSWORD) {
3435         Win32E = ERROR_LOGON_FAILURE;   /* unknown username or bad password */
3436     }
3437     else if (code == CM_ERROR_BADLOGONTYPE) {
3438         Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3439     }
3440     else if (code == CM_ERROR_GSSCONTINUE) {
3441         Win32E = ERROR_MORE_DATA;       /* more processing required */
3442     }
3443     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3444 #ifdef COMMENT
3445         Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3446 #else
3447         Win32E = ERROR_ACCESS_DENIED;   /* Access Denied */
3448 #endif
3449     }
3450     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3451         Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3452     }
3453     else if (code == CM_ERROR_ALLBUSY) {
3454         Win32E = ERROR_RETRY;           /* Retry */
3455     }
3456     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3457         Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3458     }
3459     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3460         Win32E = SEC_E_NO_KERB_KEY;     /* No Kerberos key */
3461     }
3462     else if (code == CM_ERROR_BAD_LEVEL) {
3463         Win32E = ERROR_INVALID_LEVEL;   /* Invalid Level */
3464     }
3465     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3466         Win32E = ERROR_NOT_LOCKED;      /* Range Not Locked */
3467     }
3468     else if (code == CM_ERROR_NOSUCHDEVICE) {
3469         Win32E = ERROR_FILE_NOT_FOUND;  /* No Such Device */
3470     }
3471     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3472         Win32E = ERROR_LOCK_VIOLATION;  /* Lock Not Granted */
3473     }
3474     else if (code == ENOMEM) {
3475         Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3476     }
3477     else if (code == CM_ERROR_RPC_MOREDATA) {
3478         Win32E = ERROR_MORE_DATA;       /* Buffer overflow */
3479     }
3480     else  {
3481         Win32E = ERROR_GEN_FAILURE;     /* SMB non-specific error */
3482     }
3483
3484     *Win32Ep = Win32E;
3485     osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3486 }
3487
3488 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3489                       unsigned char *classp)
3490 {
3491     unsigned char class;
3492     unsigned short error;
3493
3494     /* map CM_ERROR_* errors to SMB errors */
3495     if (code == CM_ERROR_NOSUCHCELL) {
3496         class = 1;
3497         error = 3;      /* bad path */
3498     }
3499     else if (code == CM_ERROR_NOSUCHVOLUME) {
3500         class = 1;
3501         error = 3;      /* bad path */
3502     }
3503     else if (code == CM_ERROR_TIMEDOUT) {
3504         class = 2;
3505         error = 81;     /* server is paused */
3506     }
3507     else if (code == CM_ERROR_RETRY) {
3508         class = 2;      /* shouldn't happen */
3509         error = 1;
3510     }
3511     else if (code == CM_ERROR_NOACCESS) {
3512         class = 2;
3513         error = 4;      /* bad access */
3514     }
3515     else if (code == CM_ERROR_READONLY) {
3516         class = 3;
3517         error = 19;     /* read only */
3518     }
3519     else if (code == CM_ERROR_NOSUCHFILE ||
3520              code == CM_ERROR_BPLUS_NOMATCH) {
3521         class = 1;
3522         error = 2;      /* ENOENT! */
3523     }
3524     else if (code == CM_ERROR_NOSUCHPATH) {
3525         class = 1;
3526         error = 3;      /* Bad path */
3527     }
3528     else if (code == CM_ERROR_TOOBIG) {
3529         class = 1;
3530         error = 11;     /* bad format */
3531     }
3532     else if (code == CM_ERROR_INVAL) {
3533         class = 2;      /* server non-specific error code */
3534         error = 1;
3535     }
3536     else if (code == CM_ERROR_BADFD) {
3537         class = 1;
3538         error = 6;      /* invalid file handle */
3539     }
3540     else if (code == CM_ERROR_BADFDOP) {
3541         class = 1;      /* invalid op on FD */
3542         error = 5;
3543     }
3544     else if (code == CM_ERROR_EXISTS) {
3545         class = 1;
3546         error = 80;     /* file already exists */
3547     }
3548     else if (code == CM_ERROR_NOTEMPTY) {
3549         class = 1;
3550         error = 5;      /* delete directory not empty */
3551     }
3552     else if (code == CM_ERROR_CROSSDEVLINK) {
3553         class = 1;
3554         error = 17;     /* EXDEV */
3555     }
3556     else if (code == CM_ERROR_NOTDIR) {
3557         class = 1;      /* bad path */
3558         error = 3;
3559     }
3560     else if (code == CM_ERROR_ISDIR) {
3561         class = 1;      /* access denied; DOS doesn't have a good match */
3562         error = 5;
3563     }
3564     else if (code == CM_ERROR_BADOP) {
3565         class = 2;
3566         error = 65535;
3567     }
3568     else if (code == CM_ERROR_BADSHARENAME) {
3569         class = 2;
3570         error = 6;
3571     }
3572     else if (code == CM_ERROR_NOIPC) {
3573         class = 2;
3574         error = 4; /* bad access */
3575     }
3576     else if (code == CM_ERROR_CLOCKSKEW) {
3577         class = 1;      /* invalid function */
3578         error = 1;
3579     }
3580     else if (code == CM_ERROR_BADTID) {
3581         class = 2;
3582         error = 5;
3583     }
3584     else if (code == CM_ERROR_USESTD) {
3585         class = 2;
3586         error = 251;
3587     }
3588     else if (code == CM_ERROR_REMOTECONN) {
3589         class = 2;
3590         error = 82;
3591     }
3592     else if (code == CM_ERROR_QUOTA) {
3593         if (vcp->flags & SMB_VCFLAG_USEV3) {
3594             class = 3;
3595             error = 39; /* disk full */
3596         }
3597         else {
3598             class = 1;
3599             error = 5;  /* access denied */
3600         }
3601     }
3602     else if (code == CM_ERROR_SPACE) {
3603         if (vcp->flags & SMB_VCFLAG_USEV3) {
3604             class = 3;
3605             error = 39; /* disk full */
3606         }
3607         else {
3608             class = 1;
3609             error = 5;  /* access denied */
3610         }
3611     }
3612     else if (code == CM_ERROR_PARTIALWRITE) {
3613         class = 3;
3614         error = 39;     /* disk full */
3615     }
3616     else if (code == CM_ERROR_ATSYS) {
3617         class = 1;
3618         error = 2;      /* ENOENT */
3619     }
3620     else if (code == CM_ERROR_WOULDBLOCK) {
3621         class = 1;
3622         error = 33;     /* lock conflict */
3623     }
3624     else if (code == CM_ERROR_LOCK_CONFLICT) {
3625         class = 1;
3626         error = 33;     /* lock conflict */
3627     }
3628     else if (code == CM_ERROR_SHARING_VIOLATION) {
3629         class = 1;
3630         error = 33;     /* lock conflict */
3631     }
3632     else if (code == CM_ERROR_NOFILES) {
3633         class = 1;
3634         error = 18;     /* no files in search */
3635     }
3636     else if (code == CM_ERROR_RENAME_IDENTICAL) {
3637         class = 1;
3638         error = 183;     /* Samba uses this */
3639     }
3640     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3641         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3642         class = 2;
3643         error = 2; /* bad password */
3644     }
3645     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3646         class = 2;
3647         error = 3;     /* bad path */
3648     }
3649     else {
3650         class = 2;
3651         error = 1;
3652     }
3653
3654     *scodep = error;
3655     *classp = class;
3656     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3657 }
3658
3659 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3660 {
3661     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3662     return CM_ERROR_BADOP;
3663 }
3664
3665 /* SMB_COM_ECHO */
3666 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3667 {
3668     unsigned short EchoCount, i;
3669     char *data, *outdata;
3670     int dataSize;
3671
3672     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3673
3674     for (i=1; i<=EchoCount; i++) {
3675         data = smb_GetSMBData(inp, &dataSize);
3676         smb_SetSMBParm(outp, 0, i);
3677         smb_SetSMBDataLength(outp, dataSize);
3678         outdata = smb_GetSMBData(outp, NULL);
3679         memcpy(outdata, data, dataSize);
3680         smb_SendPacket(vcp, outp);
3681     }
3682
3683     return 0;
3684 }
3685
3686 /* SMB_COM_READ_RAW */
3687 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3688 {
3689     osi_hyper_t offset;
3690     long count, minCount, finalCount;
3691     unsigned short fd;
3692     unsigned pid;
3693     smb_fid_t *fidp;
3694     smb_t *smbp = (smb_t*) inp;
3695     long code = 0;
3696     cm_user_t *userp = NULL;
3697     NCB *ncbp;
3698     int rc;
3699     char *rawBuf = NULL;
3700
3701     rawBuf = NULL;
3702     finalCount = 0;
3703
3704     fd = smb_GetSMBParm(inp, 0);
3705     count = smb_GetSMBParm(inp, 3);
3706     minCount = smb_GetSMBParm(inp, 4);
3707     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3708
3709     if (*inp->wctp == 10) {
3710         /* we were sent a request with 64-bit file offsets */
3711         offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3712
3713         if (LargeIntegerLessThanZero(offset)) {
3714             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3715             goto send1;
3716         }
3717     } else {
3718         /* we were sent a request with 32-bit file offsets */
3719         offset.HighPart = 0;
3720     }
3721
3722     osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3723              fd, offset.HighPart, offset.LowPart, count);
3724
3725     fidp = smb_FindFID(vcp, fd, 0);
3726     if (!fidp) {
3727         osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3728                  vcp, fd);
3729         goto send1;
3730     }
3731     lock_ObtainMutex(&fidp->mx);
3732     if (!fidp->scp) {
3733         lock_ReleaseMutex(&fidp->mx);
3734         smb_ReleaseFID(fidp);
3735         return CM_ERROR_BADFD;
3736     }
3737
3738     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3739         lock_ReleaseMutex(&fidp->mx);
3740         smb_CloseFID(vcp, fidp, NULL, 0);
3741         code = CM_ERROR_NOSUCHFILE;
3742         goto send1a;
3743     }
3744
3745     pid = smbp->pid;
3746     {
3747         LARGE_INTEGER LOffset, LLength;
3748         cm_key_t key;
3749
3750         key = cm_GenerateKey(vcp->vcID, pid, fd);
3751
3752         LOffset.HighPart = offset.HighPart;
3753         LOffset.LowPart = offset.LowPart;
3754         LLength.HighPart = 0;
3755         LLength.LowPart = count;
3756
3757         lock_ObtainWrite(&fidp->scp->rw);
3758         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3759         lock_ReleaseWrite(&fidp->scp->rw);
3760     }
3761     if (code) {
3762         lock_ReleaseMutex(&fidp->mx);
3763         goto send1a;
3764     }
3765
3766     lock_ObtainMutex(&smb_RawBufLock);
3767     if (smb_RawBufs) {
3768         /* Get a raw buf, from head of list */
3769         rawBuf = smb_RawBufs;
3770         smb_RawBufs = *(char **)smb_RawBufs;
3771     }
3772     lock_ReleaseMutex(&smb_RawBufLock);
3773     if (!rawBuf) {
3774         lock_ReleaseMutex(&fidp->mx);
3775         goto send1a;
3776     }
3777
3778     if (fidp->flags & SMB_FID_IOCTL)
3779     {
3780         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3781         if (rawBuf) {
3782             /* Give back raw buffer */
3783             lock_ObtainMutex(&smb_RawBufLock);
3784             *((char **) rawBuf) = smb_RawBufs;
3785
3786             smb_RawBufs = rawBuf;
3787             lock_ReleaseMutex(&smb_RawBufLock);
3788         }
3789
3790         lock_ReleaseMutex(&fidp->mx);
3791         smb_ReleaseFID(fidp);
3792         return rc;
3793     }
3794     lock_ReleaseMutex(&fidp->mx);
3795
3796     userp = smb_GetUserFromVCP(vcp, inp);
3797
3798     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3799
3800     if (code != 0)
3801         goto send;
3802
3803   send:
3804     cm_ReleaseUser(userp);
3805
3806   send1a:
3807     smb_ReleaseFID(fidp);
3808
3809   send1:
3810     ncbp = outp->ncbp;
3811     memset(ncbp, 0, sizeof(NCB));
3812
3813     ncbp->ncb_length = (unsigned short) finalCount;
3814     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3815     ncbp->ncb_lana_num = vcp->lana;
3816     ncbp->ncb_command = NCBSEND;
3817     ncbp->ncb_buffer = rawBuf;
3818
3819     code = Netbios(ncbp);
3820     if (code != 0)
3821         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3822
3823     if (rawBuf) {
3824         /* Give back raw buffer */
3825         lock_ObtainMutex(&smb_RawBufLock);
3826         *((char **) rawBuf) = smb_RawBufs;
3827
3828         smb_RawBufs = rawBuf;
3829         lock_ReleaseMutex(&smb_RawBufLock);
3830     }
3831
3832     return 0;
3833 }
3834
3835 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3836 {
3837     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3838                          ongoingOps - 1);
3839     return 0;
3840 }
3841
3842 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3843 {
3844     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3845                          ongoingOps - 1);
3846     return 0;
3847 }
3848
3849 /* SMB_COM_NEGOTIATE */
3850 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3851 {
3852     char *namep;
3853     char *datap;
3854     int coreProtoIndex;
3855     int v3ProtoIndex;
3856     int NTProtoIndex;
3857     int VistaProtoIndex;
3858     int protoIndex;                             /* index we're using */
3859     int namex;
3860     int dbytes;
3861     int entryLength;
3862     int tcounter;
3863     char protocol_array[10][1024];  /* protocol signature of the client */
3864     int caps;                       /* capabilities */
3865     time_t unixTime;
3866     afs_uint32 dosTime;
3867     TIME_ZONE_INFORMATION tzi;
3868
3869     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3870                          ongoingOps - 1);
3871
3872     namep = smb_GetSMBData(inp, &dbytes);
3873     namex = 0;
3874     tcounter = 0;
3875     coreProtoIndex = -1;                /* not found */
3876     v3ProtoIndex = -1;
3877     NTProtoIndex = -1;
3878     VistaProtoIndex = -1;
3879     while(namex < dbytes) {
3880         osi_Log1(smb_logp, "Protocol %s",
3881                   osi_LogSaveString(smb_logp, namep+1));
3882         strcpy(protocol_array[tcounter], namep+1);
3883
3884         /* namep points at the first protocol, or really, a 0x02
3885          * byte preceding the null-terminated ASCII name.
3886          */
3887         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3888             coreProtoIndex = tcounter;
3889         }
3890         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3891             v3ProtoIndex = tcounter;
3892         }
3893         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3894             NTProtoIndex = tcounter;
3895         }
3896         else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3897             VistaProtoIndex = tcounter;
3898         }
3899
3900         /* compute size of protocol entry */
3901         entryLength = (int)strlen(namep+1);
3902         entryLength += 2;       /* 0x02 bytes and null termination */
3903
3904         /* advance over this protocol entry */
3905         namex += entryLength;
3906         namep += entryLength;
3907         tcounter++;             /* which proto entry we're looking at */
3908     }
3909
3910     lock_ObtainMutex(&vcp->mx);
3911     if (NTProtoIndex != -1) {
3912         protoIndex = NTProtoIndex;
3913         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3914     }
3915     else if (v3ProtoIndex != -1) {
3916         protoIndex = v3ProtoIndex;
3917         vcp->flags |= SMB_VCFLAG_USEV3;
3918     }
3919     else if (coreProtoIndex != -1) {
3920         protoIndex = coreProtoIndex;
3921         vcp->flags |= SMB_VCFLAG_USECORE;
3922     }
3923     else protoIndex = -1;
3924     lock_ReleaseMutex(&vcp->mx);
3925
3926     if (protoIndex == -1)
3927         return CM_ERROR_INVAL;
3928     else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3929         smb_SetSMBParm(outp, 0, protoIndex);
3930         if (smb_authType != SMB_AUTH_NONE) {
3931             smb_SetSMBParmByte(outp, 1,
3932                                NEGOTIATE_SECURITY_USER_LEVEL |
3933                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
3934         } else {
3935             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3936         }
3937         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
3938         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3939         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
3940         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
3941         /* The session key is not a well documented field however most clients
3942          * will echo back the session key to the server.  Currently we are using
3943          * the same value for all sessions.  We should generate a random value
3944          * and store it into the vcp
3945          */
3946         smb_SetSMBParmLong(outp, 7, 0x1a2b3c4d);        /* session key */
3947         /*
3948          * Tried changing the capabilities to support for W2K - defect 117695
3949          * Maybe something else needs to be changed here?
3950          */
3951         /*
3952         if (isWindows2000)
3953         smb_SetSMBParmLong(outp, 9, 0x43fd);
3954         else
3955         smb_SetSMBParmLong(outp, 9, 0x251);
3956         */
3957         /* Capabilities: *
3958          * 32-bit error codes *
3959          * and NT Find *
3960          * and NT SMB's *
3961          * and raw mode
3962          * and DFS
3963          * and Unicode */
3964         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3965 #ifdef DFS_SUPPORT
3966                NTNEGOTIATE_CAPABILITY_DFS |
3967 #endif
3968                NTNEGOTIATE_CAPABILITY_LARGEFILES |
3969                NTNEGOTIATE_CAPABILITY_NTFIND |
3970                NTNEGOTIATE_CAPABILITY_RAWMODE |
3971                NTNEGOTIATE_CAPABILITY_NTSMB;
3972
3973         if ( smb_authType == SMB_AUTH_EXTENDED )
3974             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3975
3976 #ifdef SMB_UNICODE
3977         if ( smb_UseUnicode ) {
3978             caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3979         }
3980 #endif
3981
3982         smb_SetSMBParmLong(outp, 9, caps);
3983         time(&unixTime);
3984         cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3985         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3986         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3987
3988         GetTimeZoneInformation(&tzi);
3989         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
3990
3991         if (smb_authType == SMB_AUTH_NTLM) {
3992             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3993             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3994             /* paste in encryption key */
3995             datap = smb_GetSMBData(outp, NULL);
3996             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3997             /* and the faux domain name */
3998             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3999                                   datap + MSV1_0_CHALLENGE_LENGTH,
4000                                   (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4001         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
4002             void * secBlob = NULL;
4003             int secBlobLength = 0;
4004
4005             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
4006
4007             /*
4008              * The SMB specification permits the server to save a round trip
4009              * in the GSS negotiation by sending an initial security blob.
4010              * Unfortunately, doing so trips a bug in Windows 7 and Server 2008 R2
4011              * whereby the SMB 1.x redirector drops the blob on the floor after
4012              * the first connection to the server and simply attempts to reuse
4013              * the previous authentication context.  This bug can be avoided by
4014              * the server sending no security blob in the SMB_COM_NEGOTIATE
4015              * response.  This forces the client to send an initial GSS init_sec_context
4016              * blob under all circumstances which works around the bug in Microsoft's
4017              * code.
4018              *
4019              * Do not call smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
4020              */
4021
4022             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
4023             datap = smb_GetSMBData(outp, NULL);
4024
4025             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
4026             datap += sizeof(smb_ServerGUID);
4027
4028             if (secBlob) {
4029                 memcpy(datap, secBlob, secBlobLength);
4030                 free(secBlob);
4031                 datap += sizeof(secBlobLength);
4032             }
4033         } else {
4034             smb_SetSMBParmByte(outp, 16, 0);/* Challenge length */
4035             smb_SetSMBDataLength(outp, smb_ServerDomainNameLength);
4036             datap = smb_GetSMBData(outp, NULL);
4037             /* the faux domain name */
4038             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4039                                   datap,
4040                                   (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4041         }
4042     }
4043     else if (v3ProtoIndex != -1) {
4044         smb_SetSMBParm(outp, 0, protoIndex);
4045
4046         /* NOTE: Extended authentication cannot be negotiated with v3
4047          * therefore we fail over to NTLM
4048          */
4049         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4050             smb_SetSMBParm(outp, 1,
4051                            NEGOTIATE_SECURITY_USER_LEVEL |
4052                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
4053         } else {
4054             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
4055         }
4056         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
4057         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
4058         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
4059         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
4060         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
4061         smb_SetSMBParm(outp, 7, 1);
4062         time(&unixTime);
4063         cm_SearchTimeFromUnixTime(&dosTime, unixTime);
4064         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
4065         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
4066
4067         GetTimeZoneInformation(&tzi);
4068         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
4069
4070         /* NOTE: Extended authentication cannot be negotiated with v3
4071          * therefore we fail over to NTLM
4072          */
4073         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4074             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
4075             smb_SetSMBParm(outp, 12, 0);        /* resvd */
4076             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
4077             datap = smb_GetSMBData(outp, NULL);
4078             /* paste in a new encryption key */
4079             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
4080             /* and the faux domain name */
4081             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4082                                   datap + MSV1_0_CHALLENGE_LENGTH,
4083                                   (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4084         } else {
4085             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
4086             smb_SetSMBParm(outp, 12, 0); /* resvd */
4087             smb_SetSMBDataLength(outp, 0);
4088         }
4089     }
4090     else if (coreProtoIndex != -1) {     /* not really supported anymore */
4091         smb_SetSMBParm(outp, 0, protoIndex);
4092         smb_SetSMBDataLength(outp, 0);
4093     }
4094     return 0;
4095 }
4096
4097 void smb_CheckVCs(void)
4098 {
4099     smb_vc_t * vcp, *nextp;
4100     smb_packet_t * outp = smb_GetPacket();
4101     smb_t *smbp;
4102
4103     lock_ObtainWrite(&smb_rctLock);
4104     for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
4105     {
4106         if (vcp->magic != SMB_VC_MAGIC)
4107             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
4108                        __FILE__, __LINE__);
4109
4110         /* on the first pass hold 'vcp' which was not held as 'nextp' */
4111         if (vcp != nextp)
4112             smb_HoldVCNoLock(vcp);
4113
4114         /*
4115          * obtain a reference to 'nextp' now because we drop the
4116          * smb_rctLock later and the list contents could change
4117          * or 'vcp' could be destroyed when released.
4118          */
4119         nextp = vcp->nextp;
4120         if (nextp)
4121             smb_HoldVCNoLock(nextp);
4122
4123         if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4124             smb_ReleaseVCNoLock(vcp);
4125             continue;
4126         }
4127
4128         smb_FormatResponsePacket(vcp, NULL, outp);
4129         smbp = (smb_t *)outp;
4130         outp->inCom = smbp->com = 0x2b /* Echo */;
4131         smbp->tid = 0xFFFF;
4132         smbp->pid = 0;
4133         smbp->uid = 0;
4134         smbp->mid = 0;
4135         smbp->res[0] = 0;
4136         smbp->res[1] = 0;
4137
4138         smb_SetSMBParm(outp, 0, 0);
4139         smb_SetSMBDataLength(outp, 0);
4140         lock_ReleaseWrite(&smb_rctLock);
4141
4142         smb_SendPacket(vcp, outp);
4143
4144         lock_ObtainWrite(&smb_rctLock);
4145         smb_ReleaseVCNoLock(vcp);
4146     }
4147     lock_ReleaseWrite(&smb_rctLock);
4148     smb_FreePacket(outp);
4149 }
4150
4151 void smb_Daemon(void *parmp)
4152 {
4153     afs_uint32 count = 0;
4154     smb_username_t    **unpp;
4155     time_t              now;
4156
4157     while(smbShutdownFlag == 0) {
4158         count++;
4159         thrd_Sleep(10000);
4160
4161         if (smbShutdownFlag == 1)
4162             break;
4163
4164         if ((count % 72) == 0)  {       /* every five minutes */
4165             struct tm myTime;
4166             time_t old_localZero = smb_localZero;
4167
4168             /* Initialize smb_localZero */
4169             myTime.tm_isdst = -1;               /* compute whether on DST or not */
4170             myTime.tm_year = 70;
4171             myTime.tm_mon = 0;
4172             myTime.tm_mday = 1;
4173             myTime.tm_hour = 0;
4174             myTime.tm_min = 0;
4175             myTime.tm_sec = 0;
4176             smb_localZero = mktime(&myTime);
4177
4178 #ifdef AFS_FREELANCE
4179             if ( smb_localZero != old_localZero )
4180                 cm_noteLocalMountPointChange(FALSE);
4181 #endif
4182
4183             smb_CheckVCs();
4184         }
4185
4186         /* GC smb_username_t objects that will no longer be used */
4187         now = osi_Time();
4188         lock_ObtainWrite(&smb_rctLock);
4189         for ( unpp=&usernamesp; *unpp; ) {
4190             int deleteOk = 0;
4191             smb_username_t *unp;
4192
4193             lock_ObtainMutex(&(*unpp)->mx);
4194             if ( (*unpp)->refCount > 0 ||
4195                  ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4196                  !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4197                 ;
4198             else if (!smb_LogoffTokenTransfer ||
4199                      ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4200                 deleteOk = 1;
4201             lock_ReleaseMutex(&(*unpp)->mx);
4202
4203             if (deleteOk) {
4204                 cm_user_t * userp;
4205
4206                 unp = *unpp;
4207                 *unpp = unp->nextp;
4208                 unp->nextp = NULL;
4209                 lock_FinalizeMutex(&unp->mx);
4210                 userp = unp->userp;
4211                 free(unp->name);
4212                 free(unp->machine);
4213                 free(unp);
4214                 if (userp)
4215                     cm_ReleaseUser(userp);
4216             } else {
4217                 unpp = &(*unpp)->nextp;
4218             }
4219         }
4220         lock_ReleaseWrite(&smb_rctLock);
4221
4222         /* XXX GC dir search entries */
4223     }
4224 }
4225
4226 void smb_WaitingLocksDaemon()
4227 {
4228     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4229     smb_waitingLock_t *wl, *wlNext;
4230     int first;
4231     smb_vc_t *vcp;
4232     smb_packet_t *inp, *outp;
4233     NCB *ncbp;
4234     long code = 0;
4235
4236     while (smbShutdownFlag == 0) {
4237         lock_ObtainWrite(&smb_globalLock);
4238         nwlRequest = smb_allWaitingLocks;
4239         if (nwlRequest == NULL) {
4240             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4241             thrd_Sleep(1000);
4242             continue;
4243         } else {
4244             first = 1;
4245             osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4246         }
4247
4248         do {
4249             if (first)
4250                 first = 0;
4251             else
4252                 lock_ObtainWrite(&smb_globalLock);
4253
4254             osi_Log1(smb_logp, "    Checking waiting lock request %p", nwlRequest);
4255
4256             wlRequest = nwlRequest;
4257             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4258             lock_ReleaseWrite(&smb_globalLock);
4259
4260             code = 0;
4261
4262             for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4263                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4264                     continue;
4265
4266                 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4267                     code = CM_ERROR_LOCK_NOT_GRANTED;
4268                     break;
4269                 }
4270
4271                 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4272
4273                 /* wl->state is either _DONE or _WAITING.  _ERROR
4274                    would no longer be on the queue. */
4275                 code = cm_RetryLock( wl->lockp,
4276                                      !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4277
4278                 if (code == 0) {
4279                     wl->state = SMB_WAITINGLOCKSTATE_DONE;
4280                 } else if (code != CM_ERROR_WOULDBLOCK) {
4281                     wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4282                     break;
4283                 }
4284             }
4285
4286             if (code == CM_ERROR_WOULDBLOCK) {
4287
4288                 /* no progress */
4289                 if (wlRequest->msTimeout != 0xffffffff
4290                      && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4291                     goto endWait;
4292
4293                 continue;
4294             }
4295
4296           endWait:
4297
4298             if (code != 0) {
4299                 cm_scache_t * scp;
4300                 cm_req_t req;
4301
4302                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4303                          wlRequest);
4304
4305                 scp = wlRequest->scp;
4306                 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4307
4308                 smb_InitReq(&req);
4309
4310                 lock_ObtainWrite(&scp->rw);
4311
4312                 for (wl = wlRequest->locks; wl; wl = wlNext) {
4313                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4314
4315                     if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4316                         cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4317                                   wl->LLength, wl->key, 0, NULL, &req);
4318
4319                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4320
4321                     free(wl);
4322                 }
4323
4324                 lock_ReleaseWrite(&scp->rw);
4325
4326             } else {
4327
4328                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4329                          wlRequest);
4330
4331                 for (wl = wlRequest->locks; wl; wl = wlNext) {
4332                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4333                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4334                     free(wl);
4335                 }
4336             }
4337
4338             vcp = wlRequest->vcp;
4339             inp = wlRequest->inp;
4340             outp = wlRequest->outp;
4341             ncbp = smb_GetNCB();
4342             ncbp->ncb_length = inp->ncb_length;
4343             inp->spacep = cm_GetSpace();
4344
4345             /* Remove waitingLock from list */
4346             lock_ObtainWrite(&smb_globalLock);
4347             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4348                          &wlRequest->q);
4349             lock_ReleaseWrite(&smb_globalLock);
4350
4351             /* Resume packet processing */
4352             if (code == 0)
4353                 smb_SetSMBDataLength(outp, 0);
4354             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4355             outp->resumeCode = code;
4356             outp->ncbp = ncbp;
4357             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4358
4359             /* Clean up */
4360             cm_FreeSpace(inp->spacep);
4361             smb_FreePacket(inp);
4362             smb_FreePacket(outp);
4363             smb_ReleaseVC(vcp);
4364             cm_ReleaseSCache(wlRequest->scp);
4365             smb_FreeNCB(ncbp);
4366             free(wlRequest);
4367         } while (nwlRequest && smbShutdownFlag == 0);
4368         thrd_Sleep(1000);
4369     }
4370 }
4371
4372 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4373 {
4374     osi_Log0(smb_logp, "SMB receive get disk attributes");
4375
4376     smb_SetSMBParm(outp, 0, 32000);
4377     smb_SetSMBParm(outp, 1, 64);
4378     smb_SetSMBParm(outp, 2, 1024);
4379     smb_SetSMBParm(outp, 3, 30000);
4380     smb_SetSMBParm(outp, 4, 0);
4381     smb_SetSMBDataLength(outp, 0);
4382     return 0;
4383 }
4384
4385 /* SMB_COM_TREE_CONNECT */
4386 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4387 {
4388     smb_tid_t *tidp;
4389     smb_user_t *uidp;
4390     unsigned short newTid;
4391     clientchar_t shareName[AFSPATHMAX];
4392     clientchar_t *sharePath;
4393     int shareFound;
4394     clientchar_t *tp;
4395     clientchar_t *pathp;
4396     cm_user_t *userp;
4397
4398     osi_Log0(smb_logp, "SMB receive tree connect");
4399
4400     /* parse input parameters */
4401     {
4402         char *tbp;
4403         tbp = smb_GetSMBData(inp, NULL);
4404         pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4405         if (!pathp)
4406             return CM_ERROR_BADSMB;
4407     }
4408     tp = cm_ClientStrRChr(pathp, '\\');
4409     if (!tp)
4410         return CM_ERROR_BADSMB;
4411     cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4412
4413     lock_ObtainMutex(&vcp->mx);
4414     newTid = vcp->tidCounter++;
4415     lock_ReleaseMutex(&vcp->mx);
4416
4417     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4418     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4419     if (!uidp)
4420         return CM_ERROR_BADSMB;
4421     userp = smb_GetUserFromUID(uidp);
4422     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4423     smb_ReleaseUID(uidp);
4424     if (!shareFound) {
4425         smb_ReleaseTID(tidp, FALSE);
4426         return CM_ERROR_BADSHARENAME;
4427     }
4428     lock_ObtainMutex(&tidp->mx);
4429     tidp->userp = userp;
4430     tidp->pathname = sharePath;
4431     lock_ReleaseMutex(&tidp->mx);
4432     smb_ReleaseTID(tidp, FALSE);
4433
4434     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4435     smb_SetSMBParm(rsp, 1, newTid);
4436     smb_SetSMBDataLength(rsp, 0);
4437
4438     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4439     return 0;
4440 }
4441
4442 /* set maskp to the mask part of the incoming path.
4443  * Mask is 11 bytes long (8.3 with the dot elided).
4444  * Returns true if succeeds with a valid name, otherwise it does
4445  * its best, but returns false.
4446  */
4447 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4448 {
4449     clientchar_t *tp;
4450     clientchar_t *up;
4451     int i;
4452     int tc;
4453     int valid8Dot3;
4454
4455     /* starts off valid */
4456     valid8Dot3 = 1;
4457
4458     /* mask starts out all blanks */
4459     memset(maskp, ' ', 11);
4460     maskp[11] = '\0';
4461
4462     /* find last backslash, or use whole thing if there is none */
4463     tp = cm_ClientStrRChr(pathp, '\\');
4464     if (!tp)
4465         tp = pathp;
4466     else
4467         tp++;   /* skip slash */
4468
4469     up = maskp;
4470
4471     /* names starting with a dot are illegal */
4472     if (*tp == '.')
4473         valid8Dot3 = 0;
4474
4475     for(i=0;; i++) {
4476         tc = *tp++;
4477         if (tc == 0)
4478             return valid8Dot3;
4479         if (tc == '.' || tc == '"')
4480             break;
4481         if (i < 8)
4482             *up++ = tc;
4483         else
4484             valid8Dot3 = 0;
4485     }
4486
4487     /* if we get here, tp point after the dot */
4488     up = maskp+8;       /* ext goes here */
4489     for(i=0;;i++) {
4490         tc = *tp++;
4491         if (tc == 0)
4492             return valid8Dot3;
4493
4494         /* too many dots */
4495         if (tc == '.' || tc == '"')
4496             valid8Dot3 = 0;
4497
4498         /* copy extension if not too long */
4499         if (i < 3)
4500             *up++ = tc;
4501         else
4502             valid8Dot3 = 0;
4503     }
4504
4505     /* unreachable */
4506 }
4507
4508 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4509 {
4510     clientchar_t umask[11];
4511     int valid;
4512     int i;
4513     clientchar_t tc1;
4514     clientchar_t tc2;
4515     clientchar_t *tp1;
4516     clientchar_t *tp2;
4517
4518     /* XXX redo this, calling cm_MatchMask with a converted mask */
4519
4520     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4521     if (!valid)
4522         return 0;
4523
4524     /* otherwise, we have a valid 8.3 name; see if we have a match,
4525      * treating '?' as a wildcard in maskp (but not in the file name).
4526      */
4527     tp1 = umask;        /* real name, in mask format */
4528     tp2 = maskp;        /* mask, in mask format */
4529     for(i=0; i<11; i++) {
4530         tc1 = *tp1++;   /* clientchar_t from real name */
4531         tc2 = *tp2++;   /* clientchar_t from mask */
4532         tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4533         tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4534         if (tc1 == tc2)
4535             continue;
4536         if (tc2 == '?' && tc1 != ' ')
4537             continue;
4538         if (tc2 == '>')
4539             continue;
4540         return 0;
4541     }
4542
4543     /* we got a match */
4544     return 1;
4545 }
4546
4547 clientchar_t *smb_FindMask(clientchar_t *pathp)
4548 {
4549     clientchar_t *tp;
4550
4551     tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4552
4553     if (tp)
4554         return tp+1;    /* skip the slash */
4555     else
4556         return pathp;   /* no slash, return the entire path */
4557 }
4558
4559 /* SMB_COM_SEARCH for a volume label
4560
4561    (This is called from smb_ReceiveCoreSearchDir() and not an actual
4562    dispatch function.) */
4563 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4564 {
4565     clientchar_t *pathp;
4566     unsigned char *tp;
4567     clientchar_t mask[12];
4568     unsigned char *statBlockp;
4569     unsigned char initStatBlock[21];
4570     int statLen;
4571
4572     osi_Log0(smb_logp, "SMB receive search volume");
4573
4574     /* pull pathname and stat block out of request */
4575     tp = smb_GetSMBData(inp, NULL);
4576     pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4577                                 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4578     if (!pathp)
4579         return CM_ERROR_BADSMB;
4580     statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4581     osi_assertx(statBlockp != NULL, "null statBlock");
4582     if (statLen == 0) {
4583         statBlockp = initStatBlock;
4584         statBlockp[0] = 8;
4585     }
4586
4587     /* for returning to caller */
4588     smb_Get8Dot3MaskFromPath(mask, pathp);
4589
4590     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
4591     tp = smb_GetSMBData(outp, NULL);
4592     *tp++ = 5;
4593     *tp++ = 43; /* bytes in a dir entry */
4594     *tp++ = 0;  /* high byte in counter */
4595
4596     /* now marshall the dir entry, starting with the search status */
4597     *tp++ = statBlockp[0];              /* Reserved */
4598     memcpy(tp, mask, 11); tp += 11;     /* FileName */
4599
4600     /* now pass back server use info, with 1st byte non-zero */
4601     *tp++ = 1;
4602     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
4603
4604     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
4605
4606     *tp++ = 0x8;                /* attribute: volume */
4607
4608     /* copy out time */
4609     *tp++ = 0;
4610     *tp++ = 0;
4611
4612     /* copy out date */
4613     *tp++ = 18;
4614     *tp++ = 178;
4615
4616     /* 4 byte file size */
4617     *tp++ = 0;
4618     *tp++ = 0;
4619     *tp++ = 0;
4620     *tp++ = 0;
4621
4622     /* The filename is a UCHAR buffer that is ASCII even if Unicode
4623        was negotiated. */
4624
4625     /* finally, null-terminated 8.3 pathname, which we set to AFS */
4626     memset(tp, ' ', 13);
4627     strcpy(tp, "AFS");
4628
4629     /* set the length of the data part of the packet to 43 + 3, for the dir
4630      * entry plus the 5 and the length fields.
4631      */
4632     smb_SetSMBDataLength(outp, 46);
4633     return 0;
4634 }
4635
4636 static long
4637 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4638                         clientchar_t * tidPathp, clientchar_t * relPathp,
4639                         cm_user_t *userp, cm_req_t *reqp)
4640 {
4641     long code = 0;
4642     cm_scache_t *scp;
4643     char *dptr;
4644     afs_uint32 dosTime;
4645     u_short shortTemp;
4646     char attr;
4647     smb_dirListPatch_t *patchp;
4648     smb_dirListPatch_t *npatchp;
4649     clientchar_t path[AFSPATHMAX];
4650     afs_uint32 rights;
4651     afs_int32 mustFake = 0;
4652     afs_int32 nobulkstat = 0;
4653
4654     lock_ObtainWrite(&dscp->rw);
4655     code = cm_FindACLCache(dscp, userp, &rights);
4656     if (code == -1) {
4657         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4658                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4659         if (code == CM_ERROR_NOACCESS) {
4660             mustFake = 1;
4661             code = 0;
4662         }
4663     }
4664     lock_ReleaseWrite(&dscp->rw);
4665     if (code)
4666         goto cleanup;
4667
4668     if (!mustFake) {    /* Bulk Stat */
4669         afs_uint32 count;
4670         cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4671
4672         memset(bsp, 0, sizeof(cm_bulkStat_t));
4673         bsp->userp = userp;
4674
4675       restart_patchset:
4676         for (patchp = *dirPatchespp, count=0;
4677              patchp;
4678              patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4679             cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4680             int i;
4681
4682             if (tscp) {
4683                 if (lock_TryWrite(&tscp->rw)) {
4684                     /* we have an entry that we can look at */
4685                     if (!cm_EAccesFindEntry(userp, &tscp->fid) && cm_HaveCallback(tscp)) {
4686                         /* we have a callback on it.  Don't bother
4687                         * fetching this stat entry, since we're happy
4688                         * with the info we have.
4689                         */
4690                         lock_ReleaseWrite(&tscp->rw);
4691                         cm_ReleaseSCache(tscp);
4692                         continue;
4693                     }
4694
4695                     if (nobulkstat) {
4696                         code = cm_SyncOp(tscp, NULL, userp, reqp, 0,
4697                                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4698                         lock_ReleaseWrite(&tscp->rw);
4699                         cm_ReleaseSCache(tscp);
4700                         continue;
4701                     }
4702
4703                     lock_ReleaseWrite(&tscp->rw);
4704                 } /* got lock */
4705                 cm_ReleaseSCache(tscp);
4706             }   /* found entry */
4707
4708             i = bsp->counter++;
4709             bsp->fids[i].Volume = patchp->fid.volume;
4710             bsp->fids[i].Vnode = patchp->fid.vnode;
4711             bsp->fids[i].Unique = patchp->fid.unique;
4712
4713             if (bsp->counter == AFSCBMAX) {
4714                 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4715                 memset(bsp, 0, sizeof(cm_bulkStat_t));
4716                 bsp->userp = userp;
4717
4718                 if (code == CM_ERROR_BULKSTAT_FAILURE) {
4719                     /*
4720                      * If bulk stat cannot be used for this directory
4721                      * we must perform individual fetch status calls.
4722                      * Restart from the beginning of the patch series.
4723                      */
4724                     nobulkstat = 1;
4725                     goto restart_patchset;
4726                 }
4727             }
4728         }
4729
4730         if (bsp->counter > 0)
4731             code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4732
4733         free(bsp);
4734     }
4735
4736     for (patchp = *dirPatchespp; patchp; patchp =
4737          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4738
4739         dptr = patchp->dptr;
4740
4741         cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4742                             relPathp ? relPathp : _C(""), patchp->dep->name);
4743         reqp->relPathp = path;
4744         reqp->tidPathp = tidPathp;
4745
4746         code = cm_GetSCache(&patchp->fid, &dscp->fid, &scp, userp, reqp);
4747         reqp->relPathp = reqp->tidPathp = NULL;
4748
4749         if (code) {
4750             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4751                 *dptr++ = SMB_ATTR_HIDDEN;
4752             continue;
4753         }
4754         lock_ObtainWrite(&scp->rw);
4755         if (mustFake || cm_EAccesFindEntry(userp, &scp->fid) || !cm_HaveCallback(scp)) {
4756             lock_ReleaseWrite(&scp->rw);
4757
4758             /* set the attribute */
4759             switch (scp->fileType) {
4760             case CM_SCACHETYPE_DIRECTORY:
4761             case CM_SCACHETYPE_MOUNTPOINT:
4762             case CM_SCACHETYPE_INVALID:
4763                 attr = SMB_ATTR_DIRECTORY;
4764                 break;
4765             case CM_SCACHETYPE_SYMLINK:
4766                 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4767                     attr = SMB_ATTR_DIRECTORY;
4768                 else
4769                     attr = SMB_ATTR_NORMAL;
4770                 break;
4771             default:
4772                 /* if we get here we either have a normal file
4773                 * or we have a file for which we have never
4774                 * received status info.  In this case, we can
4775                 * check the even/odd value of the entry's vnode.
4776                 * odd means it is to be treated as a directory
4777                 * and even means it is to be treated as a file.
4778                 */
4779                 if (mustFake && (scp->fid.vnode & 0x1))
4780                     attr = SMB_ATTR_DIRECTORY;
4781                 else
4782                     attr = SMB_ATTR_NORMAL;
4783             }
4784             *dptr++ = attr;
4785
4786             /* 1969-12-31 23:59:58 +00*/
4787             dosTime = 0xEBBFBF7D;
4788
4789             /* copy out time */
4790             shortTemp = (unsigned short) (dosTime & 0xffff);
4791             *((u_short *)dptr) = shortTemp;
4792             dptr += 2;
4793
4794             /* and copy out date */
4795             shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4796             *((u_short *)dptr) = shortTemp;
4797             dptr += 2;
4798
4799             /* copy out file length */
4800             *((u_long *)dptr) = 0;
4801             dptr += 4;
4802         } else {
4803             lock_ConvertWToR(&scp->rw);
4804             attr = smb_Attributes(scp);
4805             /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4806             if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4807                 attr |= SMB_ATTR_HIDDEN;
4808             *dptr++ = attr;
4809
4810             /* get dos time */
4811             cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4812
4813             /* copy out time */
4814             shortTemp = (unsigned short) (dosTime & 0xffff);
4815             *((u_short *)dptr) = shortTemp;
4816             dptr += 2;
4817
4818             /* and copy out date */
4819             shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4820             *((u_short *)dptr) = shortTemp;
4821             dptr += 2;
4822
4823             /* copy out file length */
4824             *((u_long *)dptr) = scp->length.LowPart;
4825             dptr += 4;
4826             lock_ReleaseRead(&scp->rw);
4827         }
4828         cm_ReleaseSCache(scp);
4829     }
4830
4831     /* now free the patches */
4832     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4833         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4834         free(patchp);
4835     }
4836
4837     /* and mark the list as empty */
4838     *dirPatchespp = NULL;
4839
4840   cleanup:
4841     return code;
4842 }
4843
4844 /* SMB_COM_SEARCH */
4845 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4846 {
4847     int attribute;
4848     long nextCookie;
4849     unsigned char *tp;
4850     long code = 0;
4851     clientchar_t *pathp;
4852     cm_dirEntry_t *dep = 0;
4853     int maxCount;
4854     smb_dirListPatch_t *dirListPatchesp;
4855     smb_dirListPatch_t *curPatchp;
4856     int dataLength;
4857     cm_buf_t *bufferp;
4858     long temp;
4859     osi_hyper_t dirLength;
4860     osi_hyper_t bufferOffset;
4861     osi_hyper_t curOffset;
4862     osi_hyper_t thyper;
4863     unsigned char *inCookiep;
4864     smb_dirSearch_t *dsp;
4865     cm_scache_t *scp;
4866     long entryInDir;
4867     long entryInBuffer;
4868     unsigned long clientCookie;
4869     cm_pageHeader_t *pageHeaderp;
4870     cm_user_t *userp = NULL;
4871     int slotInPage;
4872     clientchar_t mask[12];
4873     int returnedNames;
4874     long nextEntryCookie;
4875     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
4876     char resByte;               /* reserved byte from the cookie */
4877     char *op;                   /* output data ptr */
4878     char *origOp;               /* original value of op */
4879     cm_space_t *spacep;         /* for pathname buffer */
4880     int starPattern;
4881     int rootPath = 0;
4882     int caseFold;
4883     clientchar_t *tidPathp = 0;
4884     cm_req_t req;
4885     cm_fid_t fid;
4886     int fileType;
4887
4888     smb_InitReq(&req);
4889
4890     maxCount = smb_GetSMBParm(inp, 0);
4891
4892     dirListPatchesp = NULL;
4893
4894     caseFold = CM_FLAG_CASEFOLD;
4895
4896     tp = smb_GetSMBData(inp, NULL);
4897     pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4898                                 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4899     if (!pathp)
4900         return CM_ERROR_BADSMB;
4901
4902     inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4903     if (!tp)
4904         return CM_ERROR_BADSMB;
4905
4906     /* We can handle long names */
4907     if (vcp->flags & SMB_VCFLAG_USENT)
4908         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4909
4910     /* make sure we got a whole search status */
4911     if (dataLength < 21) {
4912         nextCookie = 0;         /* start at the beginning of the dir */
4913         resByte = 0;
4914         clientCookie = 0;
4915         attribute = smb_GetSMBParm(inp, 1);
4916
4917         /* handle volume info in another function */
4918         if (attribute & 0x8)
4919             return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4920
4921         osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4922                  maxCount, osi_LogSaveClientString(smb_logp, pathp));
4923
4924         if (*pathp == 0) {      /* null pathp, treat as root dir */
4925             if (!(attribute & SMB_ATTR_DIRECTORY))      /* exclude dirs */
4926                 return CM_ERROR_NOFILES;
4927             rootPath = 1;
4928         }
4929
4930         dsp = smb_NewDirSearch(0);
4931         dsp->attribute = attribute;
4932         smb_Get8Dot3MaskFromPath(mask, pathp);
4933         memcpy(dsp->mask, mask, 12);
4934
4935         /* track if this is likely to match a lot of entries */
4936         if (smb_Is8Dot3StarMask(mask))
4937             starPattern = 1;
4938         else
4939             starPattern = 0;
4940     } else {
4941         /* pull the next cookie value out of the search status block */
4942         nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4943             + (inCookiep[16]<<24);
4944         dsp = smb_FindDirSearch(inCookiep[12]);
4945         if (!dsp) {
4946             /* can't find dir search status; fatal error */
4947             osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4948                      inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4949             return CM_ERROR_BADFD;
4950         }
4951         attribute = dsp->attribute;
4952         resByte = inCookiep[0];
4953
4954         /* copy out client cookie, in host byte order.  Don't bother
4955          * interpreting it, since we're just passing it through, anyway.
4956          */
4957         memcpy(&clientCookie, &inCookiep[17], 4);
4958
4959         memcpy(mask, dsp->mask, 12);
4960
4961         /* assume we're doing a star match if it has continued for more
4962          * than one call.
4963          */
4964         starPattern = 1;
4965     }
4966
4967     osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4968              nextCookie, dsp->cookie, attribute);
4969
4970     userp = smb_GetUserFromVCP(vcp, inp);
4971
4972     /* try to get the vnode for the path name next */
4973     lock_ObtainMutex(&dsp->mx);
4974     if (dsp->scp) {
4975         scp = dsp->scp;
4976         osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4977         cm_HoldSCache(scp);
4978         code = 0;
4979     } else {
4980         spacep = inp->spacep;
4981         smb_StripLastComponent(spacep->wdata, NULL, pathp);
4982         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4983         if (code) {
4984             lock_ReleaseMutex(&dsp->mx);
4985             cm_ReleaseUser(userp);
4986             smb_DeleteDirSearch(dsp);
4987             smb_ReleaseDirSearch(dsp);
4988             return CM_ERROR_NOFILES;
4989         }
4990         cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4991         cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4992
4993         code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
4994                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4995         if (code == 0) {
4996 #ifdef DFS_SUPPORT
4997             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4998                 int pnc;
4999
5000                 pnc  = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
5001                 cm_ReleaseSCache(scp);
5002                 lock_ReleaseMutex(&dsp->mx);
5003                 cm_ReleaseUser(userp);
5004                 smb_DeleteDirSearch(dsp);
5005                 smb_ReleaseDirSearch(dsp);
5006                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5007                     return CM_ERROR_PATH_NOT_COVERED;
5008                 else
5009                     return CM_ERROR_NOSUCHPATH;
5010             }
5011 #endif /* DFS_SUPPORT */
5012
5013             dsp->scp = scp;
5014             osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
5015             /* we need one hold for the entry we just stored into,
5016              * and one for our own processing.  When we're done with this
5017              * function, we'll drop the one for our own processing.
5018              * We held it once from the namei call, and so we do another hold
5019              * now.
5020              */
5021             cm_HoldSCache(scp);
5022             lock_ObtainWrite(&scp->rw);
5023             dsp->flags |= SMB_DIRSEARCH_BULKST;
5024             lock_ReleaseWrite(&scp->rw);
5025         }
5026     }
5027     lock_ReleaseMutex(&dsp->mx);
5028     if (code) {
5029         cm_ReleaseUser(userp);
5030         smb_DeleteDirSearch(dsp);
5031         smb_ReleaseDirSearch(dsp);
5032         return code;
5033     }
5034
5035     /* reserves space for parameter; we'll adjust it again later to the
5036      * real count of the # of entries we returned once we've actually
5037      * assembled the directory listing.
5038      */
5039     smb_SetSMBParm(outp, 0, 0);
5040
5041     /* get the directory size */
5042     lock_ObtainWrite(&scp->rw);
5043     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5044                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5045     if (code) {
5046         lock_ReleaseWrite(&scp->rw);
5047         cm_ReleaseSCache(scp);
5048         cm_ReleaseUser(userp);
5049         smb_DeleteDirSearch(dsp);
5050         smb_ReleaseDirSearch(dsp);
5051         return code;
5052     }
5053
5054     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5055
5056     dirLength = scp->length;
5057     bufferp = NULL;
5058     bufferOffset.LowPart = bufferOffset.HighPart = 0;
5059     curOffset.HighPart = 0;
5060     curOffset.LowPart = nextCookie;
5061     origOp = op = smb_GetSMBData(outp, NULL);
5062     /* and write out the basic header */
5063     *op++ = 5;          /* variable block */
5064     op += 2;            /* skip vbl block length; we'll fill it in later */
5065     code = 0;
5066     returnedNames = 0;
5067     while (1) {
5068         clientchar_t *actualName = NULL;
5069         int           free_actualName = 0;
5070         clientchar_t shortName[13];
5071         clientchar_t *shortNameEnd;
5072
5073         /* make sure that curOffset.LowPart doesn't point to the first
5074          * 32 bytes in the 2nd through last dir page, and that it doesn't
5075          * point at the first 13 32-byte chunks in the first dir page,
5076          * since those are dir and page headers, and don't contain useful
5077          * information.
5078          */
5079         temp = curOffset.LowPart & (2048-1);
5080         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5081             /* we're in the first page */
5082             if (temp < 13*32) temp = 13*32;
5083         }
5084         else {
5085             /* we're in a later dir page */
5086             if (temp < 32) temp = 32;
5087         }
5088
5089         /* make sure the low order 5 bits are zero */
5090         temp &= ~(32-1);
5091
5092         /* now put temp bits back ito curOffset.LowPart */
5093         curOffset.LowPart &= ~(2048-1);
5094         curOffset.LowPart |= temp;
5095
5096         /* check if we've returned all the names that will fit in the
5097          * response packet.
5098          */
5099         if (returnedNames >= maxCount) {
5100             osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
5101                       returnedNames, maxCount);
5102             break;
5103         }
5104
5105         /* check if we've passed the dir's EOF */
5106         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
5107
5108         /* see if we can use the bufferp we have now; compute in which page
5109          * the current offset would be, and check whether that's the offset
5110          * of the buffer we have.  If not, get the buffer.
5111          */
5112         thyper.HighPart = curOffset.HighPart;
5113         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5114         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5115             /* wrong buffer */
5116             if (bufferp) {
5117                 buf_Release(bufferp);
5118                 bufferp = NULL;
5119             }
5120             lock_ReleaseWrite(&scp->rw);
5121             code = buf_Get(scp, &thyper, &req, 0, &bufferp);
5122             lock_ObtainMutex(&dsp->mx);
5123
5124             /* now, if we're doing a star match, do bulk fetching of all of
5125              * the status info for files in the dir.
5126              */
5127             if (starPattern)
5128                 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5129
5130             lock_ObtainWrite(&scp->rw);
5131             lock_ReleaseMutex(&dsp->mx);
5132             if (code) {
5133                 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
5134                 break;
5135             }
5136
5137             bufferOffset = thyper;
5138
5139             /* now get the data in the cache */
5140             while (1) {
5141                 code = cm_SyncOp(scp, bufferp, userp, &req,
5142                                  PRSFS_LOOKUP,
5143                                  CM_SCACHESYNC_NEEDCALLBACK |
5144                                  CM_SCACHESYNC_READ);
5145                 if (code) {
5146                     osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5147                     break;
5148                 }
5149
5150                 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5151
5152                 if (cm_HaveBuffer(scp, bufferp, 0)) {
5153                     osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5154                     break;
5155                 }
5156
5157                 /* otherwise, load the buffer and try again */
5158                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5159                 if (code) {
5160                     osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5161                               scp, bufferp, code);
5162                     break;
5163                 }
5164             }
5165             if (code) {
5166                 buf_Release(bufferp);
5167                 bufferp = NULL;
5168                 break;
5169             }
5170         }       /* if (wrong buffer) ... */
5171
5172         /* now we have the buffer containing the entry we're interested in; copy
5173          * it out if it represents a non-deleted entry.
5174          */
5175         entryInDir = curOffset.LowPart & (2048-1);
5176         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5177
5178         /* page header will help tell us which entries are free.  Page header
5179          * can change more often than once per buffer, since AFS 3 dir page size
5180          * may be less than (but not more than a buffer package buffer.
5181          */
5182         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);  /* only look intra-buffer */
5183         temp &= ~(2048 - 1);    /* turn off intra-page bits */
5184         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5185
5186         /* now determine which entry we're looking at in the page.  If it is
5187          * free (there's a free bitmap at the start of the dir), we should
5188          * skip these 32 bytes.
5189          */
5190         slotInPage = (entryInDir & 0x7e0) >> 5;
5191         if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5192             /* this entry is free */
5193             numDirChunks = 1;           /* only skip this guy */
5194             goto nextEntry;
5195         }
5196
5197         tp = bufferp->datap + entryInBuffer;
5198         dep = (cm_dirEntry_t *) tp;             /* now points to AFS3 dir entry */
5199
5200         /* while we're here, compute the next entry's location, too,
5201          * since we'll need it when writing out the cookie into the dir
5202          * listing stream.
5203          *
5204          * XXXX Probably should do more sanity checking.
5205          */
5206         numDirChunks = cm_NameEntries(dep->name, NULL);
5207
5208         /* compute the offset of the cookie representing the next entry */
5209         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5210
5211         /* Compute 8.3 name if necessary */
5212         actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5213         if (dep->fid.vnode != 0 && cm_shortNames && !cm_Is8Dot3(actualName)) {
5214             if (actualName)
5215                 free(actualName);
5216             cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5217             actualName = shortName;
5218             free_actualName = 0;
5219         } else {
5220             free_actualName = 1;
5221         }
5222
5223         if (actualName == NULL) {
5224             /* Couldn't convert the name for some reason */
5225             osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5226                      osi_LogSaveString(smb_logp, dep->name));
5227             goto nextEntry;
5228         }
5229
5230         osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5231                  dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5232                  osi_LogSaveClientString(smb_logp, actualName));
5233
5234         if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5235             /* this is one of the entries to use: it is not deleted
5236              * and it matches the star pattern we're looking for.
5237              */
5238
5239             /* Eliminate entries that don't match requested
5240              * attributes */
5241
5242             /* no hidden files */
5243             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5244                 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5245                 goto nextEntry;
5246             }
5247
5248             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
5249             {
5250                 /* We have already done the cm_TryBulkStat above */
5251                 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5252                 fileType = cm_FindFileType(&fid);
5253                 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5254                          "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5255                           fileType);
5256                 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5257                     fileType == CM_SCACHETYPE_MOUNTPOINT ||
5258                     fileType == CM_SCACHETYPE_DFSLINK ||
5259                     fileType == CM_SCACHETYPE_INVALID)
5260                     osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5261                 goto nextEntry;
5262             }
5263
5264             *op++ = resByte;
5265             memcpy(op, mask, 11); op += 11;
5266             *op++ = (unsigned char) dsp->cookie;        /* they say it must be non-zero */
5267             *op++ = (unsigned char)(nextEntryCookie & 0xff);
5268             *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5269             *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5270             *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5271             memcpy(op, &clientCookie, 4); op += 4;
5272
5273             /* now we emit the attribute.  This is sort of tricky,
5274              * since we need to really stat the file to find out
5275              * what type of entry we've got.  Right now, we're
5276              * copying out data from a buffer, while holding the
5277              * scp locked, so it isn't really convenient to stat
5278              * something now.  We'll put in a place holder now,
5279              * and make a second pass before returning this to get
5280              * the real attributes.  So, we just skip the data for
5281              * now, and adjust it later.  We allocate a patch
5282              * record to make it easy to find this point later.
5283              * The replay will happen at a time when it is safe to
5284              * unlock the directory.
5285              */
5286             curPatchp = malloc(sizeof(*curPatchp));
5287             osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5288             curPatchp->dptr = op;
5289             cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5290
5291             /* do hidden attribute here since name won't be around when applying
5292              * dir list patches
5293              */
5294
5295             if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5296                 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5297             else
5298                 curPatchp->flags = 0;
5299
5300             op += 9;    /* skip attr, time, date and size */
5301
5302             /* zero out name area.  The spec says to pad with
5303              * spaces, but Samba doesn't, and neither do we.
5304              */
5305             memset(op, 0, 13);
5306
5307             /* finally, we get to copy out the name; we know that
5308              * it fits in 8.3 or the pattern wouldn't match, but it
5309              * never hurts to be sure.
5310              */
5311             cm_ClientStringToUtf8(actualName, -1, op, 13);
5312             if (smb_StoreAnsiFilenames)
5313                 CharToOem(op, op);
5314             /* This is a UCHAR field, which is ASCII even if Unicode
5315                is negotiated. */
5316
5317             /* Uppercase if requested by client */
5318             if (!KNOWS_LONG_NAMES(inp))
5319                 _strupr(op);
5320
5321             op += 13;
5322
5323             /* now, adjust the # of entries copied */
5324             returnedNames++;
5325         }       /* if we're including this name */
5326
5327       nextEntry:
5328         if (free_actualName && actualName) {
5329             free(actualName);
5330             actualName = NULL;
5331         }
5332
5333         /* and adjust curOffset to be where the new cookie is */
5334         thyper.HighPart = 0;
5335         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5336         curOffset = LargeIntegerAdd(thyper, curOffset);
5337     }           /* while copying data for dir listing */
5338
5339     /* release the mutex */
5340     lock_ReleaseWrite(&scp->rw);
5341     if (bufferp) {
5342         buf_Release(bufferp);
5343         bufferp = NULL;
5344     }
5345
5346     /* apply and free last set of patches; if not doing a star match, this
5347      * will be empty, but better safe (and freeing everything) than sorry.
5348      */
5349     smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5350
5351     /* special return code for unsuccessful search */
5352     if (code == 0 && dataLength < 21 && returnedNames == 0)
5353         code = CM_ERROR_NOFILES;
5354
5355     osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5356              returnedNames, code);
5357
5358     if (code != 0) {
5359         smb_DeleteDirSearch(dsp);
5360         smb_ReleaseDirSearch(dsp);
5361         cm_ReleaseSCache(scp);
5362         cm_ReleaseUser(userp);
5363         return code;
5364     }
5365
5366     /* finalize the output buffer */
5367     smb_SetSMBParm(outp, 0, returnedNames);
5368     temp = (long) (op - origOp);
5369     smb_SetSMBDataLength(outp, temp);
5370
5371     /* the data area is a variable block, which has a 5 (already there)
5372      * followed by the length of the # of data bytes.  We now know this to
5373      * be "temp," although that includes the 3 bytes of vbl block header.
5374      * Deduct for them and fill in the length field.
5375      */
5376     temp -= 3;          /* deduct vbl block info */
5377     osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5378     origOp[1] = (unsigned char)(temp & 0xff);
5379     origOp[2] = (unsigned char)((temp>>8) & 0xff);
5380     if (returnedNames == 0)
5381         smb_DeleteDirSearch(dsp);
5382     smb_ReleaseDirSearch(dsp);
5383     cm_ReleaseSCache(scp);
5384     cm_ReleaseUser(userp);
5385     return code;
5386 }
5387
5388
5389 /* verify that this is a valid path to a directory.  I don't know why they
5390  * don't use the get file attributes call.
5391  *
5392  * SMB_COM_CHECK_DIRECTORY
5393  */
5394 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5395 {
5396     clientchar_t *pathp;
5397     long code = 0;
5398     cm_scache_t *rootScp;
5399     cm_scache_t *newScp;
5400     cm_user_t *userp;
5401     unsigned int attrs;
5402     int caseFold;
5403     clientchar_t *tidPathp;
5404     cm_req_t req;
5405     char * pdata;
5406
5407     smb_InitReq(&req);
5408
5409     pdata = smb_GetSMBData(inp, NULL);
5410     pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5411     if (!pathp)
5412         return CM_ERROR_BADSMB;
5413     osi_Log1(smb_logp, "SMB receive check path %S",
5414              osi_LogSaveClientString(smb_logp, pathp));
5415
5416     userp = smb_GetUserFromVCP(vcp, inp);
5417
5418     rootScp = cm_RootSCachep(userp, &req);
5419
5420     caseFold = CM_FLAG_CASEFOLD;
5421
5422     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5423     if (code) {
5424         cm_ReleaseUser(userp);
5425         return CM_ERROR_NOSUCHPATH;
5426     }
5427     code = cm_NameI(rootScp, pathp,
5428                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5429                     userp, tidPathp, &req, &newScp);
5430
5431     if (code) {
5432         cm_ReleaseUser(userp);
5433         return code;
5434     }
5435
5436 #ifdef DFS_SUPPORT
5437     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5438         int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5439         cm_ReleaseSCache(newScp);
5440         cm_ReleaseUser(userp);
5441         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5442             return CM_ERROR_PATH_NOT_COVERED;
5443         else
5444             return CM_ERROR_NOSUCHPATH;
5445     }
5446 #endif /* DFS_SUPPORT */
5447
5448     /* now lock the vnode with a callback; returns with newScp locked */
5449     lock_ObtainWrite(&newScp->rw);
5450     code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5451                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5452     if (code) {
5453         if (code != CM_ERROR_NOACCESS) {
5454             lock_ReleaseWrite(&newScp->rw);
5455             cm_ReleaseSCache(newScp);
5456             cm_ReleaseUser(userp);
5457             return code;
5458         }
5459     } else {
5460         cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5461     }
5462
5463     attrs = smb_Attributes(newScp);
5464
5465     if (!(attrs & SMB_ATTR_DIRECTORY))
5466         code = CM_ERROR_NOTDIR;
5467
5468     lock_ReleaseWrite(&newScp->rw);
5469
5470     cm_ReleaseSCache(newScp);
5471     cm_ReleaseUser(userp);
5472     return code;
5473 }
5474
5475 /* SMB_COM_SET_INFORMATION */
5476 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5477 {
5478     clientchar_t *pathp;
5479     long code = 0;
5480     cm_scache_t *rootScp;
5481     unsigned short attribute;
5482     cm_attr_t attr;
5483     cm_scache_t *newScp;
5484     afs_uint32 dosTime;
5485     cm_user_t *userp;
5486     int caseFold;
5487     clientchar_t *tidPathp;
5488     char * datap;
5489     cm_req_t req;
5490
5491     smb_InitReq(&req);
5492
5493     /* decode basic attributes we're passed */
5494     attribute = smb_GetSMBParm(inp, 0);
5495     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5496
5497     datap = smb_GetSMBData(inp, NULL);
5498     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5499     if (!pathp)
5500         return CM_ERROR_BADSMB;
5501
5502     osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5503              dosTime, attribute);
5504
5505     userp = smb_GetUserFromVCP(vcp, inp);
5506
5507     rootScp = cm_RootSCachep(userp, &req);
5508
5509     caseFold = CM_FLAG_CASEFOLD;
5510
5511     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5512     if (code) {
5513         cm_ReleaseUser(userp);
5514         return CM_ERROR_NOSUCHFILE;
5515     }
5516     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5517                     tidPathp, &req, &newScp);
5518
5519     if (code) {
5520         cm_ReleaseUser(userp);
5521         return code;
5522     }
5523
5524 #ifdef DFS_SUPPORT
5525     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5526         int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5527         cm_ReleaseSCache(newScp);
5528         cm_ReleaseUser(userp);
5529         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5530             return CM_ERROR_PATH_NOT_COVERED;
5531         else
5532             return CM_ERROR_NOSUCHPATH;
5533     }
5534 #endif /* DFS_SUPPORT */
5535
5536     /* now lock the vnode with a callback; returns with newScp locked; we
5537      * need the current status to determine what the new status is, in some
5538      * cases.
5539      */
5540     lock_ObtainWrite(&newScp->rw);
5541     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5542                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5543     if (code) {
5544         lock_ReleaseWrite(&newScp->rw);
5545         cm_ReleaseSCache(newScp);
5546         cm_ReleaseUser(userp);
5547         return code;
5548     }
5549
5550     cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5551
5552     /* Check for RO volume */
5553     if (newScp->flags & CM_SCACHEFLAG_RO) {
5554         lock_ReleaseWrite(&newScp->rw);
5555         cm_ReleaseSCache(newScp);
5556         cm_ReleaseUser(userp);
5557         return CM_ERROR_READONLY;
5558     }
5559
5560     /* prepare for setattr call */
5561     attr.mask = 0;
5562     if (dosTime != 0) {
5563         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5564         smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5565     }
5566     if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5567         /* we're told to make a writable file read-only */
5568         attr.unixModeBits = newScp->unixModeBits & ~0222;
5569         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5570     }
5571     else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5572         /* we're told to make a read-only file writable */
5573         attr.unixModeBits = newScp->unixModeBits | 0222;
5574         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5575     }
5576     lock_ReleaseWrite(&newScp->rw);
5577
5578     /* now call setattr */
5579     if (attr.mask)
5580         code = cm_SetAttr(newScp, &attr, userp, &req);
5581     else
5582         code = 0;
5583
5584     cm_ReleaseSCache(newScp);
5585     cm_ReleaseUser(userp);
5586
5587     return code;
5588 }
5589
5590
5591 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5592 {
5593     clientchar_t *pathp;
5594     long code = 0;
5595     cm_scache_t *rootScp;
5596     cm_scache_t *newScp, *dscp;
5597     afs_uint32 dosTime;
5598     int attrs;
5599     cm_user_t *userp;
5600     int caseFold;
5601     clientchar_t *tidPathp;
5602     cm_space_t *spacep;
5603     clientchar_t *lastComp;
5604     char * datap;
5605     cm_req_t req;
5606
5607     smb_InitReq(&req);
5608
5609     datap = smb_GetSMBData(inp, NULL);
5610     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5611     if (!pathp)
5612         return CM_ERROR_BADSMB;
5613
5614     if (*pathp == 0)            /* null path */
5615         pathp = _C("\\");
5616
5617     osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5618              osi_LogSaveClientString(smb_logp, pathp));
5619
5620     userp = smb_GetUserFromVCP(vcp, inp);
5621
5622     rootScp = cm_RootSCachep(userp, &req);
5623
5624     /* we shouldn't need this for V3 requests, but we seem to */
5625     caseFold = CM_FLAG_CASEFOLD;
5626
5627     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5628     if (code) {
5629         cm_ReleaseUser(userp);
5630         return CM_ERROR_NOSUCHFILE;
5631     }
5632
5633     /*
5634      * XXX Strange hack XXX
5635      *
5636      * As of Patch 5 (16 July 97), we are having the following problem:
5637      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5638      * requests to look up "desktop.ini" in all the subdirectories.
5639      * This can cause zillions of timeouts looking up non-existent cells
5640      * and volumes, especially in the top-level directory.
5641      *
5642      * We have not found any way to avoid this or work around it except
5643      * to explicitly ignore the requests for mount points that haven't
5644      * yet been evaluated and for directories that haven't yet been
5645      * fetched.
5646      *
5647      * We should modify this hack to provide a fake desktop.ini file
5648      * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5649      */
5650     spacep = inp->spacep;
5651     smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5652 #ifndef SPECIAL_FOLDERS
5653     if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5654         code = cm_NameI(rootScp, spacep->wdata,
5655                         caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5656                         userp, tidPathp, &req, &dscp);
5657         if (code == 0) {
5658 #ifdef DFS_SUPPORT
5659             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5660                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5661                                                           spacep->wdata);
5662                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5663                     return CM_ERROR_PATH_NOT_COVERED;
5664                 else
5665                     return CM_ERROR_NOSUCHPATH;
5666             } else
5667 #endif /* DFS_SUPPORT */
5668             if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5669                 code = CM_ERROR_NOSUCHFILE;
5670             else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5671                 cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
5672                 if (bp) {
5673                     buf_Release(bp);
5674                     bp = NULL;
5675                 } else
5676                     code = CM_ERROR_NOSUCHFILE;
5677             }
5678             cm_ReleaseSCache(dscp);
5679             if (code) {
5680                 cm_ReleaseUser(userp);
5681                 return code;
5682             }
5683         }
5684         else if (code != CM_ERROR_NOSUCHFILE &&
5685                  code != CM_ERROR_NOSUCHPATH &&
5686                  code != CM_ERROR_BPLUS_NOMATCH)
5687         {
5688             cm_ReleaseUser(userp);
5689             return code;
5690         }
5691     }
5692 #endif /* SPECIAL_FOLDERS */
5693
5694     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5695                     tidPathp, &req, &newScp);
5696     if (code) {
5697         cm_ReleaseUser(userp);
5698         return code;
5699     }
5700
5701 #ifdef DFS_SUPPORT
5702     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5703         int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5704         cm_ReleaseSCache(newScp);
5705         cm_ReleaseUser(userp);
5706         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5707             return CM_ERROR_PATH_NOT_COVERED;
5708         else
5709             return CM_ERROR_NOSUCHPATH;
5710     }
5711 #endif /* DFS_SUPPORT */
5712
5713     /* now lock the vnode with a callback; returns with newScp locked */
5714     lock_ObtainWrite(&newScp->rw);
5715     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5716                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5717     if (code) {
5718         lock_ReleaseWrite(&newScp->rw);
5719         cm_ReleaseSCache(newScp);
5720         cm_ReleaseUser(userp);
5721         return code;
5722     }
5723
5724     cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5725
5726     attrs = smb_Attributes(newScp);
5727
5728     smb_SetSMBParm(outp, 0, attrs);
5729
5730     smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5731     smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5732     smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5733     smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5734     smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5735     smb_SetSMBParm(outp, 5, 0);
5736     smb_SetSMBParm(outp, 6, 0);
5737     smb_SetSMBParm(outp, 7, 0);
5738     smb_SetSMBParm(outp, 8, 0);
5739     smb_SetSMBParm(outp, 9, 0);
5740     smb_SetSMBDataLength(outp, 0);
5741     lock_ReleaseWrite(&newScp->rw);
5742
5743     cm_ReleaseSCache(newScp);
5744     cm_ReleaseUser(userp);
5745
5746     return 0;
5747 }
5748
5749 /* SMB_COM_TREE_DISCONNECT */
5750 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5751 {
5752     smb_tid_t *tidp;
5753
5754     osi_Log0(smb_logp, "SMB receive tree disconnect");
5755
5756     /* find the tree and free it */
5757     tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5758     if (tidp) {
5759         lock_ObtainWrite(&smb_rctLock);
5760         tidp->deleteOk = 1;
5761         smb_ReleaseTID(tidp, TRUE);
5762         lock_ReleaseWrite(&smb_rctLock);
5763     }
5764
5765     return 0;
5766 }
5767
5768 /* SMB_COM_0PEN */
5769 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5770 {
5771     smb_fid_t *fidp;
5772     clientchar_t *pathp;
5773     clientchar_t *lastNamep;
5774     int share;
5775     int attribute;
5776     long code = 0;
5777     cm_user_t *userp;
5778     cm_scache_t *scp;
5779     afs_uint32 dosTime;
5780     int caseFold;
5781     cm_space_t *spacep;
5782     clientchar_t *tidPathp;
5783     char * datap;
5784     cm_req_t req;
5785
5786     smb_InitReq(&req);
5787
5788     datap = smb_GetSMBData(inp, NULL);
5789     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5790     if (!pathp)
5791         return CM_ERROR_BADSMB;
5792
5793     osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5794
5795 #ifdef DEBUG_VERBOSE
5796     {
5797         char *hexpath;
5798
5799         hexpath = osi_HexifyString( pathp );
5800         DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5801         free(hexpath);
5802     }
5803 #endif
5804
5805     share = smb_GetSMBParm(inp, 0);
5806     attribute = smb_GetSMBParm(inp, 1);
5807
5808     spacep = inp->spacep;
5809     /* smb_StripLastComponent will strip "::$DATA" if present */
5810     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5811
5812     if (!cm_IsValidClientString(pathp)) {
5813 #ifdef DEBUG
5814         clientchar_t * hexp;
5815
5816         hexp = cm_GetRawCharsAlloc(pathp, -1);
5817         osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5818                  osi_LogSaveClientString(smb_logp, hexp));
5819         if (hexp)
5820             free(hexp);
5821 #else
5822         osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5823 #endif
5824         return CM_ERROR_BADNTFILENAME;
5825     }
5826
5827     if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5828         /* special case magic file name for receiving IOCTL requests
5829          * (since IOCTL calls themselves aren't getting through).
5830          */
5831         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5832         smb_SetupIoctlFid(fidp, spacep);
5833         smb_SetSMBParm(outp, 0, fidp->fid);
5834         smb_SetSMBParm(outp, 1, 0);     /* attrs */
5835         smb_SetSMBParm(outp, 2, 0);     /* next 2 are DOS time */
5836         smb_SetSMBParm(outp, 3, 0);
5837         smb_SetSMBParm(outp, 4, 0);     /* next 2 are length */
5838         smb_SetSMBParm(outp, 5, 0x7fff);
5839         /* pass the open mode back */
5840         smb_SetSMBParm(outp, 6, (share & 0xf));
5841         smb_SetSMBDataLength(outp, 0);
5842         smb_ReleaseFID(fidp);
5843         return 0;
5844     }
5845
5846     userp = smb_GetUserFromVCP(vcp, inp);
5847
5848     caseFold = CM_FLAG_CASEFOLD;
5849
5850     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5851     if (code) {
5852         cm_ReleaseUser(userp);
5853         return CM_ERROR_NOSUCHPATH;
5854     }
5855     code = cm_NameI(cm_RootSCachep(userp, &req), pathp, caseFold | CM_FLAG_FOLLOW, userp,
5856                     tidPathp, &req, &scp);
5857
5858     if (code) {
5859         cm_ReleaseUser(userp);
5860         return code;
5861     }
5862
5863 #ifdef DFS_SUPPORT
5864     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5865         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5866         cm_ReleaseSCache(scp);
5867         cm_ReleaseUser(userp);
5868         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5869             return CM_ERROR_PATH_NOT_COVERED;
5870         else
5871             return CM_ERROR_NOSUCHPATH;
5872     }
5873 #endif /* DFS_SUPPORT */
5874
5875     code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5876     if (code) {
5877         cm_ReleaseSCache(scp);
5878         cm_ReleaseUser(userp);
5879         return code;
5880     }
5881
5882     /* don't need callback to check file type, since file types never
5883      * change, and namei and cm_Lookup all stat the object at least once on
5884      * a successful return.
5885      */
5886     if (scp->fileType != CM_SCACHETYPE_FILE) {
5887         cm_ReleaseSCache(scp);
5888         cm_ReleaseUser(userp);
5889         return CM_ERROR_ISDIR;
5890     }
5891
5892     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5893     osi_assertx(fidp, "null smb_fid_t");
5894
5895     lock_ObtainMutex(&fidp->mx);
5896     if ((share & 0xf) == 0)
5897         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5898     else if ((share & 0xf) == 1)
5899         fidp->flags |= SMB_FID_OPENWRITE;
5900     else
5901         fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5902
5903     /* save the  user */
5904     cm_HoldUser(userp);
5905     fidp->userp = userp;
5906
5907     /* and a pointer to the vnode */
5908     fidp->scp = scp;
5909     osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5910     lock_ObtainWrite(&scp->rw);
5911     scp->flags |= CM_SCACHEFLAG_SMB_FID;
5912
5913     smb_SetSMBParm(outp, 0, fidp->fid);
5914     smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5915     smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5916     smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5917     smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5918     smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5919     smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5920     /* pass the open mode back; XXXX add access checks */
5921     smb_SetSMBParm(outp, 6, (share & 0xf));
5922     smb_SetSMBDataLength(outp, 0);
5923         lock_ReleaseMutex(&fidp->mx);
5924     lock_ReleaseRead(&scp->rw);
5925
5926     /* notify open */
5927     cm_Open(scp, 0, userp);
5928
5929     /* send and free packet */
5930     smb_ReleaseFID(fidp);
5931     cm_ReleaseUser(userp);
5932     /* don't release scp, since we've squirreled away the pointer in the fid struct */
5933     return 0;
5934 }
5935
5936 typedef struct smb_unlinkRock {
5937     cm_scache_t *dscp;
5938     cm_user_t *userp;
5939     cm_req_t *reqp;
5940     smb_vc_t *vcp;
5941     clientchar_t *maskp;                /* pointer to the star pattern */
5942     int flags;
5943     int any;
5944     cm_dirEntryList_t * matches;
5945 } smb_unlinkRock_t;
5946
5947 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5948 {
5949     long code = 0;
5950     smb_unlinkRock_t *rockp;
5951     int caseFold;
5952     int match;
5953     normchar_t matchName[MAX_PATH];
5954
5955     rockp = vrockp;
5956
5957     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5958     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5959         caseFold |= CM_FLAG_8DOT3;
5960
5961     if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5962         /* Can't convert name */
5963         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5964                  osi_LogSaveString(smb_logp, dep->name));
5965         return 0;
5966     }
5967
5968     match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5969     if (!match &&
5970         (rockp->flags & SMB_MASKFLAG_TILDE) &&
5971         cm_shortNames &&
5972         !cm_Is8Dot3(matchName)) {
5973         cm_Gen8Dot3Name(dep, matchName, NULL);
5974         /* 8.3 matches are always case insensitive */
5975         match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5976     }
5977     if (match) {
5978         osi_Log1(smb_logp, "Found match %S",
5979                  osi_LogSaveClientString(smb_logp, matchName));
5980
5981         cm_DirEntryListAdd(dep->name, &rockp->matches);
5982
5983         rockp->any = 1;
5984
5985         /* If we made a case sensitive exact match, we might as well quit now. */
5986         if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5987             code = CM_ERROR_STOPNOW;
5988         else
5989             code = 0;
5990     }
5991     else code = 0;
5992
5993     return code;
5994 }
5995
5996 /* SMB_COM_DELETE */
5997 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5998 {
5999     int attribute;
6000     long code = 0;
6001     clientchar_t *pathp;
6002     unsigned char *tp;
6003     cm_space_t *spacep;
6004     cm_scache_t *dscp;
6005     clientchar_t *lastNamep;
6006     smb_unlinkRock_t rock;
6007     cm_user_t *userp;
6008     osi_hyper_t thyper;
6009     int caseFold;
6010     clientchar_t *tidPathp;
6011     cm_req_t req;
6012
6013     smb_InitReq(&req);
6014     memset(&rock, 0, sizeof(rock));
6015
6016     attribute = smb_GetSMBParm(inp, 0);
6017
6018     tp = smb_GetSMBData(inp, NULL);
6019     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6020     if (!pathp)
6021         return CM_ERROR_BADSMB;
6022
6023     osi_Log1(smb_logp, "SMB receive unlink %S",
6024              osi_LogSaveClientString(smb_logp, pathp));
6025
6026     spacep = inp->spacep;
6027     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6028
6029     userp = smb_GetUserFromVCP(vcp, inp);
6030
6031     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6032
6033     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6034     if (code) {
6035         cm_ReleaseUser(userp);
6036         return CM_ERROR_NOSUCHPATH;
6037     }
6038     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold, userp, tidPathp,
6039                     &req, &dscp);
6040     if (code) {
6041         cm_ReleaseUser(userp);
6042         return code;
6043     }
6044
6045 #ifdef DFS_SUPPORT
6046     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6047         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6048         cm_ReleaseSCache(dscp);
6049         cm_ReleaseUser(userp);
6050         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6051             return CM_ERROR_PATH_NOT_COVERED;
6052         else
6053             return CM_ERROR_NOSUCHPATH;
6054     }
6055 #endif /* DFS_SUPPORT */
6056
6057     /* otherwise, scp points to the parent directory. */
6058     if (!lastNamep)
6059         lastNamep = pathp;
6060     else
6061         lastNamep++;
6062
6063     rock.any = 0;
6064     rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
6065     if (!rock.maskp) {
6066         code = CM_ERROR_NOSUCHFILE;
6067         goto done;
6068     }
6069     rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6070
6071     thyper.LowPart = 0;
6072     thyper.HighPart = 0;
6073     rock.userp = userp;
6074     rock.reqp = &req;
6075     rock.dscp = dscp;
6076     rock.vcp = vcp;
6077     rock.matches = NULL;
6078
6079     /* Now, if we aren't dealing with a wildcard match, we first try an exact
6080      * match.  If that fails, we do a case insensitve match.
6081      */
6082     if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
6083         !smb_IsStarMask(rock.maskp)) {
6084         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6085         if (!rock.any) {
6086             thyper.LowPart = 0;
6087             thyper.HighPart = 0;
6088             rock.flags |= SMB_MASKFLAG_CASEFOLD;
6089         }
6090     }
6091
6092     if (!rock.any)
6093         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6094
6095     if (code == CM_ERROR_STOPNOW)
6096         code = 0;
6097
6098     if (code == 0 && rock.matches) {
6099         cm_dirEntryList_t * entry;
6100
6101         for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6102             normchar_t normalizedName[MAX_PATH];
6103
6104             /* Note: entry->name is a non-normalized name */
6105
6106             osi_Log1(smb_logp, "Unlinking %s",
6107                      osi_LogSaveString(smb_logp, entry->name));
6108
6109             /* We assume this works because entry->name was
6110                successfully converted in smb_UnlinkProc() once. */
6111             cm_FsStringToNormString(entry->name, -1,
6112                                     normalizedName, lengthof(normalizedName));
6113
6114             code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
6115
6116             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6117                 smb_NotifyChange(FILE_ACTION_REMOVED,
6118                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6119                                  dscp, normalizedName, NULL, TRUE);
6120         }
6121     }
6122
6123     cm_DirEntryListFree(&rock.matches);
6124
6125   done:
6126     if (userp)
6127     cm_ReleaseUser(userp);
6128
6129     if (dscp)
6130     cm_ReleaseSCache(dscp);
6131
6132     if (rock.maskp)
6133     free(rock.maskp);
6134
6135     if (code == 0 && !rock.any)
6136         code = CM_ERROR_NOSUCHFILE;
6137     return code;
6138 }
6139
6140 typedef struct smb_renameRock {
6141     cm_scache_t *odscp;  /* old dir */
6142     cm_scache_t *ndscp;  /* new dir */
6143     cm_user_t *userp;    /* user */
6144     cm_req_t *reqp;      /* request struct */
6145     smb_vc_t *vcp;       /* virtual circuit */
6146     normchar_t *maskp;   /* pointer to star pattern of old file name */
6147     int flags;           /* tilde, casefold, etc */
6148     clientchar_t *newNamep;     /* ptr to the new file's name */
6149     fschar_t fsOldName[MAX_PATH]; /* raw FS name */
6150     clientchar_t clOldName[MAX_PATH]; /* client name */
6151     int any;
6152 } smb_renameRock_t;
6153
6154 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6155 {
6156     long code = 0;
6157     smb_renameRock_t *rockp;
6158     int caseFold;
6159     int match;
6160     normchar_t matchName[MAX_PATH];
6161
6162     rockp = (smb_renameRock_t *) vrockp;
6163
6164     if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6165         /* Can't convert string */
6166         osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6167                  osi_LogSaveString(smb_logp, dep->name));
6168         return 0;
6169     }
6170
6171     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6172     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6173         caseFold |= CM_FLAG_8DOT3;
6174
6175     match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6176     if (!match &&
6177         (rockp->flags & SMB_MASKFLAG_TILDE) &&
6178         cm_shortNames &&
6179         !cm_Is8Dot3(matchName)) {
6180         cm_Gen8Dot3Name(dep, matchName, NULL);
6181         match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6182     }
6183
6184     if (match) {
6185         rockp->any = 1;
6186         StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6187         cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6188                         matchName);
6189         code = CM_ERROR_STOPNOW;
6190     } else {
6191         code = 0;
6192     }
6193
6194     return code;
6195 }
6196
6197
6198 long
6199 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6200 {
6201     long code = 0;
6202     cm_space_t *spacep = NULL;
6203     smb_renameRock_t rock;
6204     cm_scache_t *oldDscp = NULL;
6205     cm_scache_t *newDscp = NULL;
6206     cm_scache_t *tmpscp= NULL;
6207     cm_scache_t *tmpscp2 = NULL;
6208     clientchar_t *oldLastNamep;
6209     clientchar_t *newLastNamep;
6210     osi_hyper_t thyper;
6211     cm_user_t *userp;
6212     int caseFold;
6213     clientchar_t *tidPathp;
6214     DWORD filter;
6215     cm_req_t req;
6216
6217     userp = smb_GetUserFromVCP(vcp, inp);
6218     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6219     if (code) {
6220         cm_ReleaseUser(userp);
6221         return CM_ERROR_NOSUCHPATH;
6222     }
6223
6224     smb_InitReq(&req);
6225     memset(&rock, 0, sizeof(rock));
6226
6227     spacep = inp->spacep;
6228     smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6229
6230     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6231     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6232                     userp, tidPathp, &req, &oldDscp);
6233     if (code) {
6234         cm_ReleaseUser(userp);
6235         return code;
6236     }
6237
6238 #ifdef DFS_SUPPORT
6239     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6240         int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6241         cm_ReleaseSCache(oldDscp);
6242         cm_ReleaseUser(userp);
6243         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6244             return CM_ERROR_PATH_NOT_COVERED;
6245         else
6246             return CM_ERROR_NOSUCHPATH;
6247     }
6248 #endif /* DFS_SUPPORT */
6249
6250     smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6251     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6252                     userp, tidPathp, &req, &newDscp);
6253
6254     if (code) {
6255         cm_ReleaseSCache(oldDscp);
6256         cm_ReleaseUser(userp);
6257         return code;
6258     }
6259
6260 #ifdef DFS_SUPPORT
6261     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6262         int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6263         cm_ReleaseSCache(oldDscp);
6264         cm_ReleaseSCache(newDscp);
6265         cm_ReleaseUser(userp);
6266         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6267             return CM_ERROR_PATH_NOT_COVERED;
6268         else
6269             return CM_ERROR_NOSUCHPATH;
6270     }
6271 #endif /* DFS_SUPPORT */
6272
6273
6274     /* otherwise, oldDscp and newDscp point to the corresponding directories.
6275      * next, get the component names, and lower case them.
6276      */
6277
6278     /* handle the old name first */
6279     if (!oldLastNamep)
6280         oldLastNamep = oldPathp;
6281     else
6282         oldLastNamep++;
6283
6284     /* and handle the new name, too */
6285     if (!newLastNamep)
6286         newLastNamep = newPathp;
6287     else
6288         newLastNamep++;
6289
6290     /* TODO: The old name could be a wildcard.  The new name must not be */
6291
6292     /* Check if the file already exists; if so return error */
6293     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6294     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6295         (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6296     {
6297         osi_Log2(smb_logp, "  lookup returns %ld for [%S]", code,
6298                  osi_LogSaveClientString(smb_logp, newLastNamep));
6299
6300         /* Check if the old and the new names differ only in case. If so return
6301          * success, else return CM_ERROR_EXISTS
6302          */
6303         if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6304
6305             /* This would be a success only if the old file is *as same as* the new file */
6306             code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6307             if (!code) {
6308                 if (tmpscp == tmpscp2)
6309                     code = 0;
6310                 else
6311                     code = CM_ERROR_EXISTS;
6312                 cm_ReleaseSCache(tmpscp2);
6313                 tmpscp2 = NULL;
6314             } else {
6315                 code = CM_ERROR_NOSUCHFILE;
6316             }
6317         } else {
6318             /* file exist, do not rename, also fixes move */
6319             osi_Log0(smb_logp, "Can't rename.  Target already exists");
6320             code = CM_ERROR_EXISTS;
6321         }
6322         goto done;
6323     }
6324
6325     /* do the vnode call */
6326     rock.odscp = oldDscp;
6327     rock.ndscp = newDscp;
6328     rock.userp = userp;
6329     rock.reqp = &req;
6330     rock.vcp = vcp;
6331     rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6332     if (!rock.maskp) {
6333         code = CM_ERROR_NOSUCHFILE;
6334         goto done;
6335     }
6336     rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6337     rock.newNamep = newLastNamep;
6338     rock.fsOldName[0] = '\0';
6339     rock.clOldName[0] = '\0';
6340     rock.any = 0;
6341
6342     /* Now search the directory for the pattern, and do the appropriate rename when found */
6343     thyper.LowPart = 0;         /* search dir from here */
6344     thyper.HighPart = 0;
6345
6346     code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6347     if (code == 0 && !rock.any) {
6348         thyper.LowPart = 0;
6349         thyper.HighPart = 0;
6350         rock.flags |= SMB_MASKFLAG_CASEFOLD;
6351         code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6352     }
6353     osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6354
6355     if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6356         code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6357                          rock.ndscp, rock.newNamep, rock.userp,
6358                          rock.reqp);
6359         /* if the call worked, stop doing the search now, since we
6360          * really only want to rename one file.
6361          */
6362     if (code)
6363         osi_Log0(smb_logp, "cm_Rename failure");
6364         osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6365     } else if (code == 0) {
6366         code = CM_ERROR_NOSUCHFILE;
6367     }
6368
6369     /* Handle Change Notification */
6370     /*
6371     * Being lazy, not distinguishing between files and dirs in this
6372     * filter, since we'd have to do a lookup.
6373     */
6374     if (code == 0) {
6375         filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6376         if (oldDscp == newDscp) {
6377             if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6378                 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6379                                  filter, oldDscp, rock.clOldName,
6380                                  newLastNamep, TRUE);
6381         } else {
6382             if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6383                 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6384                                   filter, oldDscp, rock.clOldName,
6385                                   NULL, TRUE);
6386             if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6387                 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6388                                  filter, newDscp, newLastNamep,
6389                                  NULL, TRUE);
6390         }
6391     }
6392
6393   done:
6394     if (tmpscp != NULL)
6395         cm_ReleaseSCache(tmpscp);
6396     if (userp)
6397         cm_ReleaseUser(userp);
6398     if (oldDscp)
6399         cm_ReleaseSCache(oldDscp);
6400     if (newDscp)
6401         cm_ReleaseSCache(newDscp);
6402     if (rock.maskp)
6403         free(rock.maskp);
6404
6405     return code;
6406 }
6407
6408 long
6409 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6410 {
6411     long code = 0;
6412     cm_space_t *spacep = NULL;
6413     cm_scache_t *oldDscp = NULL;
6414     cm_scache_t *newDscp = NULL;
6415     cm_scache_t *tmpscp= NULL;
6416     cm_scache_t *tmpscp2 = NULL;
6417     cm_scache_t *sscp = NULL;
6418     clientchar_t *oldLastNamep;
6419     clientchar_t *newLastNamep;
6420     cm_user_t *userp;
6421     int caseFold;
6422     clientchar_t *tidPathp;
6423     DWORD filter;
6424     cm_req_t req;
6425
6426     userp = smb_GetUserFromVCP(vcp, inp);
6427
6428     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6429     if (code) {
6430         cm_ReleaseUser(userp);
6431         return CM_ERROR_NOSUCHPATH;
6432     }
6433
6434     smb_InitReq(&req);
6435
6436     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6437
6438     spacep = inp->spacep;
6439     smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6440
6441     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6442                     userp, tidPathp, &req, &oldDscp);
6443     if (code) {
6444         cm_ReleaseUser(userp);
6445         return code;
6446     }
6447
6448 #ifdef DFS_SUPPORT
6449     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6450         int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6451         cm_ReleaseSCache(oldDscp);
6452         cm_ReleaseUser(userp);
6453         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6454             return CM_ERROR_PATH_NOT_COVERED;
6455         else
6456             return CM_ERROR_NOSUCHPATH;
6457     }
6458 #endif /* DFS_SUPPORT */
6459
6460     smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6461     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6462                     userp, tidPathp, &req, &newDscp);
6463     if (code) {
6464         cm_ReleaseSCache(oldDscp);
6465         cm_ReleaseUser(userp);
6466         return code;
6467     }
6468
6469 #ifdef DFS_SUPPORT
6470     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6471         int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6472         cm_ReleaseSCache(newDscp);
6473         cm_ReleaseSCache(oldDscp);
6474         cm_ReleaseUser(userp);
6475         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6476             return CM_ERROR_PATH_NOT_COVERED;
6477         else
6478             return CM_ERROR_NOSUCHPATH;
6479     }
6480 #endif /* DFS_SUPPORT */
6481
6482     /* Now, although we did two lookups for the two directories (because the same
6483      * directory can be referenced through different paths), we only allow hard links
6484      * within the same directory. */
6485     if (oldDscp != newDscp) {
6486         cm_ReleaseSCache(oldDscp);
6487         cm_ReleaseSCache(newDscp);
6488         cm_ReleaseUser(userp);
6489         return CM_ERROR_CROSSDEVLINK;
6490     }
6491
6492     /* handle the old name first */
6493     if (!oldLastNamep)
6494         oldLastNamep = oldPathp;
6495     else
6496         oldLastNamep++;
6497
6498     /* and handle the new name, too */
6499     if (!newLastNamep)
6500         newLastNamep = newPathp;
6501     else
6502         newLastNamep++;
6503
6504     /* now lookup the old name */
6505     osi_Log1(smb_logp,"  looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6506     code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6507     if (code) {
6508         cm_ReleaseSCache(oldDscp);
6509         cm_ReleaseSCache(newDscp);
6510         cm_ReleaseUser(userp);
6511         return code;
6512     }
6513
6514     /* Check if the file already exists; if so return error */
6515     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6516     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6517         (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6518     {
6519         osi_Log2(smb_logp, "  lookup returns %ld for [%S]", code,
6520                  osi_LogSaveClientString(smb_logp, newLastNamep));
6521
6522         /* if the existing link is to the same file, then we return success */
6523         if (!code) {
6524             if(sscp == tmpscp) {
6525                 code = 0;
6526             } else {
6527                 osi_Log0(smb_logp, "Can't create hardlink.  Target already exists");
6528                 code = CM_ERROR_EXISTS;
6529             }
6530         }
6531
6532         if (tmpscp != NULL)
6533             cm_ReleaseSCache(tmpscp);
6534         cm_ReleaseSCache(sscp);
6535         cm_ReleaseSCache(newDscp);
6536         cm_ReleaseSCache(oldDscp);
6537         cm_ReleaseUser(userp);
6538         return code;
6539     }
6540
6541     /* now create the hardlink */
6542     osi_Log1(smb_logp,"  Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6543     code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6544     osi_Log1(smb_logp,"  Link returns 0x%x", code);
6545
6546     /* Handle Change Notification */
6547     if (code == 0) {
6548         filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6549         if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6550             smb_NotifyChange(FILE_ACTION_ADDED,
6551                              filter, newDscp, newLastNamep,
6552                              NULL, TRUE);
6553     }
6554
6555     if (tmpscp != NULL)
6556         cm_ReleaseSCache(tmpscp);
6557     cm_ReleaseUser(userp);
6558     cm_ReleaseSCache(sscp);
6559     cm_ReleaseSCache(oldDscp);
6560     cm_ReleaseSCache(newDscp);
6561     return code;
6562 }
6563
6564 /* SMB_COM_RENAME */
6565 long
6566 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6567 {
6568     clientchar_t *oldPathp;
6569     clientchar_t *newPathp;
6570     unsigned char *tp;
6571     long code;
6572
6573     tp = smb_GetSMBData(inp, NULL);
6574     oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6575     if (!oldPathp)
6576         return CM_ERROR_BADSMB;
6577     newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6578     if (!newPathp)
6579         return CM_ERROR_BADSMB;
6580
6581     osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6582              osi_LogSaveClientString(smb_logp, oldPathp),
6583              osi_LogSaveClientString(smb_logp, newPathp));
6584
6585     if (!cm_IsValidClientString(newPathp)) {
6586 #ifdef DEBUG
6587         clientchar_t * hexp;
6588
6589         hexp = cm_GetRawCharsAlloc(newPathp, -1);
6590         osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6591                  osi_LogSaveClientString(smb_logp, hexp));
6592         if (hexp)
6593             free(hexp);
6594 #else
6595         osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6596 #endif
6597         return CM_ERROR_BADNTFILENAME;
6598     }
6599
6600     code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6601
6602     osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6603     return code;
6604 }
6605
6606
6607
6608 typedef struct smb_rmdirRock {
6609     cm_scache_t *dscp;
6610     cm_user_t *userp;
6611     cm_req_t *reqp;
6612     normchar_t *maskp;          /* pointer to the star pattern */
6613     int flags;
6614     int any;
6615     cm_dirEntryList_t * matches;
6616 } smb_rmdirRock_t;
6617
6618 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6619 {
6620     long code = 0;
6621     smb_rmdirRock_t *rockp;
6622     int match;
6623     normchar_t matchName[MAX_PATH];
6624
6625     rockp = (smb_rmdirRock_t *) vrockp;
6626
6627     if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6628         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6629                  osi_LogSaveString(smb_logp, dep->name));
6630         return 0;
6631     }
6632
6633     if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6634         match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6635     else
6636         match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6637     if (!match &&
6638          (rockp->flags & SMB_MASKFLAG_TILDE) &&
6639          cm_shortNames &&
6640          !cm_Is8Dot3(matchName)) {
6641         cm_Gen8Dot3Name(dep, matchName, NULL);
6642         match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6643     }
6644
6645     if (match) {
6646         rockp->any = 1;
6647         cm_DirEntryListAdd(dep->name, &rockp->matches);
6648     }
6649
6650     return 0;
6651 }
6652
6653
6654 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6655 {
6656     long code = 0;
6657     clientchar_t *pathp;
6658     unsigned char *tp;
6659     cm_space_t *spacep;
6660     cm_scache_t *dscp;
6661     clientchar_t *lastNamep;
6662     smb_rmdirRock_t rock;
6663     cm_user_t *userp;
6664     osi_hyper_t thyper;
6665     int caseFold;
6666     clientchar_t *tidPathp;
6667     cm_req_t req;
6668
6669     smb_InitReq(&req);
6670     memset(&rock, 0, sizeof(rock));
6671
6672     tp = smb_GetSMBData(inp, NULL);
6673     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6674     if (!pathp)
6675         return CM_ERROR_BADSMB;
6676
6677     spacep = inp->spacep;
6678     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6679
6680     userp = smb_GetUserFromVCP(vcp, inp);
6681
6682     caseFold = CM_FLAG_CASEFOLD;
6683
6684     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6685     if (code) {
6686         cm_ReleaseUser(userp);
6687         return CM_ERROR_NOSUCHPATH;
6688     }
6689     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6690                     userp, tidPathp, &req, &dscp);
6691
6692     if (code) {
6693         cm_ReleaseUser(userp);
6694         return code;
6695     }
6696
6697 #ifdef DFS_SUPPORT
6698     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6699         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6700         cm_ReleaseSCache(dscp);
6701         cm_ReleaseUser(userp);
6702         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6703             return CM_ERROR_PATH_NOT_COVERED;
6704         else
6705             return CM_ERROR_NOSUCHPATH;
6706     }
6707 #endif /* DFS_SUPPORT */
6708
6709     /* otherwise, scp points to the parent directory. */
6710     if (!lastNamep)
6711         lastNamep = pathp;
6712     else
6713         lastNamep++;
6714
6715     rock.any = 0;
6716     rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6717     if (!rock.maskp) {
6718         code = CM_ERROR_NOSUCHFILE;
6719         goto done;
6720     }
6721     rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6722
6723     thyper.LowPart = 0;
6724     thyper.HighPart = 0;
6725     rock.userp = userp;
6726     rock.reqp = &req;
6727     rock.dscp = dscp;
6728     rock.matches = NULL;
6729
6730     /* First do a case sensitive match, and if that fails, do a case insensitive match */
6731     code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6732     if (code == 0 && !rock.any) {
6733         thyper.LowPart = 0;
6734         thyper.HighPart = 0;
6735         rock.flags |= SMB_MASKFLAG_CASEFOLD;
6736         code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6737     }
6738
6739     if (code == 0 && rock.matches) {
6740         cm_dirEntryList_t * entry;
6741
6742         for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6743             clientchar_t clientName[MAX_PATH];
6744
6745             /* We assume this will succeed because smb_RmdirProc()
6746                successfully converted entry->name once above. */
6747             cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6748
6749             osi_Log1(smb_logp, "Removing directory %s",
6750                      osi_LogSaveString(smb_logp, entry->name));
6751
6752             code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6753
6754             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6755                 smb_NotifyChange(FILE_ACTION_REMOVED,
6756                                  FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6757                                  dscp, clientName, NULL, TRUE);
6758         }
6759     }
6760
6761   done:
6762     if (rock.matches)
6763     cm_DirEntryListFree(&rock.matches);
6764
6765     if (userp)
6766     cm_ReleaseUser(userp);
6767
6768     if (dscp)
6769     cm_ReleaseSCache(dscp);
6770
6771     if (code == 0 && !rock.any)
6772         code = CM_ERROR_NOSUCHFILE;
6773
6774     if (rock.maskp)
6775     free(rock.maskp);
6776
6777     return code;
6778 }
6779
6780 /* SMB_COM_FLUSH */
6781 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6782 {
6783     unsigned short fid;
6784     smb_fid_t *fidp;
6785     cm_user_t *userp;
6786     long code = 0;
6787     cm_req_t req;
6788
6789     smb_InitReq(&req);
6790
6791     fid = smb_GetSMBParm(inp, 0);
6792
6793     osi_Log1(smb_logp, "SMB flush fid %d", fid);
6794
6795     fid = smb_ChainFID(fid, inp);
6796     fidp = smb_FindFID(vcp, fid, 0);
6797     if (!fidp) {
6798         osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6799                  vcp, fid);
6800         return CM_ERROR_BADFD;
6801     }
6802     userp = smb_GetUserFromVCP(vcp, inp);
6803
6804     lock_ObtainMutex(&fidp->mx);
6805     if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6806         cm_ReleaseUser(userp);
6807         lock_ReleaseMutex(&fidp->mx);
6808         smb_ReleaseFID(fidp);
6809         return CM_ERROR_BADFD;
6810     }
6811
6812     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6813         lock_ReleaseMutex(&fidp->mx);
6814         cm_ReleaseUser(userp);
6815         smb_CloseFID(vcp, fidp, NULL, 0);
6816         smb_ReleaseFID(fidp);
6817         return CM_ERROR_NOSUCHFILE;
6818     }
6819
6820     if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6821         cm_scache_t * scp = fidp->scp;
6822         cm_HoldSCache(scp);
6823         lock_ReleaseMutex(&fidp->mx);
6824         code = cm_FSync(scp, userp, &req, FALSE);
6825         cm_ReleaseSCache(scp);
6826     } else {
6827         lock_ReleaseMutex(&fidp->mx);
6828         code = 0;
6829     }
6830
6831     cm_ReleaseUser(userp);
6832     smb_ReleaseFID(fidp);
6833     return code;
6834 }
6835
6836 struct smb_FullNameRock {
6837     clientchar_t *name;
6838     cm_scache_t  *vnode;
6839     clientchar_t *fullName;
6840     fschar_t     *originalName;
6841 };
6842
6843 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6844                      osi_hyper_t *offp)
6845 {
6846     normchar_t matchName[MAX_PATH];
6847     struct smb_FullNameRock *vrockp;
6848
6849     vrockp = (struct smb_FullNameRock *)rockp;
6850
6851     if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6852         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6853                  osi_LogSaveString(smb_logp, dep->name));
6854         return 0;
6855     }
6856
6857     if (cm_shortNames && !cm_Is8Dot3(matchName)) {
6858         clientchar_t shortName[13];
6859
6860         cm_Gen8Dot3Name(dep, shortName, NULL);
6861
6862         if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6863             vrockp->fullName = cm_ClientStrDup(matchName);
6864             vrockp->originalName = cm_FsStrDup(dep->name);
6865             return CM_ERROR_STOPNOW;
6866         }
6867     }
6868     if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6869         ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6870         ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6871         vrockp->fullName = cm_ClientStrDup(matchName);
6872         vrockp->originalName = cm_FsStrDup(dep->name);
6873         return CM_ERROR_STOPNOW;
6874     }
6875     return 0;
6876 }
6877
6878 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6879                   clientchar_t **newPathp, fschar_t ** originalPathp,
6880                   cm_user_t *userp, cm_req_t *reqp)
6881 {
6882     struct smb_FullNameRock rock;
6883     long code = 0;
6884
6885     memset(&rock, 0, sizeof(rock));
6886     rock.name = pathp;
6887     rock.vnode = scp;
6888
6889     code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6890     if (code == CM_ERROR_STOPNOW) {
6891         *newPathp = rock.fullName;
6892         *originalPathp = rock.originalName;
6893     } else {
6894         *newPathp = cm_ClientStrDup(pathp);
6895         *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6896     }
6897 }
6898
6899 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6900                   afs_uint32 dosTime) {
6901     long code = 0;
6902     cm_req_t req;
6903     cm_scache_t *dscp = NULL;
6904     clientchar_t *pathp = NULL;
6905     cm_scache_t * scp = NULL;
6906     cm_scache_t *delscp = NULL;
6907     int nullcreator = 0;
6908
6909     osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6910              fidp, fidp->fid, scp, vcp);
6911
6912     if (!userp) {
6913         lock_ObtainMutex(&fidp->mx);
6914         if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6915                                              SMB_FID_RPC))) {
6916             lock_ReleaseMutex(&fidp->mx);
6917             osi_Log0(smb_logp, "  No user specified.  Not closing fid");
6918             return CM_ERROR_BADFD;
6919         }
6920
6921         userp = fidp->userp;    /* no hold required since fidp is held
6922                                    throughout the function */
6923         lock_ReleaseMutex(&fidp->mx);
6924     }
6925
6926     smb_InitReq(&req);
6927
6928     lock_ObtainWrite(&smb_rctLock);
6929     if (fidp->deleteOk) {
6930         osi_Log0(smb_logp, "  Fid already closed.");
6931         lock_ReleaseWrite(&smb_rctLock);
6932         return CM_ERROR_BADFD;
6933     }
6934     fidp->deleteOk = 1;
6935     lock_ReleaseWrite(&smb_rctLock);
6936
6937     lock_ObtainMutex(&fidp->mx);
6938     if (fidp->NTopen_dscp) {
6939         dscp = fidp->NTopen_dscp;
6940         cm_HoldSCache(dscp);
6941     }
6942
6943     if (fidp->NTopen_pathp)
6944         pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6945
6946     if (fidp->scp) {
6947         scp = fidp->scp;
6948         cm_HoldSCache(scp);
6949     }
6950
6951     /* Don't jump the gun on an async raw write */
6952     while (fidp->raw_writers) {
6953         lock_ReleaseMutex(&fidp->mx);
6954         thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6955         lock_ObtainMutex(&fidp->mx);
6956     }
6957
6958     /* watch for ioctl closes, and read-only opens */
6959     if (scp != NULL &&
6960         (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6961          == SMB_FID_OPENWRITE) {
6962         if (dosTime != 0 && dosTime != -1) {
6963             lock_ObtainWrite(&fidp->scp->rw);
6964             scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6965             /* This fixes defect 10958 */
6966             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6967             smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6968             lock_ReleaseWrite(&fidp->scp->rw);
6969         }
6970         if (smb_AsyncStore != 2) {
6971             lock_ReleaseMutex(&fidp->mx);
6972             code = cm_FSync(scp, userp, &req, FALSE);
6973             lock_ObtainMutex(&fidp->mx);
6974         }
6975     }
6976     else
6977         code = 0;
6978
6979     /* unlock any pending locks */
6980     if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6981         scp->fileType == CM_SCACHETYPE_FILE) {
6982         cm_key_t key;
6983         long tcode;
6984
6985         lock_ReleaseMutex(&fidp->mx);
6986
6987         /*
6988          * CM_UNLOCK_FLAG_BY_FID doesn't look at the process ID.
6989          * We pass in zero.
6990          */
6991         key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6992         lock_ObtainWrite(&scp->rw);
6993
6994         tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6995                           CM_SCACHESYNC_NEEDCALLBACK
6996                           | CM_SCACHESYNC_GETSTATUS
6997                           | CM_SCACHESYNC_LOCK);
6998
6999         if (tcode) {
7000             osi_Log1(smb_logp,
7001                      "smb CoreClose SyncOp failure code 0x%x", tcode);
7002             goto post_syncopdone;
7003         }
7004
7005         cm_UnlockByKey(scp, key, CM_UNLOCK_FLAG_BY_FID, userp, &req);
7006
7007         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
7008
7009     post_syncopdone:
7010
7011         lock_ReleaseWrite(&scp->rw);
7012         lock_ObtainMutex(&fidp->mx);
7013     }
7014
7015     if (fidp->flags & SMB_FID_DELONCLOSE) {
7016         clientchar_t *fullPathp = NULL;
7017         fschar_t *originalNamep = NULL;
7018
7019         lock_ReleaseMutex(&fidp->mx);
7020
7021         code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
7022         if (code) {
7023             cm_HoldSCache(scp);
7024             delscp = scp;
7025         }
7026         smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
7027         if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
7028             code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
7029             if (code == 0) {
7030                 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7031                     smb_NotifyChange(FILE_ACTION_REMOVED,
7032                                       FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
7033                                       dscp, fullPathp, NULL, TRUE);
7034             }
7035         } else {
7036             code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
7037             if (code == 0) {
7038                 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7039                     smb_NotifyChange(FILE_ACTION_REMOVED,
7040                                       FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7041                                       dscp, fullPathp, NULL, TRUE);
7042             }
7043         }
7044
7045         if (fullPathp)
7046             free(fullPathp);
7047         if (originalNamep)
7048             free(originalNamep);
7049
7050         lock_ObtainMutex(&fidp->mx);
7051         fidp->flags &= ~SMB_FID_DELONCLOSE;
7052     }
7053
7054     /* if this was a newly created file, then clear the creator
7055      * in the stat cache entry. */
7056     if (fidp->flags & SMB_FID_CREATED) {
7057         nullcreator = 1;
7058         fidp->flags &= ~SMB_FID_CREATED;
7059     }
7060
7061     if (fidp->flags & SMB_FID_NTOPEN) {
7062         cm_ReleaseSCache(fidp->NTopen_dscp);
7063         fidp->NTopen_dscp = NULL;
7064         free(fidp->NTopen_pathp);
7065         fidp->NTopen_pathp = NULL;
7066         fidp->flags &= ~SMB_FID_NTOPEN;
7067     } else {
7068         osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
7069         osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
7070     }
7071
7072     if (fidp->NTopen_wholepathp) {
7073         free(fidp->NTopen_wholepathp);
7074         fidp->NTopen_wholepathp = NULL;
7075     }
7076
7077     if (fidp->scp) {
7078         cm_ReleaseSCache(fidp->scp);
7079         fidp->scp = NULL;
7080     }
7081     lock_ReleaseMutex(&fidp->mx);
7082
7083     if (dscp)
7084         cm_ReleaseSCache(dscp);
7085
7086     if (delscp) {
7087         cm_ReleaseSCache(delscp);
7088     }
7089
7090     if (scp) {
7091         lock_ObtainWrite(&scp->rw);
7092         if (nullcreator && scp->creator == userp)
7093             scp->creator = NULL;
7094         scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
7095         lock_ReleaseWrite(&scp->rw);
7096         cm_ReleaseSCache(scp);
7097     }
7098
7099     if (pathp)
7100         free(pathp);
7101
7102     return code;
7103 }
7104
7105 /* SMB_COM_CLOSE */
7106 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7107 {
7108     unsigned short fid;
7109     smb_fid_t *fidp;
7110     cm_user_t *userp;
7111     long code = 0;
7112     afs_uint32 dosTime;
7113
7114     fid = smb_GetSMBParm(inp, 0);
7115     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7116
7117     osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
7118
7119     fid = smb_ChainFID(fid, inp);
7120     fidp = smb_FindFID(vcp, fid, 0);
7121     if (!fidp) {
7122         osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
7123                  vcp, fid);
7124         return CM_ERROR_BADFD;
7125     }
7126
7127     userp = smb_GetUserFromVCP(vcp, inp);
7128
7129     code = smb_CloseFID(vcp, fidp, userp, dosTime);
7130
7131     smb_ReleaseFID(fidp);
7132     cm_ReleaseUser(userp);
7133     return code;
7134 }
7135
7136 /*
7137  * smb_ReadData -- common code for Read, Read And X, and Raw Read
7138  */
7139 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7140         cm_user_t *userp, long *readp)
7141 {
7142     osi_hyper_t offset;
7143     long code = 0;
7144     cm_scache_t *scp;
7145     cm_buf_t *bufferp;
7146     osi_hyper_t fileLength;
7147     osi_hyper_t thyper;
7148     osi_hyper_t lastByte;
7149     osi_hyper_t bufferOffset;
7150     long bufIndex;
7151     afs_uint32 nbytes;
7152     int chunk;
7153     int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
7154     cm_req_t req;
7155
7156     osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
7157               fidp->fid, offsetp->LowPart, count);
7158
7159     *readp = 0;
7160
7161     lock_ObtainMutex(&fidp->mx);
7162     /* make sure we have a readable FD */
7163     if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7164         osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7165                   fidp->fid, fidp->flags);
7166         lock_ReleaseMutex(&fidp->mx);
7167         code = CM_ERROR_BADFDOP;
7168         goto done2;
7169     }
7170
7171     if (!fidp->scp) {
7172         lock_ReleaseMutex(&fidp->mx);
7173         code = CM_ERROR_BADFD;
7174         goto done2;
7175     }
7176
7177     smb_InitReq(&req);
7178
7179     bufferp = NULL;
7180     offset = *offsetp;
7181
7182     scp = fidp->scp;
7183     cm_HoldSCache(scp);
7184     lock_ObtainWrite(&scp->rw);
7185
7186     if (offset.HighPart == 0) {
7187         chunk = offset.LowPart >> cm_logChunkSize;
7188         if (chunk != fidp->curr_chunk) {
7189             fidp->prev_chunk = fidp->curr_chunk;
7190             fidp->curr_chunk = chunk;
7191         }
7192         if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7193             sequential = 1;
7194     }
7195     lock_ReleaseMutex(&fidp->mx);
7196
7197     /* start by looking up the file's end */
7198     code = cm_SyncOp(scp, NULL, userp, &req, 0,
7199                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7200     if (code)
7201         goto done;
7202
7203     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7204
7205     /* now we have the entry locked, look up the length */
7206     fileLength = scp->length;
7207
7208     /* adjust count down so that it won't go past EOF */
7209     thyper.LowPart = count;
7210     thyper.HighPart = 0;
7211     thyper = LargeIntegerAdd(offset, thyper);   /* where read should end */
7212     lastByte = thyper;
7213     if (LargeIntegerGreaterThan(thyper, fileLength)) {
7214         /* we'd read past EOF, so just stop at fileLength bytes.
7215          * Start by computing how many bytes remain in the file.
7216          */
7217         thyper = LargeIntegerSubtract(fileLength, offset);
7218
7219         /* if we are past EOF, read 0 bytes */
7220         if (LargeIntegerLessThanZero(thyper))
7221             count = 0;
7222         else
7223             count = thyper.LowPart;
7224     }
7225
7226     *readp = count;
7227
7228     /* now, copy the data one buffer at a time,
7229      * until we've filled the request packet
7230      */
7231     while (1) {
7232         /* if we've copied all the data requested, we're done */
7233         if (count <= 0) break;
7234
7235         /* otherwise, load up a buffer of data */
7236         thyper.HighPart = offset.HighPart;
7237         thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7238         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7239             /* wrong buffer */
7240             if (bufferp) {
7241                 buf_Release(bufferp);
7242                 bufferp = NULL;
7243             }
7244             lock_ReleaseWrite(&scp->rw);
7245
7246             code = buf_Get(scp, &thyper, &req, 0, &bufferp);
7247
7248             lock_ObtainWrite(&scp->rw);
7249             if (code) goto done;
7250             bufferOffset = thyper;
7251
7252             /* now get the data in the cache */
7253             while (1) {
7254                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7255                                  CM_SCACHESYNC_NEEDCALLBACK |
7256                                  CM_SCACHESYNC_READ);
7257                 if (code)
7258                     goto done;
7259
7260                 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7261
7262                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7263
7264                 /* otherwise, load the buffer and try again */
7265                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7266                 if (code) break;
7267             }
7268             if (code) {
7269                 buf_Release(bufferp);
7270                 bufferp = NULL;
7271                 goto done;
7272             }
7273         }       /* if (wrong buffer) ... */
7274
7275         /* now we have the right buffer loaded.  Copy out the
7276          * data from here to the user's buffer.
7277          */
7278         bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7279
7280         /* and figure out how many bytes we want from this buffer */
7281         nbytes = cm_data.buf_blockSize - bufIndex;      /* what remains in buffer */
7282         if (nbytes > count) nbytes = count;     /* don't go past EOF */
7283
7284         /* now copy the data */
7285         memcpy(op, bufferp->datap + bufIndex, nbytes);
7286
7287         /* adjust counters, pointers, etc. */
7288         op += nbytes;
7289         count -= nbytes;
7290         thyper.LowPart = nbytes;
7291         thyper.HighPart = 0;
7292         offset = LargeIntegerAdd(thyper, offset);
7293     } /* while 1 */
7294
7295   done:
7296     lock_ReleaseWrite(&scp->rw);
7297     if (bufferp)
7298         buf_Release(bufferp);
7299
7300     if (code == 0 && sequential)
7301         cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7302
7303     cm_ReleaseSCache(scp);
7304
7305   done2:
7306     osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7307               fidp->fid, code, *readp);
7308     return code;
7309 }
7310
7311 /*
7312  * smb_WriteData -- common code for Write and Raw Write
7313  */
7314 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7315         cm_user_t *userp, long *writtenp)
7316 {
7317     osi_hyper_t offset = *offsetp;
7318     long code = 0;
7319     long written = 0;
7320     cm_scache_t *scp = NULL;
7321     osi_hyper_t fileLength;     /* file's length at start of write */
7322     osi_hyper_t minLength;      /* don't read past this */
7323     afs_uint32 nbytes;          /* # of bytes to transfer this iteration */
7324     cm_buf_t *bufferp = NULL;
7325     osi_hyper_t thyper;         /* hyper tmp variable */
7326     osi_hyper_t bufferOffset;
7327     afs_uint32 bufIndex;                /* index in buffer where our data is */
7328     int doWriteBack = 0;
7329     osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7330     DWORD filter = 0;
7331     cm_req_t req;
7332     int needSyncOpDone = 0;
7333
7334     osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7335               fidp->fid, offsetp->LowPart, count);
7336
7337     *writtenp = 0;
7338
7339     lock_ObtainMutex(&fidp->mx);
7340     /* make sure we have a writable FD */
7341     if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7342         osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7343                   fidp->fid, fidp->flags);
7344         lock_ReleaseMutex(&fidp->mx);
7345         code = CM_ERROR_BADFDOP;
7346         goto done2;
7347     }
7348
7349     smb_InitReq(&req);
7350
7351     scp = fidp->scp;
7352     cm_HoldSCache(scp);
7353     lock_ReleaseMutex(&fidp->mx);
7354
7355     lock_ObtainWrite(&scp->rw);
7356     /* start by looking up the file's end */
7357     code = cm_SyncOp(scp, NULL, userp, &req, 0,
7358                       CM_SCACHESYNC_NEEDCALLBACK
7359                       | CM_SCACHESYNC_SETSTATUS
7360                       | CM_SCACHESYNC_GETSTATUS);
7361     if (code)
7362         goto done;
7363
7364     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7365
7366     /* now we have the entry locked, look up the length */
7367     fileLength = scp->length;
7368     minLength = fileLength;
7369     if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7370         minLength = scp->serverLength;
7371
7372     /* adjust file length if we extend past EOF */
7373     thyper.LowPart = count;
7374     thyper.HighPart = 0;
7375     thyper = LargeIntegerAdd(offset, thyper);   /* where write should end */
7376     if (LargeIntegerGreaterThan(thyper, fileLength)) {
7377         /* we'd write past EOF, so extend the file */
7378         scp->mask |= CM_SCACHEMASK_LENGTH;
7379         scp->length = thyper;
7380         filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7381     } else
7382         filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7383
7384     /* now, if the new position (thyper) and the old (offset) are in
7385      * different storeback windows, remember to store back the previous
7386      * storeback window when we're done with the write.
7387      *
7388      * the purpose of this logic is to slow down the CIFS client
7389      * in order to avoid the client disconnecting during the CLOSE
7390      * operation if there are too many dirty buffers left to write
7391      * than can be accomplished during 45 seconds.  This used to be
7392      * based upon cm_chunkSize but we desire cm_chunkSize to be large
7393      * so that we can read larger amounts of data at a time.
7394      */
7395     if (smb_AsyncStore == 1 &&
7396          (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7397          (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7398         /* they're different */
7399         doWriteBack = 1;
7400         writeBackOffset.HighPart = offset.HighPart;
7401         writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7402     }
7403
7404     *writtenp = count;
7405
7406     /* now, copy the data one buffer at a time, until we've filled the
7407      * request packet */
7408     while (count != 0) {
7409
7410         /* handle over quota or out of space */
7411         if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7412             *writtenp = written;
7413             code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7414             break;
7415         }
7416
7417         /* otherwise, load up a buffer of data */
7418         thyper.HighPart = offset.HighPart;
7419         thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7420         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7421             /* wrong buffer */
7422             if (bufferp) {
7423                 if (needSyncOpDone) {
7424                     cm_SyncOpDone(scp, bufferp,
7425                                   CM_SCACHESYNC_NEEDCALLBACK
7426                                   | CM_SCACHESYNC_WRITE
7427                                   | CM_SCACHESYNC_BUFLOCKED);
7428                     needSyncOpDone = 0;
7429                 }
7430                 lock_ReleaseMutex(&bufferp->mx);
7431                 buf_Release(bufferp);
7432                 bufferp = NULL;
7433             }
7434             lock_ReleaseWrite(&scp->rw);
7435
7436             code = buf_Get(scp, &thyper, &req, 0, &bufferp);
7437
7438             lock_ObtainMutex(&bufferp->mx);
7439             lock_ObtainWrite(&scp->rw);
7440             if (code) goto done;
7441
7442             bufferOffset = thyper;
7443
7444             /* now get the data in the cache */
7445             while (code == 0) {
7446                 if (!needSyncOpDone) {
7447                     code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7448                                      CM_SCACHESYNC_NEEDCALLBACK
7449                                      | CM_SCACHESYNC_WRITE
7450                                      | CM_SCACHESYNC_BUFLOCKED);
7451                     if (code)
7452                         goto done;
7453
7454                     needSyncOpDone = 1;
7455                 }
7456
7457                 /* If we're overwriting the entire buffer, or
7458                  * if we're writing at or past EOF, mark the
7459                  * buffer as current so we don't call
7460                  * cm_GetBuffer.  This skips the fetch from the
7461                  * server in those cases where we're going to
7462                  * obliterate all the data in the buffer anyway,
7463                  * or in those cases where there is no useful
7464                  * data at the server to start with.
7465                  *
7466                  * Use minLength instead of scp->length, since
7467                  * the latter has already been updated by this
7468                  * call.
7469                  *
7470                  * The scp lock has been dropped multiple times
7471                  * so the minLength must be refreshed before it
7472                  * is used.
7473                  */
7474
7475                 minLength = scp->length;
7476                 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7477                     minLength = scp->serverLength;
7478
7479                 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7480                      || LargeIntegerEqualTo(offset, bufferp->offset)
7481                      && (count >= cm_data.buf_blockSize
7482                           || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7483                                                                                ConvertLongToLargeInteger(count)),
7484                                                                minLength))) {
7485                     if (count < cm_data.buf_blockSize
7486                          && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7487                         memset(bufferp->datap, 0,
7488                                 cm_data.buf_blockSize);
7489                     bufferp->dataVersion = scp->dataVersion;
7490                 }
7491
7492                 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7493
7494                 /* otherwise, load the buffer and try again */
7495                 cm_SyncOpDone(scp, bufferp,
7496                               CM_SCACHESYNC_NEEDCALLBACK
7497                               | CM_SCACHESYNC_WRITE
7498                               | CM_SCACHESYNC_BUFLOCKED);
7499                 needSyncOpDone = 0;
7500
7501                 lock_ReleaseMutex(&bufferp->mx);
7502                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7503                                      &req);
7504                 lock_ReleaseWrite(&scp->rw);
7505                 lock_ObtainMutex(&bufferp->mx);
7506                 lock_ObtainWrite(&scp->rw);
7507             }
7508             if (code)
7509                 goto done;
7510         }       /* if (wrong buffer) ... */
7511
7512         /* now we have the right buffer loaded.  Copy out the
7513          * data from here to the user's buffer.
7514          */
7515         bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7516
7517         /* and figure out how many bytes we want from this buffer */
7518         nbytes = cm_data.buf_blockSize - bufIndex;      /* what remains in buffer */
7519         if (nbytes > count)
7520             nbytes = count;     /* don't go past end of request */
7521
7522         /* now copy the data */
7523         memcpy(bufferp->datap + bufIndex, op, nbytes);
7524         buf_SetDirty(bufferp, &req, bufIndex, nbytes, userp);
7525
7526         /* adjust counters, pointers, etc. */
7527         op += nbytes;
7528         count -= nbytes;
7529         written += nbytes;
7530         offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7531     } /* while count != 0 */
7532
7533   done:
7534     if (bufferp && needSyncOpDone) {
7535         cm_SyncOpDone(scp, bufferp,
7536                       CM_SCACHESYNC_NEEDCALLBACK
7537                       | CM_SCACHESYNC_WRITE
7538                       | CM_SCACHESYNC_BUFLOCKED);
7539     }
7540
7541     lock_ReleaseWrite(&scp->rw);
7542
7543     if (bufferp) {
7544         lock_ReleaseMutex(&bufferp->mx);
7545         buf_Release(bufferp);
7546     }
7547
7548     lock_ObtainMutex(&fidp->mx);
7549     if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7550          && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7551     {
7552         lock_ReleaseMutex(&fidp->mx);
7553         smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7554                           fidp->NTopen_dscp, fidp->NTopen_pathp,
7555                           NULL, TRUE);
7556     } else {
7557         lock_ReleaseMutex(&fidp->mx);
7558     }
7559
7560     if (code == 0) {
7561         if (smb_AsyncStore > 0) {
7562             if (doWriteBack) {
7563                 long code2;
7564                 rock_BkgStore_t *rockp = malloc(sizeof(*rockp));
7565
7566                 if (rockp) {
7567                     lock_ObtainWrite(&scp->rw);
7568                     osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7569                              fidp->fid);
7570                     code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7571                     osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7572                              fidp->fid, code2);
7573                     lock_ReleaseWrite(&scp->rw);
7574                     if (code2 == 0) {
7575                         rockp->length = smb_AsyncStoreSize;
7576                         rockp->offset = writeBackOffset;
7577
7578                         cm_QueueBKGRequest(scp, cm_BkgStore, rockp, userp, &req);
7579                         /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7580                         /* rock is freed by cm_BkgDaemon */
7581                     } else {
7582                         free(rockp);
7583                     }
7584                 }
7585             }
7586         } else {
7587             cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7588         }
7589     }
7590
7591     cm_ReleaseSCache(scp);
7592
7593   done2:
7594     osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7595               fidp->fid, code, *writtenp);
7596     return code;
7597 }
7598
7599 /* SMB_COM_WRITE */
7600 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7601 {
7602     unsigned short fd;
7603     unsigned short count;
7604     osi_hyper_t offset;
7605     unsigned short hint;
7606     long written = 0, total_written = 0;
7607     unsigned pid;
7608     smb_fid_t *fidp;
7609     smb_t* smbp = (smb_t*) inp;
7610     long code = 0;
7611     cm_user_t *userp;
7612         cm_scache_t *scp;
7613     cm_attr_t truncAttr;        /* attribute struct used for truncating file */
7614     char *op;
7615     int inDataBlockCount;
7616
7617     fd = smb_GetSMBParm(inp, 0);
7618     count = smb_GetSMBParm(inp, 1);
7619     offset.HighPart = 0;        /* too bad */
7620     offset.LowPart = smb_GetSMBParmLong(inp, 2);
7621     hint = smb_GetSMBParm(inp, 4);
7622
7623     op = smb_GetSMBData(inp, NULL);
7624     op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7625
7626     osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7627              fd, offset.LowPart, count);
7628
7629     fd = smb_ChainFID(fd, inp);
7630     fidp = smb_FindFID(vcp, fd, 0);
7631     if (!fidp) {
7632         osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7633                  vcp, fd);
7634         return CM_ERROR_BADFD;
7635     }
7636
7637     lock_ObtainMutex(&fidp->mx);
7638     if (fidp->flags & SMB_FID_IOCTL) {
7639         lock_ReleaseMutex(&fidp->mx);
7640         code = smb_IoctlWrite(fidp, vcp, inp, outp);
7641         smb_ReleaseFID(fidp);
7642         osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7643         return code;
7644     }
7645
7646     if (fidp->flags & SMB_FID_RPC) {
7647         lock_ReleaseMutex(&fidp->mx);
7648         code = smb_RPCWrite(fidp, vcp, inp, outp);
7649         smb_ReleaseFID(fidp);
7650         osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7651         return code;
7652     }
7653
7654     if (!fidp->scp) {
7655         lock_ReleaseMutex(&fidp->mx);
7656         smb_ReleaseFID(fidp);
7657         return CM_ERROR_BADFD;
7658     }
7659
7660     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7661         lock_ReleaseMutex(&fidp->mx);
7662         smb_CloseFID(vcp, fidp, NULL, 0);
7663         smb_ReleaseFID(fidp);
7664         return CM_ERROR_NOSUCHFILE;
7665     }
7666
7667     scp = fidp->scp;
7668     cm_HoldSCache(scp);
7669     lock_ReleaseMutex(&fidp->mx);
7670     userp = smb_GetUserFromVCP(vcp, inp);
7671
7672     {
7673         cm_key_t key;
7674         LARGE_INTEGER LOffset;
7675         LARGE_INTEGER LLength;
7676
7677         pid = smbp->pid;
7678         key = cm_GenerateKey(vcp->vcID, pid, fd);
7679
7680         LOffset.HighPart = offset.HighPart;
7681         LOffset.LowPart = offset.LowPart;
7682         LLength.HighPart = 0;
7683         LLength.LowPart = count;
7684
7685         lock_ObtainWrite(&scp->rw);
7686         code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7687         lock_ReleaseWrite(&scp->rw);
7688
7689         if (code) {
7690             osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7691             goto done;
7692         }
7693     }
7694
7695     /* special case: 0 bytes transferred means truncate to this position */
7696     if (count == 0) {
7697         cm_req_t req;
7698
7699         osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7700
7701         smb_InitReq(&req);
7702
7703         truncAttr.mask = CM_ATTRMASK_LENGTH;
7704         truncAttr.length.LowPart = offset.LowPart;
7705         truncAttr.length.HighPart = 0;
7706         lock_ObtainMutex(&fidp->mx);
7707         code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7708         fidp->flags |= SMB_FID_LENGTHSETDONE;
7709         lock_ReleaseMutex(&fidp->mx);
7710         smb_SetSMBParm(outp, 0, 0 /* count */);
7711         smb_SetSMBDataLength(outp, 0);
7712         goto done;
7713     }
7714
7715     /*
7716      * Work around bug in NT client
7717      *
7718      * When copying a file, the NT client should first copy the data,
7719      * then copy the last write time.  But sometimes the NT client does
7720      * these in the wrong order, so the data copies would inadvertently
7721      * cause the last write time to be overwritten.  We try to detect this,
7722      * and don't set client mod time if we think that would go against the
7723      * intention.
7724      */
7725     lock_ObtainMutex(&fidp->mx);
7726     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7727         lock_ObtainWrite(&fidp->scp->rw);
7728         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7729         fidp->scp->clientModTime = time(NULL);
7730         lock_ReleaseWrite(&fidp->scp->rw);
7731     }
7732     lock_ReleaseMutex(&fidp->mx);
7733
7734     code = 0;
7735     while ( code == 0 && count > 0 ) {
7736         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7737         if (code == 0 && written == 0)
7738             code = CM_ERROR_PARTIALWRITE;
7739
7740         offset = LargeIntegerAdd(offset,
7741                                  ConvertLongToLargeInteger(written));
7742         count -= (unsigned short)written;
7743         total_written += written;
7744         written = 0;
7745     }
7746
7747     osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7748              total_written, code);
7749
7750     /* set the packet data length to 3 bytes for the data block header,
7751      * plus the size of the data.
7752      */
7753     smb_SetSMBParm(outp, 0, total_written);
7754     smb_SetSMBParmLong(outp, 1, offset.LowPart);
7755     smb_SetSMBParm(outp, 3, hint);
7756     smb_SetSMBDataLength(outp, 0);
7757
7758   done:
7759     smb_ReleaseFID(fidp);
7760     cm_ReleaseUser(userp);
7761         cm_ReleaseSCache(scp);
7762
7763     return code;
7764 }
7765
7766 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7767                           NCB *ncbp, raw_write_cont_t *rwcp)
7768 {
7769     unsigned short fd;
7770     smb_fid_t *fidp;
7771     cm_user_t *userp;
7772     char *rawBuf;
7773     long written = 0;
7774     long code = 0;
7775
7776     fd = smb_GetSMBParm(inp, 0);
7777     fidp = smb_FindFID(vcp, fd, 0);
7778
7779     lock_ObtainMutex(&fidp->mx);
7780     if (!fidp->scp) {
7781         lock_ReleaseMutex(&fidp->mx);
7782         smb_ReleaseFID(fidp);
7783         return;
7784     }
7785
7786     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7787         lock_ReleaseMutex(&fidp->mx);
7788         smb_CloseFID(vcp, fidp, NULL, 0);
7789         smb_ReleaseFID(fidp);
7790         return;
7791     }
7792     lock_ReleaseMutex(&fidp->mx);
7793
7794     osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7795              rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7796
7797     userp = smb_GetUserFromVCP(vcp, inp);
7798
7799     rawBuf = rwcp->buf;
7800     code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7801                                                  &written);
7802     if (rwcp->writeMode & 0x1) {        /* synchronous */
7803         smb_t *op;
7804
7805         smb_FormatResponsePacket(vcp, inp, outp);
7806         op = (smb_t *) outp;
7807         op->com = 0x20;         /* SMB_COM_WRITE_COMPLETE */
7808         smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7809         smb_SetSMBDataLength(outp,  0);
7810         smb_SendPacket(vcp, outp);
7811         smb_FreePacket(outp);
7812     }
7813     else {                              /* asynchronous */
7814         lock_ObtainMutex(&fidp->mx);
7815         fidp->raw_writers--;
7816         if (fidp->raw_writers == 0)
7817             thrd_SetEvent(fidp->raw_write_event);
7818         lock_ReleaseMutex(&fidp->mx);
7819     }
7820
7821     /* Give back raw buffer */
7822     lock_ObtainMutex(&smb_RawBufLock);
7823     *((char **)rawBuf) = smb_RawBufs;
7824     smb_RawBufs = rawBuf;
7825     lock_ReleaseMutex(&smb_RawBufLock);
7826
7827     smb_ReleaseFID(fidp);
7828     cm_ReleaseUser(userp);
7829 }
7830
7831 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7832 {
7833     return 0;
7834 }
7835
7836 /* SMB_COM_WRITE_RAW */
7837 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7838 {
7839     osi_hyper_t offset;
7840     long count, written = 0, total_written = 0;
7841     long totalCount;
7842     unsigned short fd;
7843     smb_fid_t *fidp;
7844     smb_t *smbp = (smb_t*) inp;
7845     long code = 0;
7846     cm_user_t *userp;
7847         cm_scache_t *scp;
7848     char *op;
7849     unsigned short writeMode;
7850     char *rawBuf;
7851     fd = smb_GetSMBParm(inp, 0);
7852     totalCount = smb_GetSMBParm(inp, 1);
7853     count = smb_GetSMBParm(inp, 10);
7854     writeMode = smb_GetSMBParm(inp, 7);
7855
7856     op = (char *) inp->data;
7857     op += smb_GetSMBParm(inp, 11);
7858
7859     offset.HighPart = 0;
7860     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7861
7862     if (*inp->wctp == 14) {
7863         /* we received a 64-bit file offset */
7864         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7865
7866         if (LargeIntegerLessThanZero(offset)) {
7867             osi_Log2(smb_logp,
7868                      "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7869                      offset.HighPart, offset.LowPart);
7870             return CM_ERROR_BADSMB;
7871         }
7872     } else {
7873         offset.HighPart = 0;    /* 32-bit file offset */
7874     }
7875
7876     osi_Log4(smb_logp,
7877              "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7878              fd, offset.HighPart, offset.LowPart, count);
7879     osi_Log1(smb_logp,
7880              "               WriteRaw WriteMode 0x%x",
7881              writeMode);
7882
7883     fd = smb_ChainFID(fd, inp);
7884     fidp = smb_FindFID(vcp, fd, 0);
7885     if (!fidp) {
7886         osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7887                  vcp, fd);
7888         return CM_ERROR_BADFD;
7889     }
7890     lock_ObtainMutex(&fidp->mx);
7891     if (!fidp->scp) {
7892         lock_ReleaseMutex(&fidp->mx);
7893         smb_ReleaseFID(fidp);
7894         return CM_ERROR_BADFD;
7895     }
7896
7897     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7898         lock_ReleaseMutex(&fidp->mx);
7899         smb_CloseFID(vcp, fidp, NULL, 0);
7900         smb_ReleaseFID(fidp);
7901         return CM_ERROR_NOSUCHFILE;
7902     }
7903
7904     scp = fidp->scp;
7905     cm_HoldSCache(scp);
7906     lock_ReleaseMutex(&fidp->mx);
7907
7908     {
7909         unsigned pid;
7910         cm_key_t key;
7911         LARGE_INTEGER LOffset;
7912         LARGE_INTEGER LLength;
7913
7914         pid = smbp->pid;
7915         key = cm_GenerateKey(vcp->vcID, pid, fd);
7916
7917         LOffset.HighPart = offset.HighPart;
7918         LOffset.LowPart = offset.LowPart;
7919         LLength.HighPart = 0;
7920         LLength.LowPart = count;
7921
7922         lock_ObtainWrite(&scp->rw);
7923         code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7924         lock_ReleaseWrite(&scp->rw);
7925
7926         if (code) {
7927             cm_ReleaseSCache(scp);
7928             smb_ReleaseFID(fidp);
7929             return code;
7930         }
7931     }
7932
7933     userp = smb_GetUserFromVCP(vcp, inp);
7934
7935     /*
7936      * Work around bug in NT client
7937      *
7938      * When copying a file, the NT client should first copy the data,
7939      * then copy the last write time.  But sometimes the NT client does
7940      * these in the wrong order, so the data copies would inadvertently
7941      * cause the last write time to be overwritten.  We try to detect this,
7942      * and don't set client mod time if we think that would go against the
7943      * intention.
7944      */
7945     lock_ObtainMutex(&fidp->mx);
7946     if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7947         lock_ObtainWrite(&fidp->scp->rw);
7948         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7949         fidp->scp->clientModTime = time(NULL);
7950         lock_ReleaseWrite(&fidp->scp->rw);
7951     }
7952     lock_ReleaseMutex(&fidp->mx);
7953
7954     code = 0;
7955     while ( code == 0 && count > 0 ) {
7956         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7957         if (code == 0 && written == 0)
7958             code = CM_ERROR_PARTIALWRITE;
7959
7960         offset = LargeIntegerAdd(offset,
7961                                  ConvertLongToLargeInteger(written));
7962
7963         count -= written;
7964         total_written += written;
7965         written = 0;
7966     }
7967
7968     /* Get a raw buffer */
7969     if (code == 0) {
7970         rawBuf = NULL;
7971         lock_ObtainMutex(&smb_RawBufLock);
7972         if (smb_RawBufs) {
7973             /* Get a raw buf, from head of list */
7974             rawBuf = smb_RawBufs;
7975             smb_RawBufs = *(char **)smb_RawBufs;
7976         }
7977         else
7978             code = CM_ERROR_USESTD;
7979
7980         lock_ReleaseMutex(&smb_RawBufLock);
7981     }
7982
7983     /* Don't allow a premature Close */
7984     if (code == 0 && (writeMode & 1) == 0) {
7985         lock_ObtainMutex(&fidp->mx);
7986         fidp->raw_writers++;
7987         thrd_ResetEvent(fidp->raw_write_event);
7988         lock_ReleaseMutex(&fidp->mx);
7989     }
7990
7991     smb_ReleaseFID(fidp);
7992     cm_ReleaseUser(userp);
7993     cm_ReleaseSCache(scp);
7994
7995     if (code) {
7996         smb_SetSMBParm(outp, 0, total_written);
7997         smb_SetSMBDataLength(outp, 0);
7998         ((smb_t *)outp)->com = 0x20;    /* SMB_COM_WRITE_COMPLETE */
7999         rwcp->code = code;
8000         return code;
8001     }
8002
8003     offset = LargeIntegerAdd(offset,
8004                              ConvertLongToLargeInteger(count));
8005
8006     rwcp->code = 0;
8007     rwcp->buf = rawBuf;
8008     rwcp->offset.HighPart = offset.HighPart;
8009     rwcp->offset.LowPart = offset.LowPart;
8010     rwcp->count = totalCount - count;
8011     rwcp->writeMode = writeMode;
8012     rwcp->alreadyWritten = total_written;
8013
8014     /* set the packet data length to 3 bytes for the data block header,
8015      * plus the size of the data.
8016      */
8017     smb_SetSMBParm(outp, 0, 0xffff);
8018     smb_SetSMBDataLength(outp, 0);
8019
8020     return 0;
8021 }
8022
8023 /* SMB_COM_READ */
8024 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8025 {
8026     osi_hyper_t offset;
8027     long count, finalCount;
8028     unsigned short fd;
8029     unsigned pid;
8030     smb_fid_t *fidp;
8031     smb_t *smbp = (smb_t*) inp;
8032     long code = 0;
8033     cm_user_t *userp;
8034     cm_scache_t *scp;
8035     char *op;
8036
8037     fd = smb_GetSMBParm(inp, 0);
8038     count = smb_GetSMBParm(inp, 1);
8039     offset.HighPart = 0;        /* too bad */
8040     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8041
8042     osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
8043              fd, offset.LowPart, count);
8044
8045     fd = smb_ChainFID(fd, inp);
8046     fidp = smb_FindFID(vcp, fd, 0);
8047     if (!fidp) {
8048         osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
8049                  vcp, fd);
8050         return CM_ERROR_BADFD;
8051     }
8052     lock_ObtainMutex(&fidp->mx);
8053     if (fidp->flags & SMB_FID_IOCTL) {
8054         lock_ReleaseMutex(&fidp->mx);
8055         code = smb_IoctlRead(fidp, vcp, inp, outp);
8056         smb_ReleaseFID(fidp);
8057         return code;
8058     }
8059
8060     if (fidp->flags & SMB_FID_RPC) {
8061         lock_ReleaseMutex(&fidp->mx);
8062         code = smb_RPCRead(fidp, vcp, inp, outp);
8063         smb_ReleaseFID(fidp);
8064         return code;
8065     }
8066
8067     if (!fidp->scp) {
8068         lock_ReleaseMutex(&fidp->mx);
8069         smb_ReleaseFID(fidp);
8070         return CM_ERROR_BADFD;
8071     }
8072
8073     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8074         lock_ReleaseMutex(&fidp->mx);
8075         smb_CloseFID(vcp, fidp, NULL, 0);
8076         smb_ReleaseFID(fidp);
8077         return CM_ERROR_NOSUCHFILE;
8078     }
8079
8080     scp = fidp->scp;
8081     cm_HoldSCache(scp);
8082     lock_ReleaseMutex(&fidp->mx);
8083
8084     {
8085         LARGE_INTEGER LOffset, LLength;
8086         cm_key_t key;
8087
8088         pid = smbp->pid;
8089         key = cm_GenerateKey(vcp->vcID, pid, fd);
8090
8091         LOffset.HighPart = 0;
8092         LOffset.LowPart = offset.LowPart;
8093         LLength.HighPart = 0;
8094         LLength.LowPart = count;
8095
8096         lock_ObtainWrite(&scp->rw);
8097         code = cm_LockCheckRead(scp, LOffset, LLength, key);
8098         lock_ReleaseWrite(&scp->rw);
8099     }
8100     if (code) {
8101         cm_ReleaseSCache(scp);
8102         smb_ReleaseFID(fidp);
8103         return code;
8104     }
8105
8106     userp = smb_GetUserFromVCP(vcp, inp);
8107
8108     /* remember this for final results */
8109     smb_SetSMBParm(outp, 0, count);
8110     smb_SetSMBParm(outp, 1, 0);
8111     smb_SetSMBParm(outp, 2, 0);
8112     smb_SetSMBParm(outp, 3, 0);
8113     smb_SetSMBParm(outp, 4, 0);
8114
8115     /* set the packet data length to 3 bytes for the data block header,
8116      * plus the size of the data.
8117      */
8118     smb_SetSMBDataLength(outp, count+3);
8119
8120     /* get op ptr after putting in the parms, since otherwise we don't
8121      * know where the data really is.
8122      */
8123     op = smb_GetSMBData(outp, NULL);
8124
8125     /* now emit the data block header: 1 byte of type and 2 bytes of length */
8126     *op++ = 1;  /* data block marker */
8127     *op++ = (unsigned char) (count & 0xff);
8128     *op++ = (unsigned char) ((count >> 8) & 0xff);
8129
8130     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
8131
8132     /* fix some things up */
8133     smb_SetSMBParm(outp, 0, finalCount);
8134     smb_SetSMBDataLength(outp, finalCount+3);
8135
8136     smb_ReleaseFID(fidp);
8137
8138     cm_ReleaseUser(userp);
8139     cm_ReleaseSCache(scp);
8140     return code;
8141 }
8142
8143 /* SMB_COM_CREATE_DIRECTORY */
8144 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8145 {
8146     clientchar_t *pathp;
8147     long code = 0;
8148     cm_space_t *spacep;
8149     unsigned char *tp;
8150     cm_user_t *userp;
8151     cm_scache_t *dscp;                  /* dir we're dealing with */
8152     cm_scache_t *scp;                   /* file we're creating */
8153     cm_attr_t setAttr;
8154     int initialModeBits;
8155     clientchar_t *lastNamep;
8156     int caseFold;
8157     clientchar_t *tidPathp;
8158     cm_req_t req;
8159
8160     smb_InitReq(&req);
8161
8162     scp = NULL;
8163
8164     /* compute initial mode bits based on read-only flag in attributes */
8165     initialModeBits = 0777;
8166
8167     tp = smb_GetSMBData(inp, NULL);
8168     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8169     if (!pathp)
8170         return CM_ERROR_BADSMB;
8171
8172     spacep = inp->spacep;
8173     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8174
8175     if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8176         return CM_ERROR_EXISTS;
8177
8178     userp = smb_GetUserFromVCP(vcp, inp);
8179
8180     caseFold = CM_FLAG_CASEFOLD;
8181
8182     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8183     if (code) {
8184         cm_ReleaseUser(userp);
8185         return CM_ERROR_NOSUCHPATH;
8186     }
8187
8188     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
8189                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8190                     userp, tidPathp, &req, &dscp);
8191
8192     if (code) {
8193         cm_ReleaseUser(userp);
8194         return code;
8195     }
8196
8197 #ifdef DFS_SUPPORT
8198     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8199         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8200         cm_ReleaseSCache(dscp);
8201         cm_ReleaseUser(userp);
8202         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8203             return CM_ERROR_PATH_NOT_COVERED;
8204         else
8205             return CM_ERROR_NOSUCHPATH;
8206     }
8207 #endif /* DFS_SUPPORT */
8208
8209     /* otherwise, scp points to the parent directory.  Do a lookup, and
8210      * fail if we find it.  Otherwise, we do the create.
8211      */
8212     if (!lastNamep)
8213         lastNamep = pathp;
8214     else
8215         lastNamep++;
8216     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8217     if (scp) cm_ReleaseSCache(scp);
8218     if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8219         if (code == 0) code = CM_ERROR_EXISTS;
8220         cm_ReleaseSCache(dscp);
8221         cm_ReleaseUser(userp);
8222         return code;
8223     }
8224
8225     setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8226     setAttr.clientModTime = time(NULL);
8227     smb_SetInitialModeBitsForDir(0, &setAttr);
8228
8229     code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8230     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8231         smb_NotifyChange(FILE_ACTION_ADDED,
8232                          FILE_NOTIFY_CHANGE_DIR_NAME,
8233                          dscp, lastNamep, NULL, TRUE);
8234
8235     /* we don't need this any longer */
8236     cm_ReleaseSCache(dscp);
8237
8238     if (code) {
8239         /* something went wrong creating or truncating the file */
8240         cm_ReleaseUser(userp);
8241         return code;
8242     }
8243
8244     /* otherwise we succeeded */
8245     smb_SetSMBDataLength(outp, 0);
8246     cm_ReleaseUser(userp);
8247
8248     return 0;
8249 }
8250
8251 BOOL smb_IsLegalFilename(clientchar_t *filename)
8252 {
8253     /*
8254      *  Find the longest substring of filename that does not contain
8255      *  any of the chars in illegalChars.  If that substring is less
8256      *  than the length of the whole string, then one or more of the
8257      *  illegal chars is in filename.
8258      */
8259     if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8260         return FALSE;
8261
8262     return TRUE;
8263 }
8264
8265 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8266 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8267 {
8268     clientchar_t *pathp;
8269     long code = 0;
8270     cm_space_t *spacep;
8271     unsigned char *tp;
8272     int excl;
8273     cm_user_t *userp;
8274     cm_scache_t *dscp;                  /* dir we're dealing with */
8275     cm_scache_t *scp;                   /* file we're creating */
8276     cm_attr_t setAttr;
8277     smb_fid_t *fidp;
8278     int attributes;
8279     clientchar_t *lastNamep;
8280     int caseFold;
8281     afs_uint32 dosTime;
8282     clientchar_t *tidPathp;
8283     cm_req_t req;
8284     int created = 0;                    /* the file was new */
8285
8286     smb_InitReq(&req);
8287
8288     scp = NULL;
8289     excl = (inp->inCom == 0x03)? 0 : 1;
8290
8291     attributes = smb_GetSMBParm(inp, 0);
8292     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8293
8294     tp = smb_GetSMBData(inp, NULL);
8295     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8296     if (!pathp)
8297         return CM_ERROR_BADSMB;
8298
8299     spacep = inp->spacep;
8300     /* smb_StripLastComponent will strip "::$DATA" if present */
8301     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8302
8303     if (!cm_IsValidClientString(pathp)) {
8304 #ifdef DEBUG
8305         clientchar_t * hexp;
8306
8307         hexp = cm_GetRawCharsAlloc(pathp, -1);
8308         osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8309                  osi_LogSaveClientString(smb_logp, hexp));
8310         if (hexp)
8311             free(hexp);
8312 #else
8313         osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8314 #endif
8315         return CM_ERROR_BADNTFILENAME;
8316     }
8317
8318     userp = smb_GetUserFromVCP(vcp, inp);
8319
8320     caseFold = CM_FLAG_CASEFOLD;
8321
8322     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8323     if (code) {
8324         cm_ReleaseUser(userp);
8325         return CM_ERROR_NOSUCHPATH;
8326     }
8327     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8328                     userp, tidPathp, &req, &dscp);
8329
8330     if (code) {
8331         cm_ReleaseUser(userp);
8332         return code;
8333     }
8334
8335 #ifdef DFS_SUPPORT
8336     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8337         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8338         cm_ReleaseSCache(dscp);
8339         cm_ReleaseUser(userp);
8340         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8341             return CM_ERROR_PATH_NOT_COVERED;
8342         else
8343             return CM_ERROR_NOSUCHPATH;
8344     }
8345 #endif /* DFS_SUPPORT */
8346
8347     /* otherwise, scp points to the parent directory.  Do a lookup, and
8348      * truncate the file if we find it, otherwise we create the file.
8349      */
8350     if (!lastNamep)
8351         lastNamep = pathp;
8352     else
8353         lastNamep++;
8354
8355     if (!smb_IsLegalFilename(lastNamep))
8356         return CM_ERROR_BADNTFILENAME;
8357
8358     osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8359 #ifdef DEBUG_VERBOSE
8360     {
8361         char *hexp;
8362         hexp = osi_HexifyString( lastNamep );
8363         DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8364         free(hexp);
8365     }
8366 #endif
8367
8368     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8369     if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8370         cm_ReleaseSCache(dscp);
8371         cm_ReleaseUser(userp);
8372         return code;
8373     }
8374
8375     /* if we get here, if code is 0, the file exists and is represented by
8376      * scp.  Otherwise, we have to create it.
8377      */
8378     if (code == 0) {
8379         if (excl) {
8380             /* oops, file shouldn't be there */
8381             cm_ReleaseSCache(dscp);
8382             cm_ReleaseSCache(scp);
8383             cm_ReleaseUser(userp);
8384             return CM_ERROR_EXISTS;
8385         }
8386
8387         setAttr.mask = CM_ATTRMASK_LENGTH;
8388         setAttr.length.LowPart = 0;
8389         setAttr.length.HighPart = 0;
8390         code = cm_SetAttr(scp, &setAttr, userp, &req);
8391     }
8392     else {
8393         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8394         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8395         smb_SetInitialModeBitsForFile(attributes, &setAttr);
8396
8397         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8398                          &req);
8399         if (code == 0) {
8400             created = 1;
8401             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8402                 smb_NotifyChange(FILE_ACTION_ADDED,
8403                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8404                                  dscp, lastNamep, NULL, TRUE);
8405         } else if (!excl && code == CM_ERROR_EXISTS) {
8406             /* not an exclusive create, and someone else tried
8407              * creating it already, then we open it anyway.  We
8408              * don't bother retrying after this, since if this next
8409              * fails, that means that the file was deleted after
8410              * we started this call.
8411              */
8412             code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8413                              &req, &scp);
8414             if (code == 0) {
8415                 setAttr.mask = CM_ATTRMASK_LENGTH;
8416                 setAttr.length.LowPart = 0;
8417                 setAttr.length.HighPart = 0;
8418                 code = cm_SetAttr(scp, &setAttr, userp, &req);
8419             }
8420         }
8421     }
8422
8423     /* we don't need this any longer */
8424     cm_ReleaseSCache(dscp);
8425
8426     if (code) {
8427         /* something went wrong creating or truncating the file */
8428         if (scp) cm_ReleaseSCache(scp);
8429         cm_ReleaseUser(userp);
8430         return code;
8431     }
8432
8433     /* make sure we only open files */
8434     if (scp->fileType != CM_SCACHETYPE_FILE) {
8435         cm_ReleaseSCache(scp);
8436         cm_ReleaseUser(userp);
8437         return CM_ERROR_ISDIR;
8438     }
8439
8440     /* now all we have to do is open the file itself */
8441     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8442     osi_assertx(fidp, "null smb_fid_t");
8443
8444     cm_HoldUser(userp);
8445
8446     lock_ObtainMutex(&fidp->mx);
8447     /* always create it open for read/write */
8448     fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8449
8450     /* remember that the file was newly created */
8451     if (created)
8452         fidp->flags |= SMB_FID_CREATED;
8453
8454     osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8455
8456     /* save a pointer to the vnode */
8457     fidp->scp = scp;
8458     lock_ObtainWrite(&scp->rw);
8459     scp->flags |= CM_SCACHEFLAG_SMB_FID;
8460     lock_ReleaseWrite(&scp->rw);
8461
8462     /* and the user */
8463     fidp->userp = userp;
8464     lock_ReleaseMutex(&fidp->mx);
8465
8466     smb_SetSMBParm(outp, 0, fidp->fid);
8467     smb_SetSMBDataLength(outp, 0);
8468
8469     cm_Open(scp, 0, userp);
8470
8471     smb_ReleaseFID(fidp);
8472     cm_ReleaseUser(userp);
8473     /* leave scp held since we put it in fidp->scp */
8474     return 0;
8475 }
8476
8477 /* SMB_COM_SEEK */
8478 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8479 {
8480     long code = 0;
8481     osi_hyper_t new_offset;
8482     long offset;
8483     int whence;
8484     unsigned short fd;
8485     smb_fid_t *fidp;
8486     cm_scache_t *scp;
8487     cm_user_t *userp;
8488     cm_req_t req;
8489
8490     smb_InitReq(&req);
8491
8492     fd = smb_GetSMBParm(inp, 0);
8493     whence = smb_GetSMBParm(inp, 1);
8494     offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8495
8496     /* try to find the file descriptor */
8497     fd = smb_ChainFID(fd, inp);
8498     fidp = smb_FindFID(vcp, fd, 0);
8499     if (!fidp) {
8500         osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8501                  vcp, fd);
8502         return CM_ERROR_BADFD;
8503     }
8504     lock_ObtainMutex(&fidp->mx);
8505     if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8506         lock_ReleaseMutex(&fidp->mx);
8507         smb_ReleaseFID(fidp);
8508         return CM_ERROR_BADFD;
8509     }
8510
8511     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8512         lock_ReleaseMutex(&fidp->mx);
8513         smb_CloseFID(vcp, fidp, NULL, 0);
8514         smb_ReleaseFID(fidp);
8515         return CM_ERROR_NOSUCHFILE;
8516     }
8517
8518     lock_ReleaseMutex(&fidp->mx);
8519
8520     userp = smb_GetUserFromVCP(vcp, inp);
8521
8522     lock_ObtainMutex(&fidp->mx);
8523     scp = fidp->scp;
8524     cm_HoldSCache(scp);
8525     lock_ReleaseMutex(&fidp->mx);
8526     lock_ObtainWrite(&scp->rw);
8527     code = cm_SyncOp(scp, NULL, userp, &req, 0,
8528                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8529     if (code == 0) {
8530         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8531         if (whence == 1) {
8532             /* offset from current offset */
8533             new_offset = LargeIntegerAdd(fidp->offset,
8534                                          ConvertLongToLargeInteger(offset));
8535         }
8536         else if (whence == 2) {
8537             /* offset from current EOF */
8538             new_offset = LargeIntegerAdd(scp->length,
8539                                          ConvertLongToLargeInteger(offset));
8540         } else {
8541             new_offset = ConvertLongToLargeInteger(offset);
8542         }
8543
8544         fidp->offset = new_offset;
8545         smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8546         smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8547         smb_SetSMBDataLength(outp, 0);
8548     }
8549     lock_ReleaseWrite(&scp->rw);
8550     smb_ReleaseFID(fidp);
8551     cm_ReleaseSCache(scp);
8552     cm_ReleaseUser(userp);
8553     return code;
8554 }
8555
8556 /* dispatch all of the requests received in a packet.  Due to chaining, this may
8557  * be more than one request.
8558  */
8559 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8560                         NCB *ncbp, raw_write_cont_t *rwcp)
8561 {
8562     smb_dispatch_t *dp;
8563     smb_t *smbp;
8564     unsigned long code = 0;
8565     unsigned char *outWctp;
8566     int nparms;                 /* # of bytes of parameters */
8567     char tbuffer[200];
8568     int nbytes;                 /* bytes of data, excluding count */
8569     int temp;
8570     unsigned char *tp;
8571     unsigned short errCode;
8572     unsigned long NTStatus;
8573     int noSend;
8574     unsigned char errClass;
8575     unsigned int oldGen;
8576     DWORD oldTime, newTime;
8577
8578     /* get easy pointer to the data */
8579     smbp = (smb_t *) inp->data;
8580
8581     if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8582         /* setup the basic parms for the initial request in the packet */
8583         inp->inCom = smbp->com;
8584         inp->wctp = &smbp->wct;
8585         inp->inCount = 0;
8586         inp->ncb_length = ncbp->ncb_length;
8587     }
8588     noSend = 0;
8589
8590     /* Sanity check */
8591     if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8592         /* log it and discard it */
8593         LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8594                  __FILE__, __LINE__, ncbp->ncb_length);
8595         osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8596         return;
8597     }
8598
8599     /* We are an ongoing op */
8600     thrd_Increment(&ongoingOps);
8601
8602     /* set up response packet for receiving output */
8603     if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8604         smb_FormatResponsePacket(vcp, inp, outp);
8605     outWctp = outp->wctp;
8606
8607     /* Remember session generation number and time */
8608     oldGen = sessionGen;
8609     oldTime = GetTickCount();
8610
8611     while (inp->inCom != 0xff) {
8612         dp = &smb_dispatchTable[inp->inCom];
8613
8614         if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8615             outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8616             code = outp->resumeCode;
8617             goto resume;
8618         }
8619
8620         /* process each request in the packet; inCom, wctp and inCount
8621          * are already set up.
8622          */
8623         osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8624                   ncbp->ncb_lsn);
8625
8626         /* now do the dispatch */
8627         /* start by formatting the response record a little, as a default */
8628         if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8629             outWctp[0] = 2;
8630             outWctp[1] = 0xff;  /* no operation */
8631             outWctp[2] = 0;             /* padding */
8632             outWctp[3] = 0;
8633             outWctp[4] = 0;
8634         }
8635         else {
8636             /* not a chained request, this is a more reasonable default */
8637             outWctp[0] = 0;     /* wct of zero */
8638             outWctp[1] = 0;     /* and bcc (word) of zero */
8639             outWctp[2] = 0;
8640         }
8641
8642         /* once set, stays set.  Doesn't matter, since we never chain
8643          * "no response" calls.
8644          */
8645         if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8646             noSend = 1;
8647
8648         if (dp->procp) {
8649             /* we have a recognized operation */
8650             char * opName = myCrt_Dispatch(inp->inCom);
8651             smb_t *smbp;
8652
8653             smbp = (smb_t *) inp;
8654
8655             osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8656                       opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8657             if (inp->inCom == 0x1d) {
8658                 /* Raw Write */
8659                 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8660             } else {
8661                 code = (*(dp->procp)) (vcp, inp, outp);
8662             }
8663             osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8664                       code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8665
8666             newTime = GetTickCount();
8667             osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8668                      opName, smbp->mid, newTime - oldTime);
8669
8670 #ifdef LOG_PACKET
8671             if ( code == CM_ERROR_BADSMB ||
8672                  code == CM_ERROR_BADOP )
8673                 smb_LogPacket(inp);
8674 #endif /* LOG_PACKET */
8675
8676             /* ReceiveV3Tran2A handles its own logging */
8677             if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8678                 smb_user_t *uidp;
8679                 smb_fid_t *fidp;
8680                 clientchar_t *treepath = NULL;  /* do not free */
8681                 clientchar_t *pathname = NULL;
8682                 cm_fid_t afid = {0,0,0,0,0};
8683
8684                 uidp = smb_FindUID(vcp, smbp->uid, 0);
8685                 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8686                 fidp = smb_FindFID(vcp, inp->fid, 0);
8687
8688                 if (fidp) {
8689                     lock_ObtainMutex(&fidp->mx);
8690                     if (fidp->NTopen_pathp)
8691                         pathname = fidp->NTopen_pathp;
8692                     if (fidp->scp)
8693                         afid = fidp->scp->fid;
8694                 } else {
8695                     if (inp->stringsp->wdata)
8696                         pathname = inp->stringsp->wdata;
8697                 }
8698
8699                 afsi_log("Request %s duration %d ms user 0x%x \"%S\" pid 0x%x mid 0x%x tid 0x%x \"%S\" path? \"%S\" afid (%d.%d.%d.%d)",
8700                           opName, newTime - oldTime,
8701                           smbp->uid, uidp ? uidp->unp->name : NULL,
8702                           smbp->pid, smbp->mid, smbp->tid,
8703                           treepath,
8704                           pathname,
8705                           afid.cell, afid.volume, afid.vnode, afid.unique);
8706
8707                 if (fidp)
8708                     lock_ReleaseMutex(&fidp->mx);
8709
8710                 if (uidp)
8711                     smb_ReleaseUID(uidp);
8712                 if (fidp)
8713                     smb_ReleaseFID(fidp);
8714             }
8715
8716             if (oldGen != sessionGen) {
8717                 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8718                          newTime - oldTime, ncbp->ncb_length);
8719                 osi_Log3(smb_logp, "Request %s straddled session startup, "
8720                           "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8721             }
8722
8723             FreeSMBStrings(inp);
8724         } else {
8725             /* bad opcode, fail the request, after displaying it */
8726             osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8727 #ifdef LOG_PACKET
8728             smb_LogPacket(inp);
8729 #endif  /* LOG_PACKET */
8730
8731             if (showErrors) {
8732                 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8733                 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8734                                       MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8735                 if (code == IDCANCEL)
8736                     showErrors = 0;
8737             }
8738             code = CM_ERROR_BADOP;
8739         }
8740
8741         /* catastrophic failure:  log as much as possible */
8742         if (code == CM_ERROR_BADSMB) {
8743             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8744                      ncbp->ncb_length);
8745 #ifdef LOG_PACKET
8746             smb_LogPacket(inp);
8747 #endif /* LOG_PACKET */
8748             osi_Log1(smb_logp, "Invalid SMB message, length %d",
8749                      ncbp->ncb_length);
8750
8751             code = CM_ERROR_INVAL;
8752         }
8753
8754         if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8755             thrd_Decrement(&ongoingOps);
8756             return;
8757         }
8758
8759       resume:
8760         /* now, if we failed, turn the current response into an empty
8761          * one, and fill in the response packet's error code.
8762          */
8763         if (code) {
8764             if (vcp->flags & SMB_VCFLAG_STATUS32) {
8765                 smb_MapNTError(code, &NTStatus, FALSE);
8766                 outWctp = outp->wctp;
8767                 smbp = (smb_t *) &outp->data;
8768                 if (code != CM_ERROR_PARTIALWRITE
8769                      && code != CM_ERROR_BUFFERTOOSMALL
8770                      && code != CM_ERROR_GSSCONTINUE) {
8771                     /* nuke wct and bcc.  For a partial
8772                      * write or an in-process authentication handshake,
8773                      * assume they're OK.
8774                      */
8775                     *outWctp++ = 0;
8776                     *outWctp++ = 0;
8777                     *outWctp++ = 0;
8778                 }
8779                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8780                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8781                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8782                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8783                 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8784                 break;
8785             }
8786             else {
8787                 smb_MapCoreError(code, vcp, &errCode, &errClass);
8788                 outWctp = outp->wctp;
8789                 smbp = (smb_t *) &outp->data;
8790                 if (code != CM_ERROR_PARTIALWRITE) {
8791                     /* nuke wct and bcc.  For a partial
8792                      * write, assume they're OK.
8793                      */
8794                     *outWctp++ = 0;
8795                     *outWctp++ = 0;
8796                     *outWctp++ = 0;
8797                 }
8798                 smbp->errLow = (unsigned char) (errCode & 0xff);
8799                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8800                 smbp->rcls = errClass;
8801                 break;
8802             }
8803         }       /* error occurred */
8804
8805         /* if we're here, we've finished one request.  Look to see if
8806          * this is a chained opcode.  If it is, setup things to process
8807          * the chained request, and setup the output buffer to hold the
8808          * chained response.  Start by finding the next input record.
8809          */
8810         if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8811             break;              /* not a chained req */
8812         tp = inp->wctp;         /* points to start of last request */
8813         /* in a chained request, the first two
8814          * parm fields are required, and are
8815          * AndXCommand/AndXReserved and
8816          * AndXOffset. */
8817         if (tp[0] < 2) break;
8818         if (tp[1] == 0xff) break;       /* no more chained opcodes */
8819         inp->inCom = tp[1];
8820         inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8821         inp->inCount++;
8822
8823         /* and now append the next output request to the end of this
8824          * last request.  Begin by finding out where the last response
8825          * ends, since that's where we'll put our new response.
8826          */
8827         outWctp = outp->wctp;           /* ptr to out parameters */
8828         osi_assert (outWctp[0] >= 2);   /* need this for all chained requests */
8829         nparms = outWctp[0] << 1;
8830         tp = outWctp + nparms + 1;      /* now points to bcc field */
8831         nbytes = tp[0] + (tp[1] << 8);  /* # of data bytes */
8832         tp += 2 /* for the count itself */ + nbytes;
8833         /* tp now points to the new output record; go back and patch the
8834          * second parameter (off2) to point to the new record.
8835          */
8836         temp = (unsigned int)(tp - outp->data);
8837         outWctp[3] = (unsigned char) (temp & 0xff);
8838         outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8839         outWctp[2] = 0; /* padding */
8840         outWctp[1] = inp->inCom;        /* next opcode */
8841
8842         /* finally, setup for the next iteration */
8843         outp->wctp = tp;
8844         outWctp = tp;
8845     }   /* while loop over all requests in the packet */
8846
8847     /* now send the output packet, and return */
8848     if (!noSend)
8849         smb_SendPacket(vcp, outp);
8850     thrd_Decrement(&ongoingOps);
8851
8852     return;
8853 }
8854
8855 /* Wait for Netbios() calls to return, and make the results available to server
8856  * threads.  Note that server threads can't wait on the NCBevents array
8857  * themselves, because NCB events are manual-reset, and the servers would race
8858  * each other to reset them.
8859  */
8860 void smb_ClientWaiter(void *parmp)
8861 {
8862     DWORD code;
8863     int   idx;
8864
8865     while (smbShutdownFlag == 0) {
8866         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8867                                                  FALSE, INFINITE);
8868         if (code == WAIT_OBJECT_0)
8869             continue;
8870
8871         /* error checking */
8872         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8873         {
8874             int abandonIdx = code - WAIT_ABANDONED_0;
8875             osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8876         }
8877
8878         if (code == WAIT_IO_COMPLETION)
8879         {
8880             osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8881             continue;
8882         }
8883
8884         if (code == WAIT_TIMEOUT)
8885         {
8886             osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8887         }
8888
8889         if (code == WAIT_FAILED)
8890         {
8891             osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8892         }
8893
8894         idx = code - WAIT_OBJECT_0;
8895
8896         /* check idx range! */
8897         if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8898         {
8899             /* this is fatal - log as much as possible */
8900             osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8901             osi_assertx(0, "invalid index");
8902         }
8903
8904         thrd_ResetEvent(NCBevents[idx]);
8905         thrd_SetEvent(NCBreturns[0][idx]);
8906     }
8907 }
8908
8909 /*
8910  * Try to have one NCBRECV request waiting for every live session.  Not more
8911  * than one, because if there is more than one, it's hard to handle Write Raw.
8912  */
8913 void smb_ServerWaiter(void *parmp)
8914 {
8915     DWORD code;
8916     int idx_session, idx_NCB;
8917     NCB *ncbp;
8918
8919     while (smbShutdownFlag == 0) {
8920         /* Get a session */
8921         code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8922                                                  FALSE, INFINITE);
8923         if (code == WAIT_OBJECT_0)
8924             continue;
8925
8926         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8927         {
8928             int abandonIdx = code - WAIT_ABANDONED_0;
8929             osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8930         }
8931
8932         if (code == WAIT_IO_COMPLETION)
8933         {
8934             osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8935             continue;
8936         }
8937
8938         if (code == WAIT_TIMEOUT)
8939         {
8940             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8941         }
8942
8943         if (code == WAIT_FAILED)
8944         {
8945             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8946         }
8947
8948         idx_session = code - WAIT_OBJECT_0;
8949
8950         /* check idx range! */
8951         if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8952         {
8953             /* this is fatal - log as much as possible */
8954             osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8955             osi_assertx(0, "invalid index");
8956         }
8957
8958                 /* Get an NCB */
8959       NCBretry:
8960         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8961                                                  FALSE, INFINITE);
8962         if (code == WAIT_OBJECT_0) {
8963             if (smbShutdownFlag == 1)
8964                 break;
8965             else
8966                 goto NCBretry;
8967         }
8968
8969         /* error checking */
8970         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8971         {
8972             int abandonIdx = code - WAIT_ABANDONED_0;
8973             osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8974         }
8975
8976         if (code == WAIT_IO_COMPLETION)
8977         {
8978             osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8979             continue;
8980         }
8981
8982         if (code == WAIT_TIMEOUT)
8983         {
8984             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8985         }
8986
8987         if (code == WAIT_FAILED)
8988         {
8989             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8990         }
8991
8992         idx_NCB = code - WAIT_OBJECT_0;
8993
8994         /* check idx range! */
8995         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8996         {
8997             /* this is fatal - log as much as possible */
8998             osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8999             osi_assertx(0, "invalid index");
9000         }
9001
9002         /* Link them together */
9003         NCBsessions[idx_NCB] = idx_session;
9004
9005         /* Fire it up */
9006         ncbp = NCBs[idx_NCB];
9007         ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
9008         ncbp->ncb_command = NCBRECV | ASYNCH;
9009         ncbp->ncb_lana_num = lanas[idx_session];
9010         ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
9011         ncbp->ncb_event = NCBevents[idx_NCB];
9012         ncbp->ncb_length = SMB_PACKETSIZE;
9013         Netbios(ncbp);
9014     }
9015 }
9016
9017 typedef struct _monitored_task {
9018     osi_queue_t q;
9019     INT_PTR     task_id;
9020     LARGE_INTEGER start_time;
9021     BOOL        started;
9022     BOOL        trace_timer_hit;
9023     BOOL        dump_timer_hit;
9024 } monitored_task;
9025
9026 typedef struct osi_queueHT {
9027     osi_queue_t * headp;
9028     osi_queue_t * tailp;
9029 } osi_queueHT_t;
9030
9031 static osi_queue_t *smb_monitored_tasks = NULL;
9032 static osi_queue_t *smb_free_monitored_tasks = NULL;
9033
9034 static osi_mutex_t _monitor_mx;
9035
9036 static HANDLE h_monitored_task_queue    = NULL;
9037 static HANDLE h_monitored_task_shutdown = NULL;
9038
9039 static time_t smb_last_dump_time = 0;
9040
9041 DWORD  smb_monitorReqs = 0;
9042
9043 /* FILETIME comparison fuzz */
9044 #define MONITOR_FUZZ_TIMEOUT    (1 * 10000000i64)
9045
9046 /* Trace timeout is at 60 seconds */
9047 #define MONITOR_TRACE_TIMEOUT   (60 * 10000000i64)
9048
9049 /* Dump timeout is at 120 seconds */
9050 #define MONITOR_DUMP_TIMEOUT    (120 * 10000000i64)
9051
9052 /* Time before another dump is performed in seconds*/
9053 #define MONITOR_DUMP_RESET_TIMEOUT  (600)
9054
9055 static void smb_PurgeOldTaskMonitors(osi_queueHT_t * taskmq)
9056 {
9057     FILETIME now;
9058     LARGE_INTEGER earliest;
9059     monitored_task * t;
9060
9061     GetSystemTimeAsFileTime(&now);
9062     earliest.LowPart = now.dwLowDateTime;
9063     earliest.HighPart = now.dwHighDateTime;
9064     earliest.QuadPart -= MONITOR_FUZZ_TIMEOUT + MONITOR_DUMP_TIMEOUT;
9065
9066     while ((t = (monitored_task *) taskmq->headp) != NULL &&
9067
9068            (t->start_time.QuadPart < earliest.QuadPart ||
9069
9070             t->dump_timer_hit)) {
9071
9072         osi_QRemoveHT(&taskmq->headp,
9073                       &taskmq->tailp,
9074                       &t->q);
9075
9076         lock_ObtainMutex(&_monitor_mx);
9077         osi_QAdd(&smb_free_monitored_tasks, &t->q);
9078         lock_ReleaseMutex(&_monitor_mx);
9079     }
9080
9081 #ifdef INVARIANT_CHECK
9082     {
9083         LARGE_INTEGER last;
9084
9085         last.QuadPart = 0;
9086
9087         for (t = (monitored_task *) taskmq->headp;
9088              t;
9089              t = (monitored_task *) osi_QNext(&t->q)) {
9090             osi_assert(last.QuadPart <= t->start_time.QuadPart);
9091             last.QuadPart = t->start_time.QuadPart;
9092         }
9093     }
9094 #endif
9095 }
9096
9097 static void smb_SlurpNewTaskMonitors(osi_queueHT_t * taskmq)
9098 {
9099     monitored_task * task;
9100     monitored_task * tasks;
9101
9102     lock_ObtainMutex(&_monitor_mx);
9103     tasks = (monitored_task *) smb_monitored_tasks;
9104     smb_monitored_tasks = NULL;
9105     lock_ReleaseMutex(&_monitor_mx);
9106
9107     while (tasks) {
9108
9109         task = tasks;
9110         osi_QRemove((osi_queue_t **) &tasks, &task->q);
9111
9112         if (task->started) {
9113
9114             osi_queue_t q;
9115             osi_queue_t *p;
9116
9117             q.nextp = NULL;
9118             q.prevp = taskmq->tailp;
9119
9120             /* Insertion sort by start_time.  Earliest request is
9121                first.  Since we are likely to receive new requests
9122                later, we start inserting from the back. */
9123             for (p = &q;
9124                  osi_QPrev(p) &&
9125                      ((monitored_task *) osi_QPrev(p))->start_time.QuadPart > task->start_time.QuadPart;
9126                  p = osi_QPrev(p));
9127
9128             if (p == &q)
9129                 osi_QAddT(&taskmq->headp, &taskmq->tailp, &task->q);
9130             else if (p->prevp == NULL)
9131                 osi_QAddH(&taskmq->headp, &taskmq->tailp, &task->q);
9132             else {
9133                 osi_queue_t *o = p->prevp;
9134
9135                 osi_assert(o->nextp == p);
9136
9137                 task->q.nextp = p;
9138                 task->q.prevp = o;
9139                 p->prevp = &task->q;
9140                 o->nextp = &task->q;
9141             }
9142
9143         } else {
9144             /* Some task ending */
9145
9146             osi_queue_t * p;
9147
9148             for (p = taskmq->headp;
9149                  p != NULL;
9150                  p = osi_QNext(p)) {
9151
9152                 monitored_task * mt = (monitored_task *) p;
9153
9154                 if (mt->task_id == task->task_id) {
9155
9156                     osi_QRemoveHT(&taskmq->headp,
9157                                   &taskmq->tailp, p);
9158
9159                     lock_ObtainMutex(&_monitor_mx);
9160                     osi_QAdd(&smb_free_monitored_tasks, p);
9161                     lock_ReleaseMutex(&_monitor_mx);
9162
9163                     break;
9164                 }
9165             }
9166
9167             lock_ObtainMutex(&_monitor_mx);
9168             osi_QAdd(&smb_free_monitored_tasks, &task->q);
9169             lock_ReleaseMutex(&_monitor_mx);
9170         }
9171     }
9172
9173 #ifdef INVARIANT_CHECK
9174     {
9175         LARGE_INTEGER last;
9176         monitored_task * t;
9177
9178         last.QuadPart = 0;
9179
9180         for (t = (monitored_task *) taskmq->headp;
9181              t;
9182              t = (monitored_task *) osi_QNext(&t->q)) {
9183             osi_assert(last.QuadPart <= t->start_time.QuadPart);
9184             last.QuadPart = t->start_time.QuadPart;
9185         }
9186     }
9187 #endif
9188 }
9189
9190 static void smb_HandleTaskMonitorEvent(monitored_task * task)
9191 {
9192     if (!task->trace_timer_hit) {
9193
9194         task->trace_timer_hit = TRUE;
9195
9196         osi_LogEnable(afsd_logp);
9197         rx_DebugOnOff(TRUE);
9198
9199     } else if (!task->dump_timer_hit) {
9200         time_t now;
9201
9202         time(&now);
9203
9204         if (smb_last_dump_time + MONITOR_DUMP_RESET_TIMEOUT < now) {
9205             task->dump_timer_hit = TRUE;
9206             smb_last_dump_time = now;
9207
9208             GenerateMiniDump(NULL);
9209         }
9210     }
9211 }
9212
9213 /**
9214  * Server request monitoring
9215  *
9216  * The server monitor runs in a separate thread and monitors server
9217  * requests for potential timeouts.  It examines notifcations queued
9218  * by smb_NotifyRequestEvent() and waits for potential timeout events:
9219  *
9220  * - After MONITOR_TRACE_TIMEOUT threshold elapses, the monitor
9221  *   enables trace logging.
9222  *
9223  * - After MONITOR_DUMP_TIMEOUT threshold elapses, the monitor writes
9224  *   out a dump file that will hopefully contain enough evidence to
9225  *   figure out why the timeout event occurred.
9226  *
9227  */
9228 void smb_ServerMonitor(VOID * parmp)
9229 {
9230     osi_queueHT_t in_progress = { NULL, NULL };
9231     HANDLE h_timer = NULL;
9232
9233     HANDLE h_all[3];
9234
9235     h_monitored_task_queue = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitor");
9236     h_monitored_task_shutdown = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitorShutdown");
9237     h_timer = CreateWaitableTimer(NULL, FALSE, "Local\\OpenAFSTaskMonitorTimer");
9238
9239     lock_InitializeMutex(&_monitor_mx, "Request monitor lock", LOCK_HIERARCHY_SMB_MONITOR);
9240
9241     h_all[0] = h_monitored_task_queue;
9242     h_all[1] = h_timer;
9243     h_all[2] = h_monitored_task_shutdown;
9244
9245     while(1) {
9246         DWORD rv;
9247
9248         rv = WaitForMultipleObjects(3, h_all, FALSE, INFINITE);
9249
9250         if (rv == WAIT_OBJECT_0) {
9251
9252             smb_SlurpNewTaskMonitors(&in_progress);
9253
9254         } else if (rv == WAIT_OBJECT_0 + 1) {
9255
9256             smb_HandleTaskMonitorEvent((monitored_task *) in_progress.headp);
9257
9258         } else {
9259
9260             break;
9261
9262         }
9263
9264         /* refresh timers */
9265         {
9266             monitored_task * t;
9267
9268             smb_PurgeOldTaskMonitors(&in_progress);
9269             t = (monitored_task *) in_progress.headp;
9270
9271             if (t && !t->trace_timer_hit) {
9272                 LARGE_INTEGER due;
9273
9274                 due = t->start_time;
9275                 due.QuadPart += MONITOR_TRACE_TIMEOUT;
9276
9277                 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9278             } else if (t && !t->dump_timer_hit) {
9279
9280                 LARGE_INTEGER due;
9281
9282                 due = t->start_time;
9283                 due.QuadPart += MONITOR_DUMP_TIMEOUT;
9284
9285                 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9286             } else {
9287                 CancelWaitableTimer(h_timer);
9288
9289                 /* CancelWaitableTimer() doesn't reset the timer if it
9290                    was already signalled. */
9291                 WaitForSingleObject(h_timer, 0);
9292             }
9293         }
9294     }
9295
9296     {
9297         HANDLE h;
9298
9299         h = h_monitored_task_queue;
9300         h_monitored_task_queue = NULL;
9301         CloseHandle(h);
9302
9303         h = h_monitored_task_shutdown;
9304         h_monitored_task_shutdown = NULL;
9305         CloseHandle(h);
9306
9307         CloseHandle(h_timer);
9308
9309         lock_FinalizeMutex(&_monitor_mx);
9310     }
9311
9312     {
9313         monitored_task * task;
9314
9315         while (in_progress.headp) {
9316             task = (monitored_task *) in_progress.headp;
9317             osi_QRemoveHT(&in_progress.headp, &in_progress.tailp, &task->q);
9318             free(task);
9319         }
9320
9321         for (task = (monitored_task  *) smb_free_monitored_tasks;
9322              task; task = (monitored_task *) smb_free_monitored_tasks) {
9323             osi_QRemove(&smb_free_monitored_tasks, &task->q);
9324             free(task);
9325         }
9326
9327         for (task = (monitored_task *) smb_monitored_tasks;
9328              task; task = (monitored_task *) smb_monitored_tasks) {
9329             osi_QRemove(&smb_monitored_tasks, &task->q);
9330             free(task);
9331         }
9332     }
9333 }
9334
9335 void smb_NotifyRequestEvent(INT_PTR task_id, BOOL started)
9336 {
9337     monitored_task * task;
9338
9339     lock_ObtainMutex(&_monitor_mx);
9340     task = (monitored_task *) smb_free_monitored_tasks;
9341     if (task)
9342         osi_QRemove(&smb_free_monitored_tasks, &task->q);
9343     lock_ReleaseMutex(&_monitor_mx);
9344
9345     if (task == NULL)
9346         task = malloc(sizeof(monitored_task));
9347     memset(task, 0, sizeof(*task));
9348
9349     task->task_id = task_id;
9350     task->started = started;
9351
9352     {
9353         FILETIME now;
9354
9355         GetSystemTimeAsFileTime(&now);
9356         task->start_time.HighPart = now.dwHighDateTime;
9357         task->start_time.LowPart = now.dwLowDateTime;
9358     }
9359
9360     lock_ObtainMutex(&_monitor_mx);
9361     osi_QAdd(&smb_monitored_tasks, &task->q);
9362     lock_ReleaseMutex(&_monitor_mx);
9363
9364     SetEvent(h_monitored_task_queue);
9365 }
9366
9367 void smb_ShutdownMonitor()
9368 {
9369     SetEvent(h_monitored_task_shutdown);
9370 }
9371
9372 /*
9373  * The top level loop for handling SMB request messages.  Each server thread
9374  * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
9375  * NCB and buffer for the incoming request are loaned to us.
9376  *
9377  * Write Raw trickery starts here.  When we get a Write Raw, we are supposed
9378  * to immediately send a request for the rest of the data.  This must come
9379  * before any other traffic for that session, so we delay setting the session
9380  * event until that data has come in.
9381  */
9382 void smb_Server(VOID *parmp)
9383 {
9384     INT_PTR myIdx = (INT_PTR) parmp;
9385     NCB *ncbp;
9386     NCB *outncbp;
9387     smb_packet_t *bufp;
9388     smb_packet_t *outbufp;
9389     DWORD code, rcode;
9390     int idx_NCB, idx_session;
9391     UCHAR rc;
9392     smb_vc_t *vcp = NULL;
9393     smb_t *smbp;
9394
9395     rx_StartClientThread();
9396
9397     outncbp = smb_GetNCB();
9398     outbufp = smb_GetPacket();
9399     outbufp->ncbp = outncbp;
9400
9401     while (1) {
9402         if (vcp) {
9403             smb_ReleaseVC(vcp);
9404             vcp = NULL;
9405         }
9406
9407         cm_ResetServerPriority();
9408
9409         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
9410                                                  FALSE, INFINITE);
9411
9412         /* terminate silently if shutdown flag is set */
9413         if (code == WAIT_OBJECT_0) {
9414             if (smbShutdownFlag == 1) {
9415                 thrd_SetEvent(smb_ServerShutdown[myIdx]);
9416                 break;
9417             } else
9418                 continue;
9419         }
9420
9421         /* error checking */
9422         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
9423         {
9424             int abandonIdx = code - WAIT_ABANDONED_0;
9425             osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
9426         }
9427
9428         if (code == WAIT_IO_COMPLETION)
9429         {
9430             osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
9431             continue;
9432         }
9433
9434         if (code == WAIT_TIMEOUT)
9435         {
9436             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
9437         }
9438
9439         if (code == WAIT_FAILED)
9440         {
9441             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
9442         }
9443
9444         idx_NCB = code - WAIT_OBJECT_0;
9445
9446         /* check idx range! */
9447         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
9448         {
9449             /* this is fatal - log as much as possible */
9450             osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
9451             osi_assertx(0, "invalid index");
9452         }
9453
9454         ncbp = NCBs[idx_NCB];
9455         idx_session = NCBsessions[idx_NCB];
9456         rc = ncbp->ncb_retcode;
9457
9458         if (rc != NRC_PENDING && rc != NRC_GOODRET)
9459             osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
9460
9461         switch (rc) {
9462         case NRC_GOODRET:
9463             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9464             break;
9465
9466         case NRC_PENDING:
9467             /* Can this happen? Or is it just my UNIX paranoia? */
9468             osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
9469             continue;
9470
9471         case NRC_SNUMOUT:
9472         case NRC_SABORT:
9473             LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
9474             AFS_FALLTHROUGH;
9475         case NRC_SCLOSED:
9476             /* Client closed session */
9477             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9478             if (vcp) {
9479                 lock_ObtainMutex(&vcp->mx);
9480                 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9481                     osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9482                              vcp, vcp->usersp);
9483                     vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9484                     lock_ReleaseMutex(&vcp->mx);
9485                     lock_ObtainWrite(&smb_globalLock);
9486                     dead_sessions[vcp->session] = TRUE;
9487                     lock_ReleaseWrite(&smb_globalLock);
9488                 } else {
9489                     lock_ReleaseMutex(&vcp->mx);
9490                 }
9491                 smb_CleanupDeadVC(vcp);
9492                 smb_ReleaseVC(vcp);
9493                 vcp = NULL;
9494             }
9495             goto doneWithNCB;
9496
9497         case NRC_INCOMP:
9498             /* Treat as transient error */
9499             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
9500                      ncbp->ncb_length);
9501             osi_Log1(smb_logp,
9502                      "dispatch smb recv failed, message incomplete, ncb_length %d",
9503                      ncbp->ncb_length);
9504             osi_Log1(smb_logp,
9505                      "SMB message incomplete, "
9506                      "length %d", ncbp->ncb_length);
9507
9508             /*
9509              * We used to discard the packet.
9510              * Instead, try handling it normally.
9511              *
9512              continue;
9513              */
9514             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9515             break;
9516
9517         default:
9518             /* A weird error code.  Log it, sleep, and continue. */
9519             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9520             if (vcp) {
9521                 lock_ObtainMutex(&vcp->mx);
9522                 if (vcp->errorCount++ > 3) {
9523                     osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9524                     if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9525                         osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9526                                  vcp, vcp->usersp);
9527                         vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9528                         lock_ReleaseMutex(&vcp->mx);
9529                         lock_ObtainWrite(&smb_globalLock);
9530                         dead_sessions[vcp->session] = TRUE;
9531                         lock_ReleaseWrite(&smb_globalLock);
9532                     } else {
9533                         lock_ReleaseMutex(&vcp->mx);
9534                     }
9535                     smb_CleanupDeadVC(vcp);
9536                     smb_ReleaseVC(vcp);
9537                     vcp = NULL;
9538                     goto doneWithNCB;
9539                 }
9540                 else {
9541                     lock_ReleaseMutex(&vcp->mx);
9542                     smb_ReleaseVC(vcp);
9543                     vcp = NULL;
9544                     Sleep(10);
9545                     thrd_SetEvent(SessionEvents[idx_session]);
9546                 }
9547             }
9548             continue;
9549         }
9550
9551         /* Success, so now dispatch on all the data in the packet */
9552
9553         smb_concurrentCalls++;
9554         if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9555             smb_maxObsConcurrentCalls = smb_concurrentCalls;
9556
9557         /*
9558          * If at this point vcp is NULL (implies that packet was invalid)
9559          * then we are in big trouble. This means either :
9560          *   a) we have the wrong NCB.
9561          *   b) Netbios screwed up the call.
9562          *   c) The VC was already marked dead before we were able to
9563          *      process the call
9564          * Obviously this implies that
9565          *   ( LSNs[idx_session] != ncbp->ncb_lsn ||
9566          *   lanas[idx_session] != ncbp->ncb_lana_num )
9567          * Either way, we can't do anything with this packet.
9568          * Log, sleep and resume.
9569          */
9570         if (!vcp) {
9571             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9572                      LSNs[idx_session],
9573                      lanas[idx_session],
9574                      ncbp->ncb_lsn,
9575                      ncbp->ncb_lana_num);
9576
9577             /* Also log in the trace log. */
9578             osi_Log4(smb_logp, "Server: VCP does not exist!"
9579                       "LSNs[idx_session]=[%d],"
9580                       "lanas[idx_session]=[%d],"
9581                       "ncbp->ncb_lsn=[%d],"
9582                       "ncbp->ncb_lana_num=[%d]",
9583                       LSNs[idx_session],
9584                       lanas[idx_session],
9585                       ncbp->ncb_lsn,
9586                       ncbp->ncb_lana_num);
9587
9588             /* thrd_Sleep(1000); Don't bother sleeping */
9589             thrd_SetEvent(SessionEvents[idx_session]);
9590             smb_concurrentCalls--;
9591             continue;
9592         }
9593
9594         cm_SetRequestStartTime();
9595         if (smb_monitorReqs) {
9596             smb_NotifyRequestEvent(GetCurrentThreadId(), TRUE);
9597         }
9598
9599         vcp->errorCount = 0;
9600         bufp = (struct smb_packet *) ncbp->ncb_buffer;
9601         smbp = (smb_t *)bufp->data;
9602         outbufp->flags = 0;
9603
9604 #ifndef NOTRACE
9605         __try
9606         {
9607 #endif
9608             if (smbp->com == 0x1d) {
9609                 /* Special handling for Write Raw */
9610                 raw_write_cont_t rwc;
9611
9612                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9613                 if (rwc.code == 0) {
9614                     EVENT_HANDLE rwevent;
9615                     char eventName[MAX_PATH];
9616
9617                     snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9618                     rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9619                     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9620                         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9621
9622                     ncbp->ncb_command = NCBRECV | ASYNCH;
9623                     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9624                     ncbp->ncb_lana_num = vcp->lana;
9625                     ncbp->ncb_buffer = rwc.buf;
9626                     ncbp->ncb_length = 65535;
9627                     ncbp->ncb_event = rwevent;
9628                     Netbios(ncbp);
9629                     rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9630                     thrd_CloseHandle(rwevent);
9631                 }
9632                 thrd_SetEvent(SessionEvents[idx_session]);
9633                 if (rwc.code == 0)
9634                     smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9635             }
9636             else if (smbp->com == 0xa0) {
9637                 /*
9638                  * Serialize the handling for NT Transact
9639                  * (defect 11626)
9640                  */
9641                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9642                 thrd_SetEvent(SessionEvents[idx_session]);
9643             } else {
9644                 thrd_SetEvent(SessionEvents[idx_session]);
9645                 /* TODO: what else needs to be serialized? */
9646                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9647             }
9648 #ifndef NOTRACE
9649         }
9650         __except( smb_ServerExceptionFilter() ) {
9651         }
9652 #endif
9653
9654         if (smb_monitorReqs) {
9655             smb_NotifyRequestEvent(GetCurrentThreadId(), FALSE);
9656         }
9657         smb_concurrentCalls--;
9658
9659       doneWithNCB:
9660         thrd_SetEvent(NCBavails[idx_NCB]);
9661     }
9662     if (vcp)
9663         smb_ReleaseVC(vcp);
9664     if (outbufp)
9665         smb_FreePacket(outbufp);
9666     if (outncbp)
9667         smb_FreeNCB(outncbp);
9668 }
9669
9670 /*
9671  * Exception filter for the server threads.  If an exception occurs in the
9672  * dispatch routines, which is where exceptions are most common, then do a
9673  * force trace and give control to upstream exception handlers. Useful for
9674  * debugging.
9675  */
9676 DWORD smb_ServerExceptionFilter(void) {
9677     /* While this is not the best time to do a trace, if it succeeds, then
9678      * we have a trace (assuming tracing was enabled). Otherwise, this should
9679      * throw a second exception.
9680      */
9681     LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9682     afsd_ForceTrace(TRUE);
9683     buf_ForceTrace(TRUE);
9684     return EXCEPTION_CONTINUE_SEARCH;
9685 }
9686
9687 /*
9688  * Create a new NCB and associated events, packet buffer, and "space" buffer.
9689  * If the number of server threads is M, and the number of live sessions is
9690  * N, then the number of NCB's in use at any time either waiting for, or
9691  * holding, received messages is M + N, so that is how many NCB's get created.
9692  */
9693 void InitNCBslot(int idx)
9694 {
9695     struct smb_packet *bufp;
9696     EVENT_HANDLE retHandle;
9697     afs_uint32 i;
9698     char eventName[MAX_PATH];
9699
9700     osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9701
9702     NCBs[idx] = smb_GetNCB();
9703     sprintf(eventName,"NCBavails[%d]", idx);
9704     NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9705     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9706         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9707     sprintf(eventName,"NCBevents[%d]", idx);
9708     NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9709     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9710         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9711     sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9712     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9713     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9714         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9715     for (i=0; i<smb_NumServerThreads; i++)
9716         NCBreturns[i][idx] = retHandle;
9717     bufp = smb_GetPacket();
9718     bufp->spacep = cm_GetSpace();
9719     bufs[idx] = bufp;
9720 }
9721
9722 /* listen for new connections */
9723 void smb_Listener(void *parmp)
9724 {
9725     NCB *ncbp;
9726     long code = 0;
9727     long len;
9728     long i;
9729     afs_uint32  session, thread;
9730     smb_vc_t *vcp = NULL;
9731     int flags = 0;
9732     char rname[NCBNAMSZ+1];
9733     char cname[MAX_COMPUTERNAME_LENGTH+1];
9734     int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9735     INT_PTR lana = (INT_PTR) parmp;
9736     char eventName[MAX_PATH];
9737     int bridgeCount = 0;
9738     int nowildCount = 0;
9739
9740     sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9741     ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9742     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9743         thrd_ResetEvent(ListenerShutdown[lana]);
9744
9745     ncbp = smb_GetNCB();
9746
9747     /* retrieve computer name */
9748     GetComputerName(cname, &cnamelen);
9749     _strupr(cname);
9750
9751     while (smb_ListenerState == SMB_LISTENER_STARTED) {
9752         memset(ncbp, 0, sizeof(NCB));
9753         flags = 0;
9754
9755         ncbp->ncb_command = NCBLISTEN;
9756         ncbp->ncb_rto = 0;      /* No receive timeout */
9757         ncbp->ncb_sto = 0;      /* No send timeout */
9758
9759         /* pad out with spaces instead of null termination */
9760         len = (long)strlen(smb_localNamep);
9761         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9762         for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9763
9764         strcpy(ncbp->ncb_callname, "*");
9765         for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9766
9767         ncbp->ncb_lana_num = (UCHAR)lana;
9768
9769         code = Netbios(ncbp);
9770
9771         if (code == NRC_NAMERR) {
9772           /* An smb shutdown or Vista resume must have taken place */
9773           osi_Log1(smb_logp,
9774                    "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9775                    ncbp->ncb_lana_num);
9776           afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9777
9778             if (lock_TryMutex(&smb_StartedLock)) {
9779                 lana_list.lana[i] = LANA_INVALID;
9780                 lock_ReleaseMutex(&smb_StartedLock);
9781             }
9782             break;
9783         } else if (code ==  NRC_BRIDGE || code != 0) {
9784             int lanaRemaining = 0;
9785
9786             if (code == NRC_BRIDGE) {
9787                 if (++bridgeCount <= 5) {
9788                     afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9789                     continue;
9790                 }
9791             } else if (code == NRC_NOWILD) {
9792                 if (++nowildCount <= 5) {
9793                     afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9794
9795                     if (bridgeCount > 0) {
9796                         memset(ncbp, 0, sizeof(*ncbp));
9797                         ncbp->ncb_command = NCBADDNAME;
9798                         ncbp->ncb_lana_num = (UCHAR)lana;
9799                         /* pad out with spaces instead of null termination */
9800                         len = (long)strlen(smb_localNamep);
9801                         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9802                         for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9803                         code = Netbios(ncbp);
9804                     }
9805                     continue;
9806                 }
9807             }
9808
9809             while (!lock_TryMutex(&smb_StartedLock)) {
9810                 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9811                     goto exit_thread;
9812                 Sleep(50);
9813             }
9814
9815             osi_Log2(smb_logp,
9816                       "NCBLISTEN lana=%d failed with %s.  Listener thread exiting.",
9817                       ncbp->ncb_lana_num, ncb_error_string(code));
9818             afsi_log("NCBLISTEN lana=%d failed with %s.  Listener thread exiting.",
9819                      ncbp->ncb_lana_num, ncb_error_string(code));
9820
9821             for (i = 0; i < lana_list.length; i++) {
9822                 if (lana_list.lana[i] == lana) {
9823                     smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9824                     lana_list.lana[i] = LANA_INVALID;
9825                 }
9826                 if (lana_list.lana[i] != LANA_INVALID)
9827                     lanaRemaining++;
9828             }
9829
9830             if (lanaRemaining == 0) {
9831                 cm_VolStatus_Network_Stopped(cm_NetbiosName
9832 #ifdef _WIN64
9833                                              ,cm_NetbiosName
9834 #endif
9835                                               );
9836                 smb_ListenerState = SMB_LISTENER_STOPPED;
9837                 smb_LANadapter = LANA_INVALID;
9838                 lana_list.length = 0;
9839             }
9840             lock_ReleaseMutex(&smb_StartedLock);
9841             break;
9842         }
9843
9844         /* a successful packet received.  clear bridge error count */
9845         bridgeCount = 0;
9846         nowildCount = 0;
9847
9848         /* check for remote conns */
9849         /* first get remote name and insert null terminator */
9850         memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9851         for (i=NCBNAMSZ; i>0; i--) {
9852             if (rname[i-1] != ' ' && rname[i-1] != 0) {
9853                 rname[i] = 0;
9854                 break;
9855             }
9856         }
9857
9858         /* compare with local name */
9859         if (!isGateway)
9860             if (strncmp(rname, cname, NCBNAMSZ) != 0)
9861                 flags |= SMB_VCFLAG_REMOTECONN;
9862
9863         /* lock */
9864         lock_ObtainMutex(&smb_ListenerLock);
9865
9866         osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9867         osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9868
9869         /* now ncbp->ncb_lsn is the connection ID */
9870         vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9871         if (vcp->session == 0) {
9872             /* New generation */
9873             osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9874             sessionGen++;
9875
9876             /* Log session startup */
9877 #ifdef NOTSERVICE
9878             fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9879                     ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9880 #endif /* NOTSERVICE */
9881             osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9882                      ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9883
9884             if (reportSessionStartups) {
9885                 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9886             }
9887
9888             lock_ObtainMutex(&vcp->mx);
9889             cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9890             vcp->flags |= flags;
9891             lock_ReleaseMutex(&vcp->mx);
9892
9893             /* Allocate slot in session arrays */
9894             /* Re-use dead session if possible, otherwise add one more */
9895             /* But don't look at session[0], it is reserved */
9896             lock_ObtainWrite(&smb_globalLock);
9897             for (session = 1; session < numSessions; session++) {
9898                 if (dead_sessions[session]) {
9899                     osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9900                     dead_sessions[session] = FALSE;
9901                     break;
9902                 }
9903             }
9904             lock_ReleaseWrite(&smb_globalLock);
9905         } else {
9906             /* We are re-using an existing VC because the lsn and lana
9907              * were re-used */
9908             session = vcp->session;
9909
9910             osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9911
9912             /* Log session startup */
9913 #ifdef NOTSERVICE
9914             fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9915                     ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9916 #endif /* NOTSERVICE */
9917             osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9918                      ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9919
9920             if (reportSessionStartups) {
9921                 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9922             }
9923         }
9924
9925         if (session >= SESSION_MAX - 1  || numNCBs >= NCB_MAX - 1) {
9926             unsigned long code = CM_ERROR_ALLBUSY;
9927             smb_packet_t * outp = smb_GetPacket();
9928             unsigned char *outWctp;
9929             smb_t *smbp;
9930
9931             smb_FormatResponsePacket(vcp, NULL, outp);
9932             outp->ncbp = ncbp;
9933
9934             if (vcp->flags & SMB_VCFLAG_STATUS32) {
9935                 unsigned long NTStatus;
9936                 smb_MapNTError(code, &NTStatus, FALSE);
9937                 outWctp = outp->wctp;
9938                 smbp = (smb_t *) &outp->data;
9939                 *outWctp++ = 0;
9940                 *outWctp++ = 0;
9941                 *outWctp++ = 0;
9942                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9943                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9944                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9945                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9946                 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9947             } else {
9948                 unsigned short errCode;
9949                 unsigned char errClass;
9950                 smb_MapCoreError(code, vcp, &errCode, &errClass);
9951                 outWctp = outp->wctp;
9952                 smbp = (smb_t *) &outp->data;
9953                 *outWctp++ = 0;
9954                 *outWctp++ = 0;
9955                 *outWctp++ = 0;
9956                 smbp->errLow = (unsigned char) (errCode & 0xff);
9957                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9958                 smbp->rcls = errClass;
9959             }
9960
9961             smb_SendPacket(vcp, outp);
9962             smb_FreePacket(outp);
9963
9964             lock_ObtainMutex(&vcp->mx);
9965             if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9966                 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9967                           vcp, vcp->usersp);
9968                 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9969                 lock_ReleaseMutex(&vcp->mx);
9970                 lock_ObtainWrite(&smb_globalLock);
9971                 dead_sessions[vcp->session] = TRUE;
9972                 lock_ReleaseWrite(&smb_globalLock);
9973                 smb_CleanupDeadVC(vcp);
9974             } else {
9975                 lock_ReleaseMutex(&vcp->mx);
9976             }
9977         } else {
9978             /* assert that we do not exceed the maximum number of sessions or NCBs.
9979              * we should probably want to wait for a session to be freed in case
9980              * we run out.
9981              */
9982             osi_assertx(session < SESSION_MAX - 1, "invalid session");
9983             osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs");   /* if we pass this test we can allocate one more */
9984
9985             lock_ObtainMutex(&vcp->mx);
9986             vcp->session   = session;
9987             lock_ReleaseMutex(&vcp->mx);
9988             lock_ObtainWrite(&smb_globalLock);
9989             LSNs[session]  = ncbp->ncb_lsn;
9990             lanas[session] = ncbp->ncb_lana_num;
9991             lock_ReleaseWrite(&smb_globalLock);
9992
9993             if (session == numSessions) {
9994                 /* Add new NCB for new session */
9995                 char eventName[MAX_PATH];
9996
9997                 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9998
9999                 InitNCBslot(numNCBs);
10000                 lock_ObtainWrite(&smb_globalLock);
10001                 numNCBs++;
10002                 lock_ReleaseWrite(&smb_globalLock);
10003                 thrd_SetEvent(NCBavails[0]);
10004                 thrd_SetEvent(NCBevents[0]);
10005                 for (thread = 0; thread < smb_NumServerThreads; thread++)
10006                     thrd_SetEvent(NCBreturns[thread][0]);
10007                 /* Also add new session event */
10008                 sprintf(eventName, "SessionEvents[%d]", session);
10009                 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
10010                 if ( GetLastError() == ERROR_ALREADY_EXISTS )
10011                     osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
10012                 lock_ObtainWrite(&smb_globalLock);
10013                 numSessions++;
10014                 lock_ReleaseWrite(&smb_globalLock);
10015                 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
10016                 thrd_SetEvent(SessionEvents[0]);
10017             } else {
10018                 thrd_SetEvent(SessionEvents[session]);
10019             }
10020         }
10021         smb_ReleaseVC(vcp);
10022
10023         /* unlock */
10024         lock_ReleaseMutex(&smb_ListenerLock);
10025     }   /* dispatch while loop */
10026
10027 exit_thread:
10028     smb_FreeNCB(ncbp);
10029     thrd_SetEvent(ListenerShutdown[lana]);
10030     return;
10031 }
10032
10033 void
10034 smb_configureBackConnectionHostNames(int bEnable)
10035 {
10036     /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
10037      * there is a restriction on the use of SMB authentication on loopback connections.
10038      * There are two work arounds available:
10039      *
10040      *   (1) We can disable the check for matching host names.  This does not
10041      *   require a reboot:
10042      *   [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
10043      *     "DisableLoopbackCheck"=dword:00000001
10044      *
10045      *   (2) We can add the AFS SMB/CIFS service name to an approved list.  This
10046      *   does require a reboot:
10047      *   [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
10048      *     "BackConnectionHostNames"=multi-sz
10049      *
10050      * The algorithm will be:
10051      *   (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
10052      *   (2a) If not, add it to the list.  (This will not take effect until the next reboot.)
10053      *   (2b1)    and check to see if DisableLoopbackCheck is set.
10054      *   (2b2)    If not set, set the DisableLoopbackCheck value to 0x1
10055      *   (2b3)                and create HKLM\SOFTWARE\OpenAFS\Client  UnsetDisableLoopbackCheck
10056      *   (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
10057      *             check for the UnsetDisableLoopbackCheck value.
10058      *             If set, set the DisableLoopbackCheck flag to 0x0
10059      *             and delete the UnsetDisableLoopbackCheck value
10060      *
10061      * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
10062      * force Windows to use the loopback authentication mechanism for the specified
10063      * services.
10064      *
10065      * Do not permit the "DisableLoopbackCheck" value to be removed within the same
10066      * service session that set it.
10067      */
10068     HKEY hkLsa;
10069     HKEY hkMSV10;
10070     HKEY hkClient;
10071     DWORD dwType;
10072     DWORD dwSize, dwAllocSize;
10073     DWORD dwValue;
10074     PBYTE pHostNames = NULL, pName = NULL;
10075     PBYTE pOrigNames = NULL, pOrig = NULL;
10076     BOOL  bNameFound = FALSE;
10077     DWORD dwLoopbackCheckDisabled;
10078     DWORD dwszBackConnectionHostNames;
10079     size_t nbsize = strlen(cm_NetbiosName) + 2;
10080     size_t len;
10081     static BOOL bLoopbackCheckDisabled = FALSE;
10082
10083     /* DisableLoopbackCheck */
10084     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10085                        "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10086                        0,
10087                        KEY_READ|KEY_WRITE,
10088                        &hkLsa) == ERROR_SUCCESS )
10089     {
10090         dwSize = sizeof(DWORD);
10091         if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwLoopbackCheckDisabled, &dwSize) != ERROR_SUCCESS)
10092         {
10093             dwLoopbackCheckDisabled = 0;
10094         }
10095     } else {
10096         hkLsa = INVALID_HANDLE_VALUE;
10097     }
10098
10099     /* BackConnectionHostNames */
10100     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10101                        "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
10102                        0,
10103                        KEY_READ|KEY_WRITE,
10104                        &hkMSV10) == ERROR_SUCCESS )
10105     {
10106         if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
10107                              &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10108             (dwType == REG_MULTI_SZ))
10109         {
10110             dwAllocSize += 1 /* in case the source string is not nul terminated */
10111                 + (DWORD)strlen(cm_NetbiosName) + 2;
10112             pHostNames = malloc(dwAllocSize);
10113             dwszBackConnectionHostNames = dwAllocSize;
10114             if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
10115                                  pHostNames, &dwszBackConnectionHostNames) == ERROR_SUCCESS)
10116             {
10117                 for (pName = pHostNames;
10118                      (pName - pHostNames < (int) dwszBackConnectionHostNames) && *pName ;
10119                      pName += strlen(pName) + 1)
10120                 {
10121                     if ( !stricmp(pName, cm_NetbiosName) ) {
10122                         bNameFound = TRUE;
10123                         break;
10124                     }
10125                 }
10126             }
10127         }
10128
10129         if ( bEnable ) {
10130             if ( !bNameFound ) {
10131                 size_t size = strlen(cm_NetbiosName) + 2;
10132                 if ( !pHostNames ) {
10133                     pHostNames = malloc(size);
10134                     pName = pHostNames;
10135                 }
10136                 StringCbCopyA(pName, size, cm_NetbiosName);
10137                 pName += size - 1;
10138                 *pName = '\0';  /* add a second nul terminator */
10139
10140                 dwType = REG_MULTI_SZ;
10141                 dwSize = (DWORD)(pName - pHostNames + 1);
10142                 RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10143
10144                 if ( hkLsa != INVALID_HANDLE_VALUE && !dwLoopbackCheckDisabled)
10145                 {
10146                     dwType = REG_DWORD;
10147                     dwSize = sizeof(DWORD);
10148                     dwLoopbackCheckDisabled = 1;
10149                     RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwLoopbackCheckDisabled, dwSize);
10150
10151                     if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10152                                         AFSREG_CLT_OPENAFS_SUBKEY,
10153                                         0,
10154                                         NULL,
10155                                         REG_OPTION_NON_VOLATILE,
10156                                         KEY_READ|KEY_WRITE,
10157                                         NULL,
10158                                         &hkClient,
10159                                         NULL) == ERROR_SUCCESS) {
10160
10161                         dwType = REG_DWORD;
10162                         dwSize = sizeof(DWORD);
10163                         dwValue = 1;
10164                         RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10165                         bLoopbackCheckDisabled = TRUE;
10166                         RegCloseKey(hkClient);
10167                     }
10168                 }
10169             } else if (!bLoopbackCheckDisabled && hkLsa != INVALID_HANDLE_VALUE) {
10170                 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10171                                     AFSREG_CLT_OPENAFS_SUBKEY,
10172                                     0,
10173                                     NULL,
10174                                     REG_OPTION_NON_VOLATILE,
10175                                     KEY_READ|KEY_WRITE,
10176                                     NULL,
10177                                     &hkClient,
10178                                     NULL) == ERROR_SUCCESS) {
10179
10180                     dwSize = sizeof(DWORD);
10181                     if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10182                          dwValue == 1 ) {
10183                         RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10184                     }
10185                 }
10186                 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10187                 RegCloseKey(hkClient);
10188             }
10189         } else {
10190             /*
10191              * Disable SMB.  Start by removing the DisableLoopbackCheck value if present.
10192              */
10193             if (hkLsa != INVALID_HANDLE_VALUE) {
10194                 if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10195                                     AFSREG_CLT_OPENAFS_SUBKEY,
10196                                     0,
10197                                     NULL,
10198                                     REG_OPTION_NON_VOLATILE,
10199                                     KEY_READ|KEY_WRITE,
10200                                     NULL,
10201                                     &hkClient,
10202                                     NULL) == ERROR_SUCCESS) {
10203
10204                     dwSize = sizeof(DWORD);
10205                     if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10206                          dwValue == 1 ) {
10207                         RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10208                     }
10209                 }
10210                 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10211                 RegCloseKey(hkClient);
10212             }
10213
10214             /* Then remove our NetbiosName from the BackConnectionHostNames list */
10215             if ( bNameFound ) {
10216                 /*
10217                 * we found our name so if the size of the value is smaller
10218                 * or equal to the length of our name alone, we are done.
10219                 */
10220                 if ( dwszBackConnectionHostNames <= nbsize ) {
10221                     RegDeleteValue( hkMSV10, "BackConnectionHostNames");
10222                 } else {
10223                     pOrigNames = pHostNames;
10224                     pHostNames = malloc(dwAllocSize);
10225
10226                     pOrig = pOrigNames;
10227                     pName = pHostNames;
10228                     while (pOrig - pOrigNames < dwszBackConnectionHostNames) {
10229                         len = strlen(pOrig);
10230                         if ( stricmp(pOrig, cm_NetbiosName)) {
10231                             /* not our name */
10232                             StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10233                             pName += len + 1;
10234                         }
10235                         pOrig += len + 1;
10236                     }
10237                     *pName = '\0';  /* add a second nul terminator */
10238                     pName++;
10239
10240                     dwType = REG_MULTI_SZ;
10241                     dwSize = (DWORD)(pName - pHostNames + 1);
10242                     RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10243                 }
10244             }
10245         }
10246
10247         if (pHostNames) {
10248             free(pHostNames);
10249             pHostNames = NULL;
10250         }
10251
10252         if (pOrigNames) {
10253             free(pOrigNames);
10254             pOrigNames = NULL;
10255         }
10256
10257         RegCloseKey(hkMSV10);
10258     }
10259
10260     if ( hkLsa != INVALID_HANDLE_VALUE ) {
10261         RegCloseKey(hkLsa);
10262     }
10263 }
10264
10265
10266 void
10267 smb_configureExtendedSMBSessionTimeouts(int bEnable)
10268 {
10269     /*
10270      * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
10271      * new functionality:
10272      *
10273      *  [HKLM\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters]
10274      *   "ReconnectableServers"            REG_MULTI_SZ
10275      *   "ExtendedSessTimeout"             REG_DWORD  (seconds)
10276      *   "ServersWithExtendedSessTimeout"  REG_MULTI_SZ
10277      *
10278      * These values can be used to prevent the smb redirector from timing out
10279      * smb connection to the afs smb server prematurely.
10280      */
10281     HKEY hkLanman;
10282     DWORD dwType;
10283     DWORD dwSize, dwAllocSize;
10284     DWORD dwValue;
10285     PBYTE pHostNames = NULL, pOrigNames = NULL, pName = NULL, pOrig = NULL;
10286     BOOL  bNameFound = FALSE;
10287     DWORD dwszReconnectableServers;
10288     DWORD dwszServersWithExtendedSessTimeout;
10289     size_t nbsize = strlen(cm_NetbiosName) + 2;
10290     size_t len;
10291
10292     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10293                        "SYSTEM\\CurrentControlSet\\Services\\LanmanWorkstation\\Parameters",
10294                        0,
10295                        KEY_READ|KEY_WRITE,
10296                        &hkLanman) == ERROR_SUCCESS )
10297     {
10298         if ((RegQueryValueEx( hkLanman, "ReconnectableServers", 0,
10299                              &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10300             (dwType == REG_MULTI_SZ))
10301         {
10302             dwAllocSize += 1 /* in case the source string is not nul terminated */
10303                 + (DWORD)strlen(cm_NetbiosName) + 2;
10304             pHostNames = malloc(dwAllocSize);
10305             dwszReconnectableServers = dwAllocSize;
10306             if (RegQueryValueEx( hkLanman, "ReconnectableServers", 0, &dwType,
10307                                  pHostNames, &dwszReconnectableServers) == ERROR_SUCCESS)
10308             {
10309                 for (pName = pHostNames;
10310                      (pName - pHostNames < (int) dwszReconnectableServers) && *pName ;
10311                      pName += strlen(pName) + 1)
10312                 {
10313                     if ( !stricmp(pName, cm_NetbiosName) ) {
10314                         bNameFound = TRUE;
10315                         break;
10316                     }
10317                 }
10318             }
10319         }
10320
10321         /*
10322          * If our name was not found and we are enabling SMB,
10323          * add our name to the current value.
10324          */
10325         if ( bEnable && !bNameFound ) {
10326             if ( !pHostNames ) {
10327                 pHostNames = malloc(nbsize);
10328                 pName = pHostNames;
10329             }
10330             StringCbCopyA(pName, nbsize, cm_NetbiosName);
10331             pName += nbsize - 1;
10332             *pName = '\0';  /* add a second nul terminator */
10333
10334             dwType = REG_MULTI_SZ;
10335             dwSize = (DWORD)(pName - pHostNames + 1);
10336             RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10337         }
10338
10339         /*
10340          * If our name was found and we are disabling SMB,
10341          * remove our name from the list and update the value.
10342          * If our name is the only entry, remove the value.
10343          */
10344         if ( !bEnable && bNameFound ) {
10345             /*
10346              * we found our name so if the size of the value is smaller
10347              * or equal to the length of our name alone, we are done.
10348              */
10349             if ( dwszReconnectableServers <= nbsize ) {
10350                 RegDeleteValue( hkLanman, "ReconnectableServers");
10351             } else {
10352                 pOrigNames = pHostNames;
10353                 pHostNames = malloc(dwAllocSize);
10354
10355                 pOrig = pOrigNames;
10356                 pName = pHostNames;
10357                 while (pOrig - pOrigNames <dwszReconnectableServers ) {
10358                     len = strlen(pOrig);
10359                     if ( stricmp(pOrig, cm_NetbiosName)) {
10360                         /* not our name */
10361                         StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10362                         pName += len + 1;
10363                     }
10364                     pOrig += len + 1;
10365                 }
10366                 *pName = '\0';  /* add a second nul terminator */
10367                 pName++;
10368
10369                 dwType = REG_MULTI_SZ;
10370                 dwSize = (DWORD)(pName - pHostNames + 1);
10371                 RegSetValueEx( hkLanman, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10372             }
10373         }
10374
10375         if (pHostNames) {
10376             free(pHostNames);
10377             pHostNames = NULL;
10378         }
10379
10380         if (pOrigNames) {
10381             free(pOrigNames);
10382             pOrigNames = NULL;
10383         }
10384
10385         if ((RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0,
10386                              &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10387             (dwType == REG_MULTI_SZ))
10388         {
10389             dwAllocSize += 1 /* in case the source string is not nul terminated */
10390                 + (DWORD)strlen(cm_NetbiosName) + 2;
10391             pHostNames = malloc(dwAllocSize);
10392             dwszServersWithExtendedSessTimeout = dwAllocSize;
10393             if (RegQueryValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, &dwType,
10394                                  pHostNames, &dwszServersWithExtendedSessTimeout) == ERROR_SUCCESS)
10395             {
10396                 for (pName = pHostNames;
10397                      (pName - pHostNames < (int) dwszServersWithExtendedSessTimeout) && *pName ;
10398                      pName += strlen(pName) + 1)
10399                 {
10400                     if ( !stricmp(pName, cm_NetbiosName) ) {
10401                         bNameFound = TRUE;
10402                         break;
10403                     }
10404                 }
10405             }
10406         }
10407
10408         /*
10409          * If our name was not found and we are enabling SMB,
10410          * add our name to the current value.
10411          */
10412         if ( bEnable && !bNameFound ) {
10413             size_t size = strlen(cm_NetbiosName) + 2;
10414             if ( !pHostNames ) {
10415                 pHostNames = malloc(size);
10416                 pName = pHostNames;
10417             }
10418             StringCbCopyA(pName, size, cm_NetbiosName);
10419             pName += size - 1;
10420             *pName = '\0';  /* add a second nul terminator */
10421
10422             dwType = REG_MULTI_SZ;
10423             dwSize = (DWORD)(pName - pHostNames + 1);
10424             RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10425         }
10426
10427         /*
10428          * If our name was found and we are disabling SMB,
10429          * remove our name from the list and update the value.
10430          * If our name is the only entry, remove the value.
10431          */
10432         if ( !bEnable && bNameFound ) {
10433             /*
10434              * we found our name so if the size of the value is smaller
10435              * or equal to the length of our name alone, we are done.
10436              */
10437             if ( dwszServersWithExtendedSessTimeout <= nbsize ) {
10438                 RegDeleteValue( hkLanman, "ServersWithExtendedSessTimeout");
10439             } else {
10440                 pOrigNames = pHostNames;
10441                 pHostNames = malloc(dwAllocSize);
10442
10443                 pOrig = pOrigNames;
10444                 pName = pHostNames;
10445                 while (pOrig - pOrigNames < dwszServersWithExtendedSessTimeout) {
10446                     len = strlen(pOrig);
10447                     if ( stricmp(pOrig, cm_NetbiosName)) {
10448                         /* not our name */
10449                         StringCbCopyA(pName, dwAllocSize - (pName - pHostNames), pOrig);
10450                         pName += len + 1;
10451                     }
10452                     pOrig += len + 1;
10453                 }
10454                 *pName = '\0';  /* add a second nul terminator */
10455                 pName++;
10456
10457                 dwType = REG_MULTI_SZ;
10458                 dwSize = (DWORD)(pName - pHostNames + 1);
10459                 RegSetValueEx( hkLanman, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10460             }
10461         }
10462
10463         if (pHostNames) {
10464             free(pHostNames);
10465             pHostNames = NULL;
10466         }
10467
10468         if (pOrigNames) {
10469             free(pOrigNames);
10470             pOrigNames = NULL;
10471         }
10472
10473         if ( bEnable ) {
10474             if ((RegQueryValueEx( hkLanman, "ExtendedSessTimeout", 0,
10475                                   &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
10476                  (dwType != REG_DWORD))
10477             {
10478                 dwType = REG_DWORD;
10479                 dwSize = sizeof(dwValue);
10480                 dwValue = 300;      /* 5 minutes */
10481                 RegSetValueEx( hkLanman, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
10482             }
10483         }
10484         RegCloseKey(hkLanman);
10485     }
10486 }
10487
10488 static void
10489 smb_LanAdapterChangeThread(void *param)
10490 {
10491     /*
10492      * Give the IPAddrDaemon thread a chance
10493      * to block before we trigger.
10494      */
10495     Sleep(30000);
10496     smb_LanAdapterChange(0);
10497 }
10498
10499 void smb_SetLanAdapterChangeDetected(void)
10500 {
10501     int lpid;
10502     thread_t phandle;
10503
10504     lock_ObtainMutex(&smb_StartedLock);
10505
10506     if (!powerStateSuspended) {
10507         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
10508                               NULL, 0, &lpid, "smb_LanAdapterChange");
10509         if (phandle == NULL) {
10510             DWORD gle;
10511             char msg[128];
10512
10513             gle = GetLastError();
10514             StringCchPrintf( msg, sizeof(msg)/sizeof(msg[0]),
10515                              "smb_LanAdapterChangeThread thread creation failure - gle 0x%x",
10516                              gle);
10517             osi_assertx(TRUE, msg);
10518         }
10519         thrd_CloseHandle(phandle);
10520     }
10521
10522     smb_LanAdapterChangeDetected = 1;
10523     lock_ReleaseMutex(&smb_StartedLock);
10524 }
10525
10526 void smb_LanAdapterChange(int locked) {
10527     lana_number_t lanaNum;
10528     BOOL          bGateway;
10529     char          NetbiosName[MAX_NB_NAME_LENGTH] = "";
10530     int           change = 0;
10531     LANA_ENUM     temp_list;
10532     long          code;
10533     int           i;
10534
10535
10536     afsi_log("smb_LanAdapterChange");
10537
10538     if (!locked)
10539         lock_ObtainMutex(&smb_StartedLock);
10540
10541     smb_LanAdapterChangeDetected = 0;
10542
10543     if (!powerStateSuspended &&
10544         SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
10545                                           LANA_NETBIOS_NAME_FULL | LANA_NETBIOS_NO_RESET)) &&
10546         lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
10547         if ( isGateway != bGateway ) {
10548             afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
10549                       smb_LANadapter, lanaNum, isGateway, bGateway);
10550             change = 1;
10551         } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
10552             afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
10553                       smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
10554             change = 1;
10555         } else {
10556             NCB *ncbp = smb_GetNCB();
10557             ncbp->ncb_command = NCBENUM;
10558             ncbp->ncb_buffer = (PUCHAR)&temp_list;
10559             ncbp->ncb_length = sizeof(temp_list);
10560             code = Netbios(ncbp);
10561             if (code == 0) {
10562                 if (temp_list.length != lana_list.length) {
10563                     afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
10564                               smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
10565                     change = 1;
10566                 } else {
10567                     for (i=0; i<lana_list.length; i++) {
10568                         if ( temp_list.lana[i] != lana_list.lana[i] ) {
10569                             afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
10570                                       smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
10571                             change = 1;
10572                             break;
10573                         }
10574                     }
10575                 }
10576             }
10577             smb_FreeNCB(ncbp);
10578         }
10579     }
10580
10581     if (change) {
10582         smb_StopListeners(1);
10583         smb_RestartListeners(1);
10584     }
10585     if (!locked)
10586         lock_ReleaseMutex(&smb_StartedLock);
10587 }
10588
10589 /* initialize Netbios */
10590 int smb_NetbiosInit(int locked)
10591 {
10592     NCB *ncbp;
10593     int i, lana, code, l;
10594     char s[100];
10595     int delname_tried=0;
10596     int len;
10597     int lana_found = 0;
10598     lana_number_t lanaNum;
10599
10600     if (!smb_Enabled)
10601         return 0;
10602
10603     if (!locked)
10604         lock_ObtainMutex(&smb_StartedLock);
10605
10606     if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
10607          smb_ListenerState != SMB_LISTENER_STOPPED) {
10608
10609         if (!locked)
10610             lock_ReleaseMutex(&smb_StartedLock);
10611         return 0;
10612     }
10613     /* setup the NCB system */
10614     ncbp = smb_GetNCB();
10615
10616     /*
10617      * Call lanahelper to get Netbios name, lan adapter number and gateway flag
10618      * This will reset all of the network adapter's netbios state.
10619      */
10620     if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
10621         smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
10622
10623         if (smb_LANadapter != LANA_INVALID)
10624             afsi_log("LAN adapter number %d", smb_LANadapter);
10625         else
10626             afsi_log("LAN adapter number not determined");
10627
10628         if (isGateway)
10629             afsi_log("Set for gateway service");
10630
10631         afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
10632     } else {
10633         /* something went horribly wrong.  We can't proceed without a netbios name */
10634         char buf[128];
10635         StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
10636         osi_panic(buf, __FILE__, __LINE__);
10637     }
10638
10639     /* remember the name */
10640     len = (int)strlen(cm_NetbiosName);
10641     if (smb_localNamep)
10642         free(smb_localNamep);
10643     smb_localNamep = malloc(len+1);
10644     strcpy(smb_localNamep, cm_NetbiosName);
10645     afsi_log("smb_localNamep is >%s<", smb_localNamep);
10646
10647     /* Also copy the value to the client character encoded string */
10648     cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10649
10650     if (smb_LANadapter == LANA_INVALID) {
10651         ncbp->ncb_command = NCBENUM;
10652         ncbp->ncb_buffer = (PUCHAR)&lana_list;
10653         ncbp->ncb_length = sizeof(lana_list);
10654         code = Netbios(ncbp);
10655         if (code != 0) {
10656             afsi_log("Netbios NCBENUM error code %d", code);
10657             osi_panic(s, __FILE__, __LINE__);
10658         }
10659     }
10660     else {
10661         lana_list.length = 1;
10662         lana_list.lana[0] = smb_LANadapter;
10663     }
10664
10665     for (i = 0; i < lana_list.length; i++) {
10666         /* reset the adaptor: in Win32, this is required for every process, and
10667          * acts as an init call, not as a real hardware reset.
10668          */
10669         ncbp->ncb_command = NCBRESET;
10670         ncbp->ncb_callname[0] = 100;
10671         ncbp->ncb_callname[2] = 100;
10672         ncbp->ncb_lana_num = lana_list.lana[i];
10673         code = Netbios(ncbp);
10674         if (code == 0)
10675             code = ncbp->ncb_retcode;
10676         if (code != 0) {
10677             afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10678             lana_list.lana[i] = LANA_INVALID;  /* invalid lana */
10679         } else {
10680             afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10681         }
10682     }
10683
10684     /* and declare our name so we can receive connections */
10685     memset(ncbp, 0, sizeof(*ncbp));
10686     len=lstrlen(smb_localNamep);
10687     memset(smb_sharename,' ',NCBNAMSZ);
10688     memcpy(smb_sharename,smb_localNamep,len);
10689     afsi_log("lana_list.length %d", lana_list.length);
10690
10691     /* Keep the name so we can unregister it later */
10692     for (l = 0; l < lana_list.length; l++) {
10693         lana = lana_list.lana[l];
10694
10695         ncbp->ncb_command = NCBADDNAME;
10696         ncbp->ncb_lana_num = lana;
10697         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10698         code = Netbios(ncbp);
10699
10700         afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10701                  lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10702         {
10703             char name[NCBNAMSZ+1];
10704             name[NCBNAMSZ]=0;
10705             memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10706             afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10707         }
10708
10709         if (code == 0)
10710             code = ncbp->ncb_retcode;
10711
10712         if (code == 0) {
10713             afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10714         }
10715         else {
10716             afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10717             if (code == NRC_BRIDGE) {    /* invalid LANA num */
10718                 lana_list.lana[l] = LANA_INVALID;
10719                 continue;
10720             }
10721             else if (code == NRC_DUPNAME) {
10722                 afsi_log("Name already exists; try to delete it");
10723                 memset(ncbp, 0, sizeof(*ncbp));
10724                 ncbp->ncb_command = NCBDELNAME;
10725                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10726                 ncbp->ncb_lana_num = lana;
10727                 code = Netbios(ncbp);
10728                 if (code == 0)
10729                     code = ncbp->ncb_retcode;
10730                 else {
10731                     afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10732                 }
10733                 if (code != 0 || delname_tried) {
10734                     lana_list.lana[l] = LANA_INVALID;
10735                 }
10736                 else if (code == 0) {
10737                     if (!delname_tried) {
10738                         lana--;
10739                         delname_tried = 1;
10740                         continue;
10741                     }
10742                 }
10743             }
10744             else {
10745                 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10746                 lana_list.lana[l] = LANA_INVALID;  /* invalid lana */
10747             }
10748         }
10749         if (code == 0) {
10750             smb_LANadapter = lana;
10751             lana_found = 1;   /* at least one worked */
10752         }
10753     }
10754
10755     osi_assertx(lana_list.length >= 0, "empty lana list");
10756     if (!lana_found) {
10757         afsi_log("No valid LANA numbers found!");
10758         lana_list.length = 0;
10759         smb_LANadapter = LANA_INVALID;
10760         smb_ListenerState = SMB_LISTENER_STOPPED;
10761         cm_VolStatus_Network_Stopped(cm_NetbiosName
10762 #ifdef _WIN64
10763                                       ,cm_NetbiosName
10764 #endif
10765                                       );
10766     }
10767
10768     /* we're done with the NCB now */
10769     smb_FreeNCB(ncbp);
10770
10771     afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10772     if (lana_list.length > 0)
10773         osi_assert(smb_LANadapter != LANA_INVALID);
10774
10775     if (!locked)
10776         lock_ReleaseMutex(&smb_StartedLock);
10777
10778     return (lana_list.length > 0 ? 1 : 0);
10779 }
10780
10781 void smb_StartListeners(int locked)
10782 {
10783     int i;
10784     int lpid;
10785     thread_t phandle;
10786
10787     if (!smb_Enabled)
10788         return;
10789
10790     if (!locked)
10791         lock_ObtainMutex(&smb_StartedLock);
10792
10793     if (smb_ListenerState == SMB_LISTENER_STARTED) {
10794         if (!locked)
10795             lock_ReleaseMutex(&smb_StartedLock);
10796         return;
10797     }
10798
10799     afsi_log("smb_StartListeners");
10800     /* Ensure the AFS Netbios Name is registered to allow loopback access */
10801     smb_configureBackConnectionHostNames(TRUE);
10802
10803     /* Configure Extended SMB Session Timeouts */
10804     if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10805         afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10806         smb_configureExtendedSMBSessionTimeouts(TRUE);
10807     }
10808
10809     smb_ListenerState = SMB_LISTENER_STARTED;
10810     cm_VolStatus_Network_Started(cm_NetbiosName
10811 #ifdef _WIN64
10812                                   , cm_NetbiosName
10813 #endif
10814                                   );
10815
10816     for (i = 0; i < lana_list.length; i++) {
10817         if (lana_list.lana[i] == LANA_INVALID)
10818             continue;
10819         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10820                                (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10821         osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10822         thrd_CloseHandle(phandle);
10823     }
10824     if (!locked)
10825         lock_ReleaseMutex(&smb_StartedLock);
10826 }
10827
10828 void smb_RestartListeners(int locked)
10829 {
10830     if (!smb_Enabled)
10831         return;
10832
10833     if (!locked)
10834         lock_ObtainMutex(&smb_StartedLock);
10835
10836     if (powerStateSuspended)
10837         afsi_log("smb_RestartListeners called while suspended");
10838
10839     if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10840         if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10841             if (smb_NetbiosInit(1))
10842                 smb_StartListeners(1);
10843         } else if (smb_LanAdapterChangeDetected) {
10844             smb_LanAdapterChange(1);
10845         }
10846     }
10847     if (!locked)
10848         lock_ReleaseMutex(&smb_StartedLock);
10849 }
10850
10851 void smb_StopListener(NCB *ncbp, int lana, int wait)
10852 {
10853     long code;
10854
10855     memset(ncbp, 0, sizeof(*ncbp));
10856     ncbp->ncb_command = NCBDELNAME;
10857     ncbp->ncb_lana_num = lana;
10858     memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10859     code = Netbios(ncbp);
10860
10861     afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10862               lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10863
10864     /* and then reset the LANA; this will cause the listener threads to exit */
10865     ncbp->ncb_command = NCBRESET;
10866     ncbp->ncb_callname[0] = 100;
10867     ncbp->ncb_callname[2] = 100;
10868     ncbp->ncb_lana_num = lana;
10869     code = Netbios(ncbp);
10870     if (code == 0)
10871         code = ncbp->ncb_retcode;
10872     if (code != 0) {
10873         afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10874     } else {
10875         afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10876     }
10877
10878     if (wait)
10879         thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10880 }
10881
10882 void smb_StopListeners(int locked)
10883 {
10884     NCB *ncbp;
10885     int lana, l;
10886
10887     if (!smb_Enabled)
10888         return;
10889
10890     if (!locked)
10891         lock_ObtainMutex(&smb_StartedLock);
10892
10893     if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10894         if (!locked)
10895             lock_ReleaseMutex(&smb_StartedLock);
10896         return;
10897     }
10898
10899     afsi_log("smb_StopListeners");
10900     smb_ListenerState = SMB_LISTENER_STOPPED;
10901     cm_VolStatus_Network_Stopped(cm_NetbiosName
10902 #ifdef _WIN64
10903                                   , cm_NetbiosName
10904 #endif
10905                                   );
10906
10907     ncbp = smb_GetNCB();
10908
10909     /* Unregister the SMB name */
10910     for (l = 0; l < lana_list.length; l++) {
10911         lana = lana_list.lana[l];
10912
10913         if (lana != LANA_INVALID) {
10914             smb_StopListener(ncbp, lana, TRUE);
10915
10916             /* mark the adapter invalid */
10917             lana_list.lana[l] = LANA_INVALID;  /* invalid lana */
10918         }
10919     }
10920
10921     /* force a re-evaluation of the network adapters */
10922     lana_list.length = 0;
10923     smb_LANadapter = LANA_INVALID;
10924     smb_FreeNCB(ncbp);
10925     if (!locked)
10926         lock_ReleaseMutex(&smb_StartedLock);
10927 }
10928
10929 void smb_Init(osi_log_t *logp, int useV3,
10930               int nThreads
10931               , void *aMBfunc
10932   )
10933
10934 {
10935     thread_t phandle;
10936     int lpid;
10937     UINT_PTR i;
10938     struct tm myTime;
10939     EVENT_HANDLE retHandle;
10940     char eventName[MAX_PATH];
10941     int startListeners = 0;
10942
10943     if (!smb_Enabled)
10944         return;
10945
10946     smb_MBfunc = aMBfunc;
10947
10948     smb_useV3 = useV3;
10949
10950     /* Initialize smb_localZero */
10951     myTime.tm_isdst = -1;               /* compute whether on DST or not */
10952     myTime.tm_year = 70;
10953     myTime.tm_mon = 0;
10954     myTime.tm_mday = 1;
10955     myTime.tm_hour = 0;
10956     myTime.tm_min = 0;
10957     myTime.tm_sec = 0;
10958     smb_localZero = mktime(&myTime);
10959
10960 #ifdef AFS_FREELANCE_CLIENT
10961     /* Make sure the root.afs volume has the correct time */
10962     cm_noteLocalMountPointChange(FALSE);
10963 #endif
10964
10965     /* initialize the remote debugging log */
10966     smb_logp = logp;
10967
10968     /* and the global lock */
10969     lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10970     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10971
10972     /* Raw I/O data structures */
10973     lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10974
10975     lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10976     lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10977
10978     /* 4 Raw I/O buffers */
10979     smb_RawBufs = calloc(65536,1);
10980     *((char **)smb_RawBufs) = NULL;
10981     for (i=0; i<3; i++) {
10982         char *rawBuf = calloc(65536,1);
10983         *((char **)rawBuf) = smb_RawBufs;
10984         smb_RawBufs = rawBuf;
10985     }
10986
10987     /* global free lists */
10988     smb_ncbFreeListp = NULL;
10989     smb_packetFreeListp = NULL;
10990
10991     lock_ObtainMutex(&smb_StartedLock);
10992     startListeners = smb_NetbiosInit(1);
10993
10994     /* Initialize listener and server structures */
10995     numVCs = 0;
10996     memset(dead_sessions, 0, sizeof(dead_sessions));
10997     sprintf(eventName, "SessionEvents[0]");
10998     SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10999     if ( GetLastError() == ERROR_ALREADY_EXISTS )
11000         afsi_log("Event Object Already Exists: %s", eventName);
11001     numSessions = 1;
11002     smb_NumServerThreads = nThreads;
11003     sprintf(eventName, "NCBavails[0]");
11004     NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11005     if ( GetLastError() == ERROR_ALREADY_EXISTS )
11006         afsi_log("Event Object Already Exists: %s", eventName);
11007     sprintf(eventName, "NCBevents[0]");
11008     NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11009     if ( GetLastError() == ERROR_ALREADY_EXISTS )
11010         afsi_log("Event Object Already Exists: %s", eventName);
11011     NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
11012     sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
11013     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11014     if ( GetLastError() == ERROR_ALREADY_EXISTS )
11015         afsi_log("Event Object Already Exists: %s", eventName);
11016     for (i = 0; i < smb_NumServerThreads; i++) {
11017         NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
11018         NCBreturns[i][0] = retHandle;
11019     }
11020
11021     smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
11022     for (i = 0; i < smb_NumServerThreads; i++) {
11023         sprintf(eventName, "smb_ServerShutdown[%d]", i);
11024         smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
11025         if ( GetLastError() == ERROR_ALREADY_EXISTS )
11026             afsi_log("Event Object Already Exists: %s", eventName);
11027         InitNCBslot((int)(i+1));
11028     }
11029     numNCBs = smb_NumServerThreads + 1;
11030
11031     /* Initialize dispatch table */
11032     memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
11033     /* Prepare the table for unknown operations */
11034     for(i=0; i<= SMB_NOPCODES; i++) {
11035         smb_dispatchTable[i].procp = smb_SendCoreBadOp;
11036     }
11037     /* Fill in the ones we do know */
11038     smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
11039     smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
11040     smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
11041     smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
11042     smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
11043     smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
11044     smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
11045     smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
11046     smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
11047     smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
11048     smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
11049     smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
11050     smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
11051     smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
11052     smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
11053     smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
11054     smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
11055     smb_dispatchTable[0x11].procp = smb_SendCoreBadOp;  /* process exit */
11056     smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
11057     smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
11058     /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
11059     smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11060     smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
11061     smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
11062     smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
11063     smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
11064     smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
11065     smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
11066     smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11067     smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
11068     smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11069     smb_dispatchTable[0x29].procp = smb_SendCoreBadOp;  /* copy file */
11070     smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
11071     /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
11072     smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11073     smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
11074     smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
11075     smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
11076     smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
11077     smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
11078     smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
11079     smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A;        /* both are same */
11080     smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11081     smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
11082     smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11083     smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
11084     smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
11085     smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
11086     smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
11087     smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
11088     smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
11089     smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
11090     smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
11091     smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
11092     smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
11093     smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
11094     smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
11095     smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
11096     smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
11097     smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
11098     smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
11099     smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
11100     smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
11101     smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
11102     smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
11103     smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
11104     smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
11105     smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;  /* Open Print File */
11106     smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;  /* Write Print File */
11107     smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;  /* Close Print File */
11108     smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;  /* Get Print Queue */
11109     smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp;  /* Read Bulk */
11110     smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp;  /* Write Bulk */
11111     smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp;  /* Write Bulk Data */
11112
11113     /* setup tran 2 dispatch table */
11114     smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
11115     smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir;        /* FindFirst */
11116     smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir;        /* FindNext */
11117     smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
11118     smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
11119     smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
11120     smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
11121     smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
11122     smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
11123     smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
11124     smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
11125     smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
11126     smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
11127     smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
11128     smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
11129     smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
11130     smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
11131     smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
11132
11133     /* setup the rap dispatch table */
11134     memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
11135     smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
11136     smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
11137     smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
11138     smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
11139
11140     smb3_Init();
11141
11142     /* if we are doing SMB authentication we have register outselves as a logon process */
11143     if (smb_authType != SMB_AUTH_NONE) {
11144         NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
11145         LSA_STRING afsProcessName;
11146         LSA_OPERATIONAL_MODE dummy; /*junk*/
11147
11148         afsProcessName.Buffer = "OpenAFSClientDaemon";
11149         afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
11150         afsProcessName.MaximumLength = afsProcessName.Length + 1;
11151
11152         nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
11153
11154         if (nts == STATUS_SUCCESS) {
11155             LSA_STRING packageName;
11156             /* we are registered. Find out the security package id */
11157             packageName.Buffer = MSV1_0_PACKAGE_NAME;
11158             packageName.Length = (USHORT)strlen(packageName.Buffer);
11159             packageName.MaximumLength = packageName.Length + 1;
11160             nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
11161             if (nts == STATUS_SUCCESS) {
11162                 /* BEGIN
11163                  * This code forces Windows to authenticate against the Logon Cache
11164                  * first instead of attempting to authenticate against the Domain
11165                  * Controller.  When the Windows logon cache is enabled this improves
11166                  * performance by removing the network access and works around a bug
11167                  * seen at sites which are using a MIT Kerberos principal to login
11168                  * to machines joined to a non-root domain in a multi-domain forest.
11169                  * MsV1_0SetProcessOption was added in Windows XP.
11170                  */
11171                 PVOID pResponse = NULL;
11172                 ULONG cbResponse = 0;
11173                 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
11174
11175                 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
11176                 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
11177                 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
11178                 OptionsRequest.DisableOptions = FALSE;
11179
11180                 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
11181                                                     smb_lsaSecPackage,
11182                                                     &OptionsRequest,
11183                                                     sizeof(OptionsRequest),
11184                                                     &pResponse,
11185                                                     &cbResponse,
11186                                                     &ntsEx
11187                                                     );
11188
11189                 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
11190                     osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
11191                              nts, ntsEx);
11192
11193                     afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
11194                 } else {
11195                     osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
11196                     afsi_log("MsV1_0SetProcessOption success");
11197                 }
11198                 /* END - code from Larry */
11199
11200                 smb_lsaLogonOrigin.Buffer = "OpenAFS";
11201                 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
11202                 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
11203             } else {
11204                 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
11205
11206                 /* something went wrong. We report the error and revert back to no authentication
11207                 because we can't perform any auth requests without a successful lsa handle
11208                 or sec package id. */
11209                 afsi_log("Reverting to NO SMB AUTH");
11210                 smb_authType = SMB_AUTH_NONE;
11211             }
11212         } else {
11213             afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
11214
11215             /* something went wrong. We report the error and revert back to no authentication
11216             because we can't perform any auth requests without a successful lsa handle
11217             or sec package id. */
11218             afsi_log("Reverting to NO SMB AUTH");
11219             smb_authType = SMB_AUTH_NONE;
11220         }
11221
11222 #ifdef COMMENT
11223         /* Don't fallback to SMB_AUTH_NTLM.  Apparently, allowing SPNEGO to be used each
11224          * time prevents the failure of authentication when logged into Windows with an
11225          * external Kerberos principal mapped to a local account.
11226          */
11227         else if ( smb_authType == SMB_AUTH_EXTENDED) {
11228             /* Test to see if there is anything to negotiate.  If SPNEGO is not going to be used
11229              * then the only option is NTLMSSP anyway; so just fallback.
11230              */
11231             void * secBlob;
11232             int secBlobLength;
11233
11234             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
11235             if (secBlobLength == 0) {
11236                 smb_authType = SMB_AUTH_NTLM;
11237                 afsi_log("Reverting to SMB AUTH NTLM");
11238             } else
11239                 free(secBlob);
11240         }
11241 #endif
11242     }
11243
11244     {
11245         DWORD bufsize;
11246         /* Now get ourselves a domain name. */
11247         /* For now we are using the local computer name as the domain name.
11248          * It is actually the domain for local logins, and we are acting as
11249          * a local SMB server.
11250          */
11251         bufsize = lengthof(smb_ServerDomainName) - 1;
11252         GetComputerNameW(smb_ServerDomainName, &bufsize);
11253         smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
11254         afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
11255     }
11256
11257     /* Start listeners, waiters, servers, and daemons */
11258     if (startListeners)
11259         smb_StartListeners(1);
11260
11261     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
11262                           NULL, 0, &lpid, "smb_ClientWaiter");
11263     osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
11264     thrd_CloseHandle(phandle);
11265
11266     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
11267                           NULL, 0, &lpid, "smb_ServerWaiter");
11268     osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
11269     thrd_CloseHandle(phandle);
11270
11271     for (i=0; i<smb_NumServerThreads; i++) {
11272         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
11273                               (void *) i, 0, &lpid, "smb_Server");
11274         osi_assertx(phandle != NULL, "smb_Server thread creation failure");
11275         thrd_CloseHandle(phandle);
11276     }
11277
11278     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
11279                           NULL, 0, &lpid, "smb_Daemon");
11280     osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
11281     thrd_CloseHandle(phandle);
11282
11283     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
11284                           NULL, 0, &lpid, "smb_WaitingLocksDaemon");
11285     osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
11286     thrd_CloseHandle(phandle);
11287
11288     if (smb_monitorReqs) {
11289         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerMonitor,
11290                               NULL, 0, &lpid, "smb_ServerMonitor");
11291         osi_assertx(phandle != NULL, "smb_ServerMonitor thread creation failure");
11292         thrd_CloseHandle(phandle);
11293     }
11294
11295     lock_ReleaseMutex(&smb_StartedLock);
11296     return;
11297 }
11298
11299 void smb_Shutdown(void)
11300 {
11301     NCB *ncbp;
11302     long code = 0;
11303     afs_uint32 i;
11304     smb_vc_t *vcp;
11305
11306     if (!smb_Enabled)
11307         return;
11308
11309     /*fprintf(stderr, "Entering smb_Shutdown\n");*/
11310
11311     /* setup the NCB system */
11312     ncbp = smb_GetNCB();
11313
11314     /* Block new sessions by setting shutdown flag */
11315     smbShutdownFlag = 1;
11316
11317     /* Hang up all sessions */
11318     memset(ncbp, 0, sizeof(NCB));
11319     for (i = 1; i < numSessions; i++)
11320     {
11321         if (dead_sessions[i])
11322             continue;
11323
11324         /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11325         ncbp->ncb_command = NCBHANGUP;
11326         ncbp->ncb_lana_num = lanas[i];  /*smb_LANadapter;*/
11327         ncbp->ncb_lsn = (UCHAR)LSNs[i];
11328         code = Netbios(ncbp);
11329         /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11330         if (code == 0) code = ncbp->ncb_retcode;
11331         if (code != 0) {
11332             osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
11333             fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
11334         }
11335     }
11336
11337     /* Trigger the shutdown of all SMB threads */
11338     for (i = 0; i < smb_NumServerThreads; i++)
11339         thrd_SetEvent(NCBreturns[i][0]);
11340
11341     thrd_SetEvent(NCBevents[0]);
11342     thrd_SetEvent(SessionEvents[0]);
11343     thrd_SetEvent(NCBavails[0]);
11344
11345     for (i = 0;i < smb_NumServerThreads; i++) {
11346         DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
11347         if (code == WAIT_OBJECT_0) {
11348             continue;
11349         } else {
11350             afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
11351             thrd_SetEvent(NCBreturns[i--][0]);
11352         }
11353     }
11354
11355     /* Delete Netbios name */
11356     memset(ncbp, 0, sizeof(NCB));
11357     for (i = 0; i < lana_list.length; i++) {
11358         if (lana_list.lana[i] == LANA_INVALID) continue;
11359         ncbp->ncb_command = NCBDELNAME;
11360         ncbp->ncb_lana_num = lana_list.lana[i];
11361         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
11362         code = Netbios(ncbp);
11363         if (code == 0)
11364             code = ncbp->ncb_retcode;
11365         if (code != 0) {
11366             fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
11367                      ncbp->ncb_lana_num, code);
11368         }
11369         fflush(stderr);
11370     }
11371
11372     /* Release the reference counts held by the VCs */
11373     lock_ObtainWrite(&smb_rctLock);
11374     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11375     {
11376         smb_fid_t *fidp;
11377         smb_tid_t *tidp;
11378
11379         if (vcp->magic != SMB_VC_MAGIC)
11380             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
11381                        __FILE__, __LINE__);
11382
11383         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11384         {
11385             if (fidp->scp != NULL) {
11386                 cm_scache_t * scp;
11387
11388                 lock_ReleaseWrite(&smb_rctLock);
11389                 lock_ObtainMutex(&fidp->mx);
11390                 if (fidp->scp != NULL) {
11391                     scp = fidp->scp;
11392                     fidp->scp = NULL;
11393                     lock_ObtainWrite(&scp->rw);
11394                     scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
11395                     lock_ReleaseWrite(&scp->rw);
11396                     osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
11397                     cm_ReleaseSCache(scp);
11398                 }
11399                 lock_ReleaseMutex(&fidp->mx);
11400                 lock_ObtainWrite(&smb_rctLock);
11401             }
11402         }
11403
11404         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11405             if (tidp->vcp)
11406                 smb_ReleaseVCNoLock(tidp->vcp);
11407             if (tidp->userp) {
11408                 cm_user_t *userp = tidp->userp;
11409                 tidp->userp = NULL;
11410                 cm_ReleaseUser(userp);
11411             }
11412         }
11413     }
11414     lock_ReleaseWrite(&smb_rctLock);
11415     smb_FreeNCB(ncbp);
11416
11417     if (smb_monitorReqs) {
11418         smb_ShutdownMonitor();
11419     }
11420 }
11421
11422 /* Get the UNC \\<servername>\<sharename> prefix. */
11423 char *smb_GetSharename()
11424 {
11425     char *name;
11426     size_t len;
11427
11428     /* Make sure we have been properly initialized. */
11429     if (smb_localNamep == NULL)
11430         return NULL;
11431
11432     /* Allocate space for \\<servername>\<sharename>, plus the
11433      * terminator.
11434      */
11435     len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
11436     name = malloc(len);
11437     snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
11438     return name;
11439 }
11440
11441
11442 #ifdef LOG_PACKET
11443 void smb_LogPacket(smb_packet_t *packet)
11444 {
11445     BYTE *vp, *cp;
11446     smb_t * smbp;
11447     unsigned length, paramlen, datalen, i, j;
11448     char buf[81];
11449     char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
11450
11451     if (!packet) return;
11452
11453     osi_Log0(smb_logp, "*** SMB packet dump ***");
11454
11455     smbp = (smb_t *) packet->data;
11456     vp = (BYTE *) packet->data;
11457
11458     paramlen = smbp->wct * 2;
11459     datalen = *((WORD *) (smbp->vdata + paramlen));
11460     length = sizeof(*smbp) + paramlen + 1 + datalen;
11461
11462     for (i=0;i < length; i+=16)
11463     {
11464         memset( buf, ' ', 80 );
11465         buf[80] = 0;
11466
11467         itoa( i, buf, 16 );
11468
11469         buf[strlen(buf)] = ' ';
11470
11471         cp = (BYTE*) buf + 7;
11472
11473         for (j=0;j < 16 && (i+j)<length; j++)
11474         {
11475             *(cp++) = hex[vp[i+j] >> 4];
11476             *(cp++) = hex[vp[i+j] & 0xf];
11477             *(cp++) = ' ';
11478
11479             if (j==7)
11480             {
11481                 *(cp++) = '-';
11482                 *(cp++) = ' ';
11483             }
11484         }
11485
11486         for (j=0;j < 16 && (i+j)<length;j++)
11487         {
11488             *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
11489             if (j==7)
11490             {
11491                 *(cp++) = ' ';
11492                 *(cp++) = '-';
11493                 *(cp++) = ' ';
11494             }
11495         }
11496
11497         *cp = 0;
11498
11499         osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
11500     }
11501
11502     osi_Log0(smb_logp, "*** End SMB packet dump ***");
11503 }
11504 #endif /* LOG_PACKET */
11505
11506
11507 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
11508 {
11509     int zilch;
11510     char output[4196];
11511
11512     smb_vc_t *vcp;
11513     smb_username_t *unp;
11514     smb_waitingLockRequest_t *wlrp;
11515
11516     if (lock)
11517         lock_ObtainRead(&smb_rctLock);
11518
11519     sprintf(output, "begin dumping smb_username_t\r\n");
11520     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11521     for (unp = usernamesp; unp; unp=unp->nextp)
11522     {
11523         cm_ucell_t *ucellp;
11524
11525         sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
11526                 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
11527                 unp->name ? unp->name : _C("NULL"),
11528                 unp->machine ? unp->machine : _C("NULL"));
11529         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11530
11531         sprintf(output, "  begin dumping cm_ucell_t\r\n");
11532         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11533
11534         for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
11535             sprintf(output, "  %s -- ucellp=0x%p, cellp=0x%p, flags=0x%x, tktLen=%04u, kvno=%03u, expires=%I64u, gen=%d, name=%s, cellname=%s\r\n",
11536                      cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
11537                      ucellp->expirationTime, ucellp->gen,
11538                      ucellp->userName,
11539                      ucellp->cellp ? ucellp->cellp->name : "<null>");
11540             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11541         }
11542
11543         sprintf(output, "  done dumping cm_ucell_t\r\n");
11544         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11545
11546     }
11547     sprintf(output, "done dumping smb_username_t\r\n");
11548     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11549
11550
11551     if (!smb_Enabled)
11552         goto done;
11553
11554     sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
11555     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11556
11557     for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
11558         smb_waitingLock_t *lockp;
11559
11560         sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
11561                  cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
11562         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11563
11564         sprintf(output, "  begin dumping smb_waitingLock_t\r\n");
11565         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11566         for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
11567             sprintf(output, "  %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
11568                     cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
11569             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11570         }
11571         sprintf(output, "  done dumping smb_waitingLock_t\r\n");
11572         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11573     }
11574
11575     sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
11576     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11577
11578     sprintf(output, "begin dumping smb_vc_t\r\n");
11579     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11580
11581     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11582     {
11583         smb_fid_t *fidp;
11584         smb_tid_t *tidp;
11585         smb_user_t *userp;
11586
11587         sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11588                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11589         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11590
11591         sprintf(output, "  begin dumping smb_user_t\r\n");
11592         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11593         for (userp = vcp->usersp; userp; userp = userp->nextp) {
11594             sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11595                     cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11596             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11597         }
11598         sprintf(output, "  done dumping smb_user_t\r\n");
11599         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11600
11601         sprintf(output, "  begin dumping smb_tid_t\r\n");
11602         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11603         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11604             sprintf(output, "  %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n",
11605                     cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11606                     tidp->pathname ? tidp->pathname : _C("NULL"));
11607             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11608         }
11609         sprintf(output, "  done dumping smb_tid_t\r\n");
11610         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11611
11612         sprintf(output, "  begin dumping smb_fid_t\r\n");
11613         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11614
11615         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11616         {
11617             sprintf(output, "  %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n",
11618                     cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11619                     fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11620                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11621             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11622         }
11623
11624         sprintf(output, "  done dumping smb_fid_t\r\n");
11625         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11626     }
11627
11628     sprintf(output, "done dumping smb_vc_t\r\n");
11629     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11630
11631     sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
11632     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11633
11634     for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
11635     {
11636         smb_fid_t *fidp;
11637         smb_tid_t *tidp;
11638         smb_user_t *userp;
11639
11640         sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11641                 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11642         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11643
11644         sprintf(output, "  begin dumping smb_user_t\r\n");
11645         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11646         for (userp = vcp->usersp; userp; userp = userp->nextp) {
11647             sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11648                     cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11649             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11650         }
11651         sprintf(output, "  done dumping smb_user_t\r\n");
11652         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11653
11654         sprintf(output, "  begin dumping smb_tid_t\r\n");
11655         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11656         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11657             sprintf(output, "  %s -- smb_tidp=0x%p, refCount=%d, tid=%d, vcp=0x%p, cm_userp=0x%p, flags=0x%x, delOk=%d, path=%S\r\n",
11658                     cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11659                     tidp->pathname ? tidp->pathname : _C("NULL"));
11660             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11661         }
11662         sprintf(output, "  done dumping smb_tid_t\r\n");
11663         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11664
11665         sprintf(output, "  begin dumping smb_fid_t\r\n");
11666         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11667
11668         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11669         {
11670             sprintf(output, "  %s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, userp=0x%p, ioctlp=0x%p, flags=0x%x, delOk=%d, NTopen_pathp=%S, NTopen_wholepathp=%S\r\n",
11671                     cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11672                     fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11673                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11674             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11675         }
11676
11677         sprintf(output, "  done dumping smb_fid_t\r\n");
11678         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11679     }
11680
11681     sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11682     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11683
11684   done:
11685     if (lock)
11686         lock_ReleaseRead(&smb_rctLock);
11687     return 0;
11688 }
11689
11690 long smb_IsNetworkStarted(void)
11691 {
11692     long rc;
11693
11694     if (!smb_Enabled)
11695         return 0;
11696
11697     lock_ObtainWrite(&smb_globalLock);
11698     rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11699     lock_ReleaseWrite(&smb_globalLock);
11700     return rc;
11701 }