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