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