Windows: Make use of SMB interface a runtime decision
[openafs.git] / src / WINNT / afsd / smb.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <roken.h>
13
14 #include <afs/stds.h>
15
16 #include <windows.h>
17 #pragma warning(push)
18 #pragma warning(disable: 4005)
19 #include <ntstatus.h>
20 #pragma warning(pop)
21 #include <sddl.h>
22 #include <stddef.h>
23 #include <stdlib.h>
24 #include <malloc.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <time.h>
28
29 #include "afsd.h"
30 #include <osi.h>
31 #include <rx\rx.h>
32 #include <rx/rx_prototypes.h>
33 #include <WINNT\afsreg.h>
34
35 #include "smb.h"
36 #include "msrpc.h"
37 #include "lanahelper.h"
38
39 #define STRSAFE_NO_DEPRECATE
40 #include <strsafe.h>
41
42 /* These characters are illegal in Windows filenames */
43 static clientchar_t *illegalChars = _C("\\/:*?\"<>|");
44
45 static int smbShutdownFlag = 0;
46 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
47
48 int smb_LogoffTokenTransfer;
49 time_t smb_LogoffTransferTimeout;
50
51 int smb_StoreAnsiFilenames = 0;
52
53 DWORD last_msg_time = 0;
54
55 long ongoingOps = 0;
56
57 unsigned int sessionGen = 0;
58
59 extern void afsi_log(char *pattern, ...);
60 extern HANDLE afsi_file;
61 extern int powerStateSuspended;
62
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
65
66 osi_log_t *  smb_logp;
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t  smb_ListenerLock;
70 osi_mutex_t  smb_StartedLock;
71
72 unsigned char smb_LANadapter = LANA_INVALID;
73 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
74 int  smb_LanAdapterChangeDetected = 0;
75 afs_uint32    smb_AsyncStore = 1;
76 afs_uint32    smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
77
78 BOOL isGateway = FALSE;
79
80 /* for debugging */
81 long smb_maxObsConcurrentCalls=0;
82 long smb_concurrentCalls=0;
83
84 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
85
86 smb_packet_t *smb_packetFreeListp;
87 smb_ncb_t *smb_ncbFreeListp;
88
89 afs_uint32 smb_NumServerThreads;
90
91 afs_uint32 numNCBs, numSessions, numVCs;
92
93 int smb_maxVCPerServer;
94 int smb_maxMpxRequests;
95
96 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
97 HANDLE smb_lsaHandle;
98 ULONG smb_lsaSecPackage;
99 LSA_STRING smb_lsaLogonOrigin;
100
101 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
102 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
103 EVENT_HANDLE **NCBreturns;
104 EVENT_HANDLE **NCBShutdown;
105 EVENT_HANDLE *smb_ServerShutdown;
106 EVENT_HANDLE ListenerShutdown[256];
107 DWORD NCBsessions[NCB_MAX];
108 NCB *NCBs[NCB_MAX];
109 struct smb_packet *bufs[NCB_MAX];
110
111 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
112 EVENT_HANDLE SessionEvents[SESSION_MAX];
113 unsigned short LSNs[SESSION_MAX];
114 int lanas[SESSION_MAX];
115 BOOL dead_sessions[SESSION_MAX];
116 LANA_ENUM lana_list;
117 /* for raw I/O */
118 osi_mutex_t smb_RawBufLock;
119 char *smb_RawBufs;
120
121 #define SMB_MASKFLAG_TILDE 1
122 #define SMB_MASKFLAG_CASEFOLD 2
123
124 #define RAWTIMEOUT INFINITE
125
126 /* for raw write */
127 typedef struct raw_write_cont {
128     long code;
129     osi_hyper_t offset;
130     long count;
131     char *buf;
132     int writeMode;
133     long alreadyWritten;
134 } raw_write_cont_t;
135
136 /* dir search stuff */
137 long smb_dirSearchCounter = 1;
138 smb_dirSearch_t *smb_firstDirSearchp;
139 smb_dirSearch_t *smb_lastDirSearchp;
140
141 /* Initial mode bits for files and directories.  Set to 0 to use
142    defaults. */
143 int smb_unixModeDefaultFile = 0666;
144 int smb_unixModeDefaultDir = 0777;
145
146 /* hide dot files? */
147 int smb_hideDotFiles;
148
149 /* Negotiate Unicode support? */
150 LONG smb_UseUnicode;
151
152 /* global state about V3 protocols */
153 int smb_useV3;          /* try to negotiate V3 */
154
155 static int showErrors = 0;
156 /* MessageBox or something like it */
157 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
158 = NULL;
159
160 /* GMT time info:
161  * Time in Unix format of midnight, 1/1/1970 local time.
162  * When added to dosUTime, gives Unix (AFS) time.
163  */
164 time_t smb_localZero = 0;
165
166 char *smb_localNamep = NULL;
167
168 smb_vc_t *smb_allVCsp;
169 smb_vc_t *smb_deadVCsp;
170
171 smb_username_t *usernamesp = NULL;
172
173 smb_waitingLockRequest_t *smb_allWaitingLocks;
174
175 /* forward decl */
176 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
177                         NCB *ncbp, raw_write_cont_t *rwcp);
178 int smb_NetbiosInit(int);
179
180 #ifdef LOG_PACKET
181 void smb_LogPacket(smb_packet_t *packet);
182 #endif /* LOG_PACKET */
183
184 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
185 int smb_ServerDomainNameLength = 0;
186 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
187 int smb_ServerOSLength = lengthof(smb_ServerOS);
188 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
189 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
190
191 /* Faux server GUID. This is never checked. */
192 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
193
194 void smb_InitReq(cm_req_t *reqp)
195 {
196     cm_InitReq(reqp);
197     reqp->flags |= CM_REQ_SOURCE_SMB;
198 }
199
200 const char * ncb_error_string(int code)
201 {
202     const char * s;
203     switch ( code ) {
204     case 0x01: s = "NRC_BUFLEN llegal buffer length";                   break;
205     case 0x03: s = "NRC_ILLCMD illegal command";                        break;
206     case 0x05: s = "NRC_CMDTMO command timed out";                      break;
207     case 0x06: s = "NRC_INCOMP message incomplete, issue another command"; break;
208     case 0x07: s = "NRC_BADDR  illegal buffer address";                 break;
209     case 0x08: s = "NRC_SNUMOUT session number out of range";           break;
210     case 0x09: s = "NRC_NORES no resource available";                   break;
211     case 0x0a: s = "NRC_SCLOSED asession closed";                       break;
212     case 0x0b: s = "NRC_CMDCAN command cancelled";                      break;
213     case 0x0d: s = "NRC_DUPNAME duplicate name";                        break;
214     case 0x0e: s = "NRC_NAMTFUL name table full";                       break;
215     case 0x0f: s = "NRC_ACTSES no deletions, name has active sessions"; break;
216     case 0x11: s = "NRC_LOCTFUL local session table full";              break;
217     case 0x12: s = "NRC_REMTFUL remote session table full";             break;
218     case 0x13: s = "NRC_ILLNN illegal name number";                     break;
219     case 0x14: s = "NRC_NOCALL no callname";                            break;
220     case 0x15: s = "NRC_NOWILD cannot put * in NCB_NAME";               break;
221     case 0x16: s = "NRC_INUSE name in use on remote adapter";           break;
222     case 0x17: s = "NRC_NAMERR name deleted";                           break;
223     case 0x18: s = "NRC_SABORT session ended abnormally";               break;
224     case 0x19: s = "NRC_NAMCONF name conflict detected";                break;
225     case 0x21: s = "NRC_IFBUSY interface busy, IRET before retrying";   break;
226     case 0x22: s = "NRC_TOOMANY too many commands outstanding, retry later";break;
227     case 0x23: s = "NRC_BRIDGE ncb_lana_num field invalid";             break;
228     case 0x24: s = "NRC_CANOCCR command completed while cancel occurring "; break;
229     case 0x26: s = "NRC_CANCEL command not valid to cancel";            break;
230     case 0x30: s = "NRC_DUPENV name defined by anther local process";   break;
231     case 0x34: s = "NRC_ENVNOTDEF xenvironment undefined. RESET required";      break;
232     case 0x35: s = "NRC_OSRESNOTAV required OS resources exhausted";    break;
233     case 0x36: s = "NRC_MAXAPPS max number of applications exceeded";   break;
234     case 0x37: s = "NRC_NOSAPS no saps available for netbios";          break;
235     case 0x38: s = "NRC_NORESOURCES requested resources are not available";     break;
236     case 0x39: s = "NRC_INVADDRESS invalid ncb address or length > segment";    break;
237     case 0x3B: s = "NRC_INVDDID invalid NCB DDID";                      break;
238     case 0x3C: s = "NRC_LOCKFAILlock of user area failed";              break;
239     case 0x3f: s = "NRC_OPENERR NETBIOS not loaded";                    break;
240     case 0x40: s = "NRC_SYSTEM system error";                           break;
241     default:   s = "unknown error";
242     }
243     return s;
244 }
245
246
247 char * myCrt_Dispatch(int i)
248 {
249     switch (i)
250     {
251     case 0x00:
252         return "(00)ReceiveCoreMakeDir";
253     case 0x01:
254         return "(01)ReceiveCoreRemoveDir";
255     case 0x02:
256         return "(02)ReceiveCoreOpen";
257     case 0x03:
258         return "(03)ReceiveCoreCreate";
259     case 0x04:
260         return "(04)ReceiveCoreClose";
261     case 0x05:
262         return "(05)ReceiveCoreFlush";
263     case 0x06:
264         return "(06)ReceiveCoreUnlink";
265     case 0x07:
266         return "(07)ReceiveCoreRename";
267     case 0x08:
268         return "(08)ReceiveCoreGetFileAttributes";
269     case 0x09:
270         return "(09)ReceiveCoreSetFileAttributes";
271     case 0x0a:
272         return "(0a)ReceiveCoreRead";
273     case 0x0b:
274         return "(0b)ReceiveCoreWrite";
275     case 0x0c:
276         return "(0c)ReceiveCoreLockRecord";
277     case 0x0d:
278         return "(0d)ReceiveCoreUnlockRecord";
279     case 0x0e:
280         return "(0e)SendCoreBadOp";
281     case 0x0f:
282         return "(0f)ReceiveCoreCreate";
283     case 0x10:
284         return "(10)ReceiveCoreCheckPath";
285     case 0x11:
286         return "(11)SendCoreBadOp";
287     case 0x12:
288         return "(12)ReceiveCoreSeek";
289     case 0x1a:
290         return "(1a)ReceiveCoreReadRaw";
291     case 0x1d:
292         return "(1d)ReceiveCoreWriteRawDummy";
293     case 0x22:
294         return "(22)ReceiveV3SetAttributes";
295     case 0x23:
296         return "(23)ReceiveV3GetAttributes";
297     case 0x24:
298         return "(24)ReceiveV3LockingX";
299     case 0x25:
300         return "(25)ReceiveV3Trans";
301     case 0x26:
302         return "(26)ReceiveV3Trans[aux]";
303     case 0x29:
304         return "(29)SendCoreBadOp";
305     case 0x2b:
306         return "(2b)ReceiveCoreEcho";
307     case 0x2d:
308         return "(2d)ReceiveV3OpenX";
309     case 0x2e:
310         return "(2e)ReceiveV3ReadX";
311     case 0x2f:
312         return "(2f)ReceiveV3WriteX";
313     case 0x32:
314         return "(32)ReceiveV3Tran2A";
315     case 0x33:
316         return "(33)ReceiveV3Tran2A[aux]";
317     case 0x34:
318         return "(34)ReceiveV3FindClose";
319     case 0x35:
320         return "(35)ReceiveV3FindNotifyClose";
321     case 0x70:
322         return "(70)ReceiveCoreTreeConnect";
323     case 0x71:
324         return "(71)ReceiveCoreTreeDisconnect";
325     case 0x72:
326         return "(72)ReceiveNegotiate";
327     case 0x73:
328         return "(73)ReceiveV3SessionSetupX";
329     case 0x74:
330         return "(74)ReceiveV3UserLogoffX";
331     case 0x75:
332         return "(75)ReceiveV3TreeConnectX";
333     case 0x80:
334         return "(80)ReceiveCoreGetDiskAttributes";
335     case 0x81:
336         return "(81)ReceiveCoreSearchDir";
337     case 0x82:
338         return "(82)Find";
339     case 0x83:
340         return "(83)FindUnique";
341     case 0x84:
342         return "(84)FindClose";
343     case 0xA0:
344         return "(A0)ReceiveNTTransact";
345     case 0xA2:
346         return "(A2)ReceiveNTCreateX";
347     case 0xA4:
348         return "(A4)ReceiveNTCancel";
349     case 0xA5:
350         return "(A5)ReceiveNTRename";
351     case 0xc0:
352         return "(C0)OpenPrintFile";
353     case 0xc1:
354         return "(C1)WritePrintFile";
355     case 0xc2:
356         return "(C2)ClosePrintFile";
357     case 0xc3:
358         return "(C3)GetPrintQueue";
359     case 0xd8:
360         return "(D8)ReadBulk";
361     case 0xd9:
362         return "(D9)WriteBulk";
363     case 0xda:
364         return "(DA)WriteBulkData";
365     default:
366         return "unknown SMB op";
367     }
368 }
369
370 char * myCrt_2Dispatch(int i)
371 {
372     switch (i)
373     {
374     default:
375         return "unknown SMB op-2";
376     case 0:
377         return "S(00)CreateFile_ReceiveTran2Open";
378     case 1:
379         return "S(01)FindFirst_ReceiveTran2SearchDir";
380     case 2:
381         return "S(02)FindNext_ReceiveTran2SearchDir";   /* FindNext */
382     case 3:
383         return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
384     case 4:
385         return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
386     case 5:
387         return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
388     case 6:
389         return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
390     case 7:
391         return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
392     case 8:
393         return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
394     case 9:
395         return "S(09)_ReceiveTran2FSCTL";
396     case 10:
397         return "S(0a)_ReceiveTran2IOCTL";
398     case 11:
399         return "S(0b)_ReceiveTran2FindNotifyFirst";
400     case 12:
401         return "S(0c)_ReceiveTran2FindNotifyNext";
402     case 13:
403         return "S(0d)_ReceiveTran2CreateDirectory";
404     case 14:
405         return "S(0e)_ReceiveTran2SessionSetup";
406     case 15:
407         return "S(0f)_QueryFileSystemInformationFid";
408     case 16:
409         return "S(10)_ReceiveTran2GetDfsReferral";
410     case 17:
411         return "S(11)_ReceiveTran2ReportDfsInconsistency";
412     }
413 }
414
415 char * myCrt_RapDispatch(int i)
416 {
417     switch(i)
418     {
419     default:
420         return "unknown RAP OP";
421     case 0:
422         return "RAP(0)NetShareEnum";
423     case 1:
424         return "RAP(1)NetShareGetInfo";
425     case 13:
426         return "RAP(13)NetServerGetInfo";
427     case 63:
428         return "RAP(63)NetWkStaGetInfo";
429     }
430 }
431
432 char * myCrt_NmpipeDispatch(int i)
433 {
434     switch(i) {
435     case SMB_TRANS_SET_NMPIPE_STATE:
436         return "SET NMPIPE STATE";
437
438     case SMB_TRANS_RAW_READ_NMPIPE:
439         return "RAW READ NMPIPE";
440
441     case SMB_TRANS_QUERY_NMPIPE_STATE:
442         return "QUERY NMPIPE STATE";
443
444     case SMB_TRANS_QUERY_NMPIPE_INFO:
445         return "QUERY NMPIPE INFO";
446
447     case SMB_TRANS_PEEK_NMPIPE:
448         return "PEEK NMPIPE";
449
450     case SMB_TRANS_TRANSACT_NMPIPE:
451         return "TRANSACT NMPIPE";
452
453     case SMB_TRANS_RAW_WRITE_NMPIPE:
454         return "WRITE NMPIPE";
455
456     case SMB_TRANS_READ_NMPIPE:
457         return "READ NMPIPE";
458
459     case SMB_TRANS_WRITE_NMPIPE:
460         return "WRITE NMPIPE";
461
462     case SMB_TRANS_WAIT_NMPIPE:
463         return "WAIT NMPIPE";
464
465     case SMB_TRANS_CALL_NMPIPE:
466         return "CALL NMPIPE";
467     }
468     return "(Unknown)";
469 }
470
471 /* scache must be locked */
472 unsigned int smb_Attributes(cm_scache_t *scp)
473 {
474     unsigned int attrs;
475
476     if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
477          scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
478          scp->fileType == CM_SCACHETYPE_INVALID)
479     {
480         attrs = SMB_ATTR_DIRECTORY;
481 #ifdef SPECIAL_FOLDERS
482         attrs |= SMB_ATTR_SYSTEM;               /* FILE_ATTRIBUTE_SYSTEM */
483 #endif /* SPECIAL_FOLDERS */
484     } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
485         attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
486     } else
487         attrs = 0;
488
489     /*
490      * We used to mark a file RO if it was in an RO volume, but that
491      * turns out to be impolitic in NT.  See defect 10007.
492      */
493 #ifdef notdef
494     if ((scp->unixModeBits & 0200) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
495         attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
496 #else
497     if ((scp->unixModeBits & 0200) == 0)
498         attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
499 #endif
500
501     return attrs;
502 }
503
504 void smb_SetInitialModeBitsForFile(int smb_attr, cm_attr_t * attr)
505 {
506     if (smb_unixModeDefaultFile != 0) {
507         attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
508         attr->unixModeBits = smb_unixModeDefaultFile;
509         if (smb_attr & SMB_ATTR_READONLY)
510             attr->unixModeBits &= ~0222;
511     }
512 }
513
514 void smb_SetInitialModeBitsForDir(int smb_attr, cm_attr_t * attr)
515 {
516     if (smb_unixModeDefaultDir != 0) {
517         attr->mask |= CM_ATTRMASK_UNIXMODEBITS;
518         attr->unixModeBits = smb_unixModeDefaultDir;
519     }
520 }
521
522 /* Check if the named file/dir is a dotfile/dotdir */
523 /* String pointed to by lastComp can have leading slashes, but otherwise should have
524    no other patch components */
525 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
526     clientchar_t *s;
527
528     if(lastComp) {
529         /* skip over slashes */
530         for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
531     }
532     else
533         return 0;
534
535     /* nulls, curdir and parent dir doesn't count */
536     if (!*s)
537         return 0;
538     if (*s == _C('.')) {
539         if (!*(s + 1))
540             return 0;
541         if(*(s+1) == _C('.') && !*(s + 2))
542             return 0;
543         return 1;
544     }
545     return 0;
546 }
547
548 static int ExtractBits(WORD bits, short start, short len)
549 {
550     int end;
551     WORD num;
552
553     end = start + len;
554
555     num = bits << (16 - end);
556     num = num >> ((16 - end) + start);
557
558     return (int)num;
559 }
560
561 void ShowUnixTime(char *FuncName, time_t unixTime)
562 {
563     FILETIME ft;
564     WORD wDate, wTime;
565
566     cm_LargeSearchTimeFromUnixTime(&ft, unixTime);
567
568     if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
569         osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
570     else {
571         int day, month, year, sec, min, hour;
572         char msg[256];
573
574         day = ExtractBits(wDate, 0, 5);
575         month = ExtractBits(wDate, 5, 4);
576         year = ExtractBits(wDate, 9, 7) + 1980;
577
578         sec = ExtractBits(wTime, 0, 5);
579         min = ExtractBits(wTime, 5, 6);
580         hour = ExtractBits(wTime, 11, 5);
581
582         sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
583         osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
584     }
585 }
586
587 /* Determine if we are observing daylight savings time */
588 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
589 {
590     TIME_ZONE_INFORMATION timeZoneInformation;
591     SYSTEMTIME utc, local, localDST;
592
593     /* Get the time zone info. NT uses this to calc if we are in DST. */
594     GetTimeZoneInformation(&timeZoneInformation);
595
596     /* Return the daylight bias */
597     *pDstBias = timeZoneInformation.DaylightBias;
598
599     /* Return the bias */
600     *pBias = timeZoneInformation.Bias;
601
602     /* Now determine if DST is being observed */
603
604     /* Get the UTC (GMT) time */
605     GetSystemTime(&utc);
606
607     /* Convert UTC time to local time using the time zone info.  If we are
608        observing DST, the calculated local time will include this.
609      */
610     SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
611
612     /* Set the daylight bias to 0.  The daylight bias is the amount of change
613      * in time that we use for daylight savings time.  By setting this to 0
614      * we cause there to be no change in time during daylight savings time.
615      */
616     timeZoneInformation.DaylightBias = 0;
617
618     /* Convert the utc time to local time again, but this time without any
619        adjustment for daylight savings time.
620        */
621     SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
622
623     /* If the two times are different, then it means that the localDST that
624        we calculated includes the daylight bias, and therefore we are
625        observing daylight savings time.
626      */
627     *pDST = localDST.wHour != local.wHour;
628 }
629
630
631 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
632 {
633     BOOL dst;       /* Will be TRUE if observing DST */
634     LONG dstBias;   /* Offset from local time if observing DST */
635     LONG bias;      /* Offset from GMT for local time */
636
637     /*
638      * This function will adjust the last write time to compensate
639      * for two bugs in the smb client:
640      *
641      *    1) During Daylight Savings Time, the LastWriteTime is ahead
642      *       in time by the DaylightBias (ignoring the sign - the
643      *       DaylightBias is always stored as a negative number).  If
644      *       the DaylightBias is -60, then the LastWriteTime will be
645      *       ahead by 60 minutes.
646      *
647      *    2) If the local time zone is a positive offset from GMT, then
648      *       the LastWriteTime will be the correct local time plus the
649      *       Bias (ignoring the sign - a positive offset from GMT is
650      *       always stored as a negative Bias).  If the Bias is -120,
651      *       then the LastWriteTime will be ahead by 120 minutes.
652      *
653      *    These bugs can occur at the same time.
654      */
655
656     GetTimeZoneInfo(&dst, &dstBias, &bias);
657
658     /* First adjust for DST */
659     if (dst)
660         *pLastWriteTime -= (-dstBias * 60);     /* Convert dstBias to seconds */
661
662     /* Now adjust for a positive offset from GMT (a negative bias). */
663     if (bias < 0)
664         *pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
665 }
666
667 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
668 {
669     time_t diff_t = unixTime - smb_localZero;
670 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
671     osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
672 #endif
673     *dosUTimep = (afs_uint32)diff_t;
674 }
675
676 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
677 {
678     *unixTimep = dosTime + smb_localZero;
679 }
680
681 void smb_MarkAllVCsDead(smb_vc_t * exclude)
682 {
683     smb_vc_t *vcp;
684     smb_vc_t **vcp_to_cleanup = NULL;
685     int n_to_cleanup = 0;
686     int i;
687
688     osi_Log1(smb_logp, "Marking all VCs as dead excluding %p", exclude);
689
690     lock_ObtainWrite(&smb_globalLock);  /* for dead_sessions[] */
691     lock_ObtainWrite(&smb_rctLock);
692     for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
693
694         if (vcp->magic != SMB_VC_MAGIC)
695             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
696                       __FILE__, __LINE__);
697
698         if (vcp == exclude)
699             continue;
700
701         lock_ObtainMutex(&vcp->mx);
702         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
703             vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
704             lock_ReleaseMutex(&vcp->mx);
705             dead_sessions[vcp->session] = TRUE;
706         } else {
707             lock_ReleaseMutex(&vcp->mx);
708         }
709         n_to_cleanup ++;
710     }
711
712     vcp_to_cleanup = malloc(sizeof(vcp_to_cleanup[0]) * n_to_cleanup);
713     i = 0;
714     for (vcp = smb_allVCsp; vcp; vcp = vcp->nextp) {
715         if (vcp == exclude)
716             continue;
717
718         vcp_to_cleanup[i++] = vcp;
719         smb_HoldVCNoLock(vcp);
720     }
721
722     osi_assert(i == n_to_cleanup);
723
724     lock_ReleaseWrite(&smb_rctLock);
725     lock_ReleaseWrite(&smb_globalLock);
726
727     for (i=0; i < n_to_cleanup; i++) {
728         smb_CleanupDeadVC(vcp_to_cleanup[i]);
729         smb_ReleaseVC(vcp_to_cleanup[i]);
730         vcp_to_cleanup[i] = 0;
731     }
732
733     free(vcp_to_cleanup);
734 }
735
736 #ifdef DEBUG_SMB_REFCOUNT
737 smb_vc_t *smb_FindVCDbg(unsigned short lsn, int flags, int lana, char *file, long line)
738 #else
739 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
740 #endif
741 {
742     smb_vc_t *vcp;
743
744     lock_ObtainWrite(&smb_globalLock);  /* for numVCs */
745     lock_ObtainWrite(&smb_rctLock);
746     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
747         if (vcp->magic != SMB_VC_MAGIC)
748             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
749                        __FILE__, __LINE__);
750
751         lock_ObtainMutex(&vcp->mx);
752         if (lsn == vcp->lsn && lana == vcp->lana &&
753             !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
754             lock_ReleaseMutex(&vcp->mx);
755             smb_HoldVCNoLock(vcp);
756             break;
757         }
758         lock_ReleaseMutex(&vcp->mx);
759     }
760     if (!vcp && (flags & SMB_FLAG_CREATE)) {
761         vcp = malloc(sizeof(*vcp));
762         memset(vcp, 0, sizeof(*vcp));
763         vcp->vcID = ++numVCs;
764         vcp->magic = SMB_VC_MAGIC;
765         vcp->refCount = 2;      /* smb_allVCsp and caller */
766         vcp->tidCounter = 1;
767         vcp->fidCounter = 1;
768         vcp->uidCounter = 1;    /* UID 0 is reserved for blank user */
769         vcp->nextp = smb_allVCsp;
770         smb_allVCsp = vcp;
771         lock_InitializeMutex(&vcp->mx, "vc_t mutex", LOCK_HIERARCHY_SMB_VC);
772         vcp->lsn = lsn;
773         vcp->lana = lana;
774         vcp->secCtx = NULL;
775
776         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
777             /* We must obtain a challenge for extended auth
778              * in case the client negotiates smb v3
779              */
780             NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
781             MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
782             PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
783             ULONG lsaRespSize = 0;
784
785             lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
786
787             nts = LsaCallAuthenticationPackage( smb_lsaHandle,
788                                                 smb_lsaSecPackage,
789                                                 &lsaReq,
790                                                 sizeof(lsaReq),
791                                                 &lsaResp,
792                                                 &lsaRespSize,
793                                                 &ntsEx);
794             if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
795                 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
796                          nts, ntsEx, sizeof(lsaReq), lsaRespSize);
797                     afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
798                          nts, ntsEx, lsaRespSize);
799             }
800             osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
801
802             if (ntsEx == STATUS_SUCCESS) {
803                 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
804             } else {
805                 /*
806                  * This will cause the subsequent authentication to fail but
807                  * that is better than us dereferencing a NULL pointer and
808                  * crashing.
809                  */
810                 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
811             }
812             if (lsaResp)
813                 LsaFreeReturnBuffer(lsaResp);
814         }
815         else
816             memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
817
818         if (numVCs >= CM_SESSION_RESERVED) {
819             numVCs = 0;
820             osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
821         }
822     }
823 #ifdef DEBUG_SMB_REFCOUNT
824     if (vcp) {
825         afsi_log("%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
826         osi_Log4(smb_logp,"%s:%d smb_FindVC vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
827     }
828 #endif
829     lock_ReleaseWrite(&smb_rctLock);
830     lock_ReleaseWrite(&smb_globalLock);
831     return vcp;
832 }
833
834 static int smb_Is8Dot3StarMask(clientchar_t *maskp)
835 {
836     int i;
837     clientchar_t tc;
838
839     for(i=0; i<11; i++) {
840         tc = *maskp++;
841         if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
842             return 1;
843     }
844     return 0;
845 }
846
847 static int smb_IsStarMask(clientchar_t *maskp)
848 {
849     clientchar_t tc;
850
851     while (*maskp) {
852         tc = *maskp++;
853         if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
854             return 1;
855     }
856     return 0;
857 }
858
859 #ifdef DEBUG_SMB_REFCOUNT
860 void smb_ReleaseVCInternalDbg(smb_vc_t *vcp, char * file, long line)
861 #define smb_ReleaseVCInternal(a) smb_ReleaseVCInternalDbg(a, file, line)
862 #else
863 void smb_ReleaseVCInternal(smb_vc_t *vcp)
864 #endif
865 {
866     smb_vc_t **vcpp;
867     smb_vc_t * avcp;
868
869     lock_AssertWrite(&smb_rctLock);
870     vcp->refCount--;
871
872     if (vcp->refCount == 0) {
873         if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
874 #ifdef DEBUG_SMB_REFCOUNT
875             afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
876             osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is dead ref %d", file, line, vcp, vcp->refCount);
877 #endif
878             /* remove VCP from smb_deadVCsp */
879             for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
880                 if (*vcpp == vcp) {
881                     *vcpp = vcp->nextp;
882                     break;
883                 }
884             }
885             lock_FinalizeMutex(&vcp->mx);
886             memset(vcp,0,sizeof(smb_vc_t));
887             free(vcp);
888         } else {
889 #ifdef DEBUG_SMB_REFCOUNT
890             afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is alive ref %d", file, line, vcp, vcp->refCount);
891 #endif
892             for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
893                 if (avcp == vcp)
894                     break;
895             }
896             osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
897                       avcp?"":"not ",vcp, vcp->refCount);
898
899             /* This is a wrong.  However, I suspect that there is an undercount
900              * and I don't want to release 1.4.1 in a state that will allow
901              * smb_vc_t objects to be deallocated while still in the
902              * smb_allVCsp list.  The list is supposed to keep a reference
903              * to the smb_vc_t.  Put it back.
904              */
905             if (avcp) {
906                 vcp->refCount++;
907 #ifdef DEBUG_SMB_REFCOUNT
908                 afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
909                 osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p is in smb_allVCsp ref %d", file, line, vcp, vcp->refCount);
910 #endif
911             }
912         }
913     } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
914         /* The reference count is non-zero but the VC is dead.
915          * This implies that some FIDs, TIDs, etc on the VC have yet to
916          * be cleaned up.  If we were not called by smb_CleanupDeadVC(),
917          * add a reference that will be dropped by
918          * smb_CleanupDeadVC() and try to cleanup the VC again.
919          * Eventually the refCount will drop to zero when all of the
920          * active threads working with the VC end their task.
921          */
922         if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
923             vcp->refCount++;        /* put the refCount back */
924             lock_ReleaseWrite(&smb_rctLock);
925             smb_CleanupDeadVC(vcp);
926 #ifdef DEBUG_SMB_REFCOUNT
927             afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
928             osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p after CleanupDeadVC ref %d", file, line, vcp, vcp->refCount);
929 #endif
930             lock_ObtainWrite(&smb_rctLock);
931         }
932     } else {
933 #ifdef DEBUG_SMB_REFCOUNT
934         afsi_log("%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
935         osi_Log4(smb_logp,"%s:%d smb_ReleaseVCInternal vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
936 #endif
937     }
938 }
939
940 #ifdef DEBUG_SMB_REFCOUNT
941 void smb_ReleaseVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
942 #else
943 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
944 #endif
945 {
946     lock_AssertWrite(&smb_rctLock);
947     osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
948     smb_ReleaseVCInternal(vcp);
949 }
950
951 #ifdef DEBUG_SMB_REFCOUNT
952 void smb_ReleaseVCDbg(smb_vc_t *vcp, char * file, long line)
953 #else
954 void smb_ReleaseVC(smb_vc_t *vcp)
955 #endif
956 {
957     lock_ObtainWrite(&smb_rctLock);
958     osi_Log2(smb_logp,"smb_ReleaseVC       vcp %x ref %d",vcp, vcp->refCount);
959     smb_ReleaseVCInternal(vcp);
960     lock_ReleaseWrite(&smb_rctLock);
961 }
962
963 #ifdef DEBUG_SMB_REFCOUNT
964 void smb_HoldVCNoLockDbg(smb_vc_t *vcp, char * file, long line)
965 #else
966 void smb_HoldVCNoLock(smb_vc_t *vcp)
967 #endif
968 {
969     lock_AssertWrite(&smb_rctLock);
970     vcp->refCount++;
971 #ifdef DEBUG_SMB_REFCOUNT
972     afsi_log("%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
973     osi_Log4(smb_logp,"%s:%d smb_HoldVCNoLock vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
974 #else
975     osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
976 #endif
977 }
978
979 #ifdef DEBUG_SMB_REFCOUNT
980 void smb_HoldVCDbg(smb_vc_t *vcp, char * file, long line)
981 #else
982 void smb_HoldVC(smb_vc_t *vcp)
983 #endif
984 {
985     lock_ObtainWrite(&smb_rctLock);
986     vcp->refCount++;
987 #ifdef DEBUG_SMB_REFCOUNT
988     afsi_log("%s:%d smb_HoldVC       vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
989     osi_Log4(smb_logp,"%s:%d smb_HoldVC       vcp 0x%p ref %d", file, line, vcp, vcp->refCount);
990 #else
991     osi_Log2(smb_logp,"smb_HoldVC       vcp %x ref %d",vcp, vcp->refCount);
992 #endif
993     lock_ReleaseWrite(&smb_rctLock);
994 }
995
996 void smb_CleanupDeadVC(smb_vc_t *vcp)
997 {
998     smb_fid_t *fidpIter;
999     smb_fid_t *fidpNext;
1000     unsigned short fid;
1001     smb_tid_t *tidpIter;
1002     smb_tid_t *tidpNext;
1003     unsigned short tid;
1004     smb_user_t *uidpIter;
1005     smb_user_t *uidpNext;
1006     smb_vc_t **vcpp;
1007     afs_uint32 refCount = 0;
1008
1009     lock_ObtainMutex(&vcp->mx);
1010     if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1011         lock_ReleaseMutex(&vcp->mx);
1012         osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1013         return;
1014     }
1015     vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1016     lock_ReleaseMutex(&vcp->mx);
1017     osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1018
1019     lock_ObtainWrite(&smb_rctLock);
1020     /* remove VCP from smb_allVCsp */
1021     for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1022         if ((*vcpp)->magic != SMB_VC_MAGIC)
1023             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1024                        __FILE__, __LINE__);
1025         if (*vcpp == vcp) {
1026             *vcpp = vcp->nextp;
1027             vcp->nextp = smb_deadVCsp;
1028             smb_deadVCsp = vcp;
1029             /* Hold onto the reference until we are done with this function */
1030             break;
1031         }
1032     }
1033
1034     for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1035         fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1036
1037         if (fidpIter->deleteOk)
1038             continue;
1039
1040         fid = fidpIter->fid;
1041         osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1042
1043         smb_HoldFIDNoLock(fidpIter);
1044         lock_ReleaseWrite(&smb_rctLock);
1045
1046         smb_CloseFID(vcp, fidpIter, NULL, 0);
1047         smb_ReleaseFID(fidpIter);
1048
1049         lock_ObtainWrite(&smb_rctLock);
1050         fidpNext = vcp->fidsp;
1051     }
1052
1053     for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1054         tidpNext = tidpIter->nextp;
1055         if (tidpIter->deleteOk)
1056             continue;
1057         tidpIter->deleteOk = 1;
1058
1059         tid = tidpIter->tid;
1060         osi_Log2(smb_logp, "  Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1061
1062         smb_HoldTIDNoLock(tidpIter);
1063         smb_ReleaseTID(tidpIter, TRUE);
1064         tidpNext = vcp->tidsp;
1065     }
1066
1067     for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1068         uidpNext = uidpIter->nextp;
1069         if (uidpIter->deleteOk)
1070             continue;
1071         uidpIter->deleteOk = 1;
1072
1073         /* do not add an additional reference count for the smb_user_t
1074          * as the smb_vc_t already is holding a reference */
1075         lock_ReleaseWrite(&smb_rctLock);
1076
1077         smb_ReleaseUID(uidpIter);
1078
1079         lock_ObtainWrite(&smb_rctLock);
1080         uidpNext = vcp->usersp;
1081     }
1082
1083     /* The vcp is now on the deadVCsp list.  We intentionally drop the
1084      * reference so that the refcount can reach 0 and we can delete it
1085      *
1086      * If the refCount == 1 going into the ReleaseVCNoLock call
1087      * the object will be freed and it won't be safe to clear
1088      * the flag.
1089      */
1090     refCount = vcp->refCount;
1091     smb_ReleaseVCNoLock(vcp);
1092     if (refCount > 1) {
1093         lock_ObtainMutex(&vcp->mx);
1094         vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1095         lock_ReleaseMutex(&vcp->mx);
1096     }
1097
1098     lock_ReleaseWrite(&smb_rctLock);
1099     osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1100 }
1101
1102 #ifdef DEBUG_SMB_REFCOUNT
1103 smb_tid_t *smb_FindTIDDbg(smb_vc_t *vcp, unsigned short tid, int flags, char * file, long line)
1104 #else
1105 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1106 #endif
1107 {
1108     smb_tid_t *tidp;
1109
1110     lock_ObtainWrite(&smb_rctLock);
1111   retry:
1112     for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1113         if (tidp->refCount == 0 && tidp->deleteOk) {
1114             tidp->refCount++;
1115             smb_ReleaseTID(tidp, TRUE);
1116             goto retry;
1117         }
1118
1119         if (tid == tidp->tid) {
1120             tidp->refCount++;
1121             break;
1122         }
1123     }
1124     if (!tidp && (flags & SMB_FLAG_CREATE)) {
1125         tidp = malloc(sizeof(*tidp));
1126         memset(tidp, 0, sizeof(*tidp));
1127         tidp->nextp = vcp->tidsp;
1128         tidp->refCount = 1;
1129         tidp->vcp = vcp;
1130         smb_HoldVCNoLock(vcp);
1131         vcp->tidsp = tidp;
1132         lock_InitializeMutex(&tidp->mx, "tid_t mutex", LOCK_HIERARCHY_SMB_TID);
1133         tidp->tid = tid;
1134     }
1135 #ifdef DEBUG_SMB_REFCOUNT
1136     if (tidp) {
1137         afsi_log("%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1138         osi_Log4(smb_logp,"%s:%d smb_FindTID tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1139     }
1140 #endif
1141     lock_ReleaseWrite(&smb_rctLock);
1142     return tidp;
1143 }
1144
1145 #ifdef DEBUG_SMB_REFCOUNT
1146 void smb_HoldTIDNoLockDbg(smb_tid_t *tidp, char * file, long line)
1147 #else
1148 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1149 #endif
1150 {
1151     lock_AssertWrite(&smb_rctLock);
1152     tidp->refCount++;
1153 #ifdef DEBUG_SMB_REFCOUNT
1154     afsi_log("%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1155     osi_Log4(smb_logp,"%s:%d smb_HoldTIDNoLock tidp 0x%p ref %d", file, line, tidp, tidp->refCount);
1156 #endif
1157 }
1158
1159 #ifdef DEBUG_SMB_REFCOUNT
1160 void smb_ReleaseTIDDbg(smb_tid_t *tidp, afs_uint32 locked, char *file, long line)
1161 #else
1162 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1163 #endif
1164 {
1165     smb_tid_t *tp;
1166     smb_tid_t **ltpp;
1167     cm_user_t *userp = NULL;
1168     smb_vc_t  *vcp = NULL;
1169
1170     if (!locked)
1171         lock_ObtainWrite(&smb_rctLock);
1172     else
1173         lock_AssertWrite(&smb_rctLock);
1174
1175     osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1176 #ifdef DEBUG_SMB_REFCOUNT
1177     afsi_log("%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1178     osi_Log5(smb_logp,"%s:%d smb_ReleaseTID tidp 0x%p ref %d deleteOk %d", file, line, tidp, tidp->refCount, tidp->deleteOk);
1179 #endif
1180     if (tidp->refCount == 0) {
1181         if (tidp->deleteOk) {
1182             ltpp = &tidp->vcp->tidsp;
1183             for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1184                 if (tp == tidp)
1185                     break;
1186             }
1187             osi_assertx(tp != NULL, "null smb_tid_t");
1188             *ltpp = tp->nextp;
1189             lock_FinalizeMutex(&tidp->mx);
1190             userp = tidp->userp;        /* remember to drop ref later */
1191             tidp->userp = NULL;
1192             vcp = tidp->vcp;
1193             tidp->vcp = NULL;
1194             free(tidp);
1195         }
1196     }
1197     if (vcp)
1198         smb_ReleaseVCNoLock(vcp);
1199     if (!locked)
1200         lock_ReleaseWrite(&smb_rctLock);
1201     if (userp)
1202         cm_ReleaseUser(userp);
1203 }
1204
1205 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1206 {
1207     smb_user_t *uidp = NULL;
1208
1209     lock_ObtainWrite(&smb_rctLock);
1210     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1211         if (uid == uidp->userID) {
1212             uidp->refCount++;
1213             osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1214                      vcp, uidp->userID,
1215                      ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1216             break;
1217         }
1218     }
1219     if (!uidp && (flags & SMB_FLAG_CREATE)) {
1220         uidp = malloc(sizeof(*uidp));
1221         memset(uidp, 0, sizeof(*uidp));
1222         uidp->nextp = vcp->usersp;
1223         uidp->refCount = 2; /* one for the vcp and one for the caller */
1224         uidp->vcp = vcp;
1225         smb_HoldVCNoLock(vcp);
1226         vcp->usersp = uidp;
1227         lock_InitializeMutex(&uidp->mx, "user_t mutex", LOCK_HIERARCHY_SMB_UID);
1228         uidp->userID = uid;
1229         osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1230                  vcp, uidp->userID,
1231                  ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1232     }
1233     lock_ReleaseWrite(&smb_rctLock);
1234     return uidp;
1235 }
1236
1237 afs_int32 smb_userIsLocalSystem(smb_user_t *uidp)
1238 {
1239     SID *pSid = NULL;
1240     DWORD dwSize1 = 0, dwSize2 = 0;
1241     wchar_t *pszRefDomain = NULL;
1242     SID_NAME_USE snu = SidTypeGroup;
1243     clientchar_t * secSidString = NULL;
1244     DWORD gle;
1245     afs_int32 isSystem = 0;
1246
1247     if (uidp->unp->flags & SMB_USERNAMEFLAG_SID) {
1248         isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, uidp->unp->name);
1249         return isSystem;
1250     }
1251
1252     /*
1253      * The input name is not a SID for the user.  See if we can
1254      * obtain the SID for the specified name.  If we can, use
1255      * that instead of the name provided for the comparison.
1256      */
1257
1258     LookupAccountNameW( NULL /* System Name to begin Search */,
1259                         uidp->unp->name,
1260                         NULL, &dwSize1,
1261                         NULL, &dwSize2,
1262                         &snu);
1263     gle = GetLastError();
1264     if (gle == ERROR_INSUFFICIENT_BUFFER) {
1265         pSid = malloc(dwSize1);
1266         /*
1267          * Although dwSize2 is supposed to include the terminating
1268          * NUL character, on Win7 it does not.
1269          */
1270         pszRefDomain = malloc((dwSize2 + 1) * sizeof(wchar_t));
1271     }
1272
1273     if ( pSid && pszRefDomain ) {
1274         memset(pSid, 0, dwSize1);
1275
1276         if (LookupAccountNameW( NULL /* System Name to begin Search */,
1277                                 uidp->unp->name,
1278                                 pSid, &dwSize1,
1279                                 pszRefDomain, &dwSize2,
1280                                 &snu))
1281             ConvertSidToStringSidW(pSid, &secSidString);
1282     }
1283
1284     if (secSidString) {
1285         isSystem = !cm_ClientStrCmp(NTSID_LOCAL_SYSTEM, secSidString);
1286         LocalFree(secSidString);
1287     }
1288
1289     if (pSid)
1290         free(pSid);
1291     if (pszRefDomain)
1292         free(pszRefDomain);
1293
1294     return isSystem;
1295 }
1296
1297 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1298                                    afs_uint32 flags)
1299 {
1300     smb_username_t *unp= NULL;
1301
1302     lock_ObtainWrite(&smb_rctLock);
1303     for(unp = usernamesp; unp; unp = unp->nextp) {
1304         if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1305             cm_ClientStrCmpI(unp->machine, machine) == 0) {
1306             unp->refCount++;
1307             break;
1308         }
1309     }
1310     if (!unp && (flags & SMB_FLAG_CREATE)) {
1311         unp = malloc(sizeof(*unp));
1312         memset(unp, 0, sizeof(*unp));
1313         unp->refCount = 1;
1314         unp->nextp = usernamesp;
1315         unp->name = cm_ClientStrDup(usern);
1316         unp->machine = cm_ClientStrDup(machine);
1317         usernamesp = unp;
1318         lock_InitializeMutex(&unp->mx, "username_t mutex", LOCK_HIERARCHY_SMB_USERNAME);
1319         if (flags & SMB_FLAG_AFSLOGON)
1320             unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1321     }
1322
1323     lock_ReleaseWrite(&smb_rctLock);
1324     return unp;
1325 }
1326
1327 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1328 {
1329     smb_user_t *uidp= NULL;
1330
1331     lock_ObtainWrite(&smb_rctLock);
1332     for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1333         if (!uidp->unp)
1334             continue;
1335         if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1336             uidp->refCount++;
1337             osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1338                      vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1339             break;
1340         } else
1341             continue;
1342     }
1343     lock_ReleaseWrite(&smb_rctLock);
1344     return uidp;
1345 }
1346
1347 void smb_ReleaseUsername(smb_username_t *unp)
1348 {
1349     smb_username_t *up;
1350     smb_username_t **lupp;
1351     cm_user_t *userp = NULL;
1352     time_t      now = osi_Time();
1353
1354     lock_ObtainWrite(&smb_rctLock);
1355     osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1356     if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1357         (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1358         lupp = &usernamesp;
1359         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1360             if (up == unp)
1361                 break;
1362         }
1363         osi_assertx(up != NULL, "null smb_username_t");
1364         *lupp = up->nextp;
1365         up->nextp = NULL;                       /* do not remove this */
1366         lock_FinalizeMutex(&unp->mx);
1367         userp = unp->userp;
1368         free(unp->name);
1369         free(unp->machine);
1370         free(unp);
1371     }
1372     lock_ReleaseWrite(&smb_rctLock);
1373     if (userp)
1374         cm_ReleaseUser(userp);
1375 }
1376
1377 void smb_HoldUIDNoLock(smb_user_t *uidp)
1378 {
1379     lock_AssertWrite(&smb_rctLock);
1380     uidp->refCount++;
1381 }
1382
1383 void smb_ReleaseUID(smb_user_t *uidp)
1384 {
1385     smb_user_t *up;
1386     smb_user_t **lupp;
1387     smb_username_t *unp = NULL;
1388
1389     lock_ObtainWrite(&smb_rctLock);
1390     osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1391     if (uidp->refCount == 0) {
1392         lupp = &uidp->vcp->usersp;
1393         for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1394             if (up == uidp)
1395                 break;
1396         }
1397         osi_assertx(up != NULL, "null smb_user_t");
1398         *lupp = up->nextp;
1399         lock_FinalizeMutex(&uidp->mx);
1400         unp = uidp->unp;
1401         smb_ReleaseVCNoLock(uidp->vcp);
1402         uidp->vcp = NULL;
1403         free(uidp);
1404     }
1405     lock_ReleaseWrite(&smb_rctLock);
1406
1407     if (unp) {
1408         if (unp->userp)
1409             cm_ReleaseUserVCRef(unp->userp);
1410         smb_ReleaseUsername(unp);
1411     }
1412 }
1413
1414 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1415 {
1416     cm_user_t *up = NULL;
1417
1418     if (!uidp)
1419         return NULL;
1420
1421     lock_ObtainMutex(&uidp->mx);
1422     if (uidp->unp) {
1423         up = uidp->unp->userp;
1424         cm_HoldUser(up);
1425     }
1426     lock_ReleaseMutex(&uidp->mx);
1427
1428     return up;
1429 }
1430
1431
1432 /* retrieve a held reference to a user structure corresponding to an incoming
1433  * request.
1434  * corresponding release function is cm_ReleaseUser.
1435  */
1436 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1437 {
1438     smb_user_t *uidp;
1439     cm_user_t *up = NULL;
1440     smb_t *smbp;
1441
1442     smbp = (smb_t *) inp;
1443     uidp = smb_FindUID(vcp, smbp->uid, 0);
1444     if (!uidp)
1445         return NULL;
1446
1447     up = smb_GetUserFromUID(uidp);
1448
1449     smb_ReleaseUID(uidp);
1450     return up;
1451 }
1452
1453 /*
1454  * Return a pointer to a pathname extracted from a TID structure.  The
1455  * TID structure is not held; assume it won't go away.
1456  */
1457 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1458 {
1459     smb_tid_t *tidp;
1460     long code = 0;
1461
1462     tidp = smb_FindTID(vcp, tid, 0);
1463     if (!tidp) {
1464         *treepath = NULL;
1465     } else {
1466         if (tidp->flags & SMB_TIDFLAG_IPC) {
1467             code = CM_ERROR_TIDIPC;
1468             /* tidp->pathname would be NULL, but that's fine */
1469         }
1470         *treepath = tidp->pathname;
1471         smb_ReleaseTID(tidp, FALSE);
1472     }
1473     return code;
1474 }
1475
1476 /* check to see if we have a chained fid, that is, a fid that comes from an
1477  * OpenAndX message that ran earlier in this packet.  In this case, the fid
1478  * field in a read, for example, request, isn't set, since the value is
1479  * supposed to be inherited from the openAndX call.
1480  */
1481 int smb_ChainFID(int fid, smb_packet_t *inp)
1482 {
1483     if (inp->fid == 0 || inp->inCount == 0)
1484         return fid;
1485     else
1486         return inp->fid;
1487 }
1488
1489 /* are we a priv'd user?  What does this mean on NT? */
1490 int smb_SUser(cm_user_t *userp)
1491 {
1492     return 1;
1493 }
1494
1495 /* find a file ID.  If we pass in 0 we select an unused File ID.
1496  * If the SMB_FLAG_CREATE flag is set, we allocate a new
1497  * smb_fid_t data structure if desired File ID cannot be found.
1498  */
1499 #ifdef DEBUG_SMB_REFCOUNT
1500 smb_fid_t *smb_FindFIDDbg(smb_vc_t *vcp, unsigned short fid, int flags, char *file, long line)
1501 #else
1502 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1503 #endif
1504 {
1505     smb_fid_t *fidp;
1506     int newFid = 0;
1507
1508     if (fid == 0) {
1509         if (!(flags & SMB_FLAG_CREATE))
1510             return NULL;
1511         newFid = 1;
1512     }
1513
1514     lock_ObtainWrite(&smb_rctLock);
1515     if (newFid)
1516         fid = vcp->fidCounter;
1517   retry:
1518
1519     for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1520         if (fidp->refCount == 0 && fidp->deleteOk) {
1521             fidp->refCount++;
1522             lock_ReleaseWrite(&smb_rctLock);
1523             smb_ReleaseFID(fidp);
1524             lock_ObtainWrite(&smb_rctLock);
1525             /*
1526              * We dropped the smb_rctLock so the fid value we are using
1527              * may now be used by another thread.  Start over with the
1528              * current vcp->fidCounter.
1529              */
1530             if (newFid)
1531                 fid = vcp->fidCounter;
1532             goto retry;
1533         }
1534         if (fid == fidp->fid) {
1535             if (newFid) {
1536                 osi_Log1(smb_logp, "smb_FindFID New Fid Requested.  fid %d found -- retrying ...", fid);
1537                 fid++;
1538                 if (fid == 0xFFFF) {
1539                     osi_Log1(smb_logp,
1540                              "New FID number wraps on vcp 0x%x", vcp);
1541                     fid = 1;
1542                 }
1543                 goto retry;
1544             }
1545             fidp->refCount++;
1546             break;
1547         }
1548     }
1549
1550     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1551         char eventName[MAX_PATH];
1552         EVENT_HANDLE event;
1553
1554         if (!newFid)
1555             osi_Log1(smb_logp, "smb_FindFID New Fid Not Requested, Fid %d Not Found and CREATE flag set.", fid);
1556         else
1557             osi_Log1(smb_logp, "smb_FindFID New Fid Requested.  Creating fid %d", fid);
1558
1559         sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1560         event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1561         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1562             osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1563             thrd_CloseHandle(event);
1564             fid++;
1565             if (fid == 0xFFFF) {
1566                 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1567                 fid = 1;
1568             }
1569             goto retry;
1570         }
1571
1572         fidp = malloc(sizeof(*fidp));
1573         memset(fidp, 0, sizeof(*fidp));
1574         osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1575         fidp->refCount = 1;
1576         fidp->vcp = vcp;
1577         smb_HoldVCNoLock(vcp);
1578         lock_InitializeMutex(&fidp->mx, "fid_t mutex", LOCK_HIERARCHY_SMB_FID);
1579         fidp->fid = fid;
1580         fidp->curr_chunk = fidp->prev_chunk = -2;
1581         fidp->raw_write_event = event;
1582         if (newFid) {
1583             vcp->fidCounter = fid+1;
1584             if (vcp->fidCounter == 0xFFFF) {
1585                 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1586                          vcp);
1587                 vcp->fidCounter = 1;
1588             }
1589         }
1590     }
1591
1592 #ifdef DEBUG_SMB_REFCOUNT
1593     if (fidp) {
1594         afsi_log("%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1595         osi_Log4(smb_logp,"%s:%d smb_FindFID fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1596     }
1597 #endif
1598     lock_ReleaseWrite(&smb_rctLock);
1599     return fidp;
1600 }
1601
1602
1603 /* Must not be called with scp->rw held because smb_ReleaseFID might be called */
1604 #ifdef DEBUG_SMB_REFCOUNT
1605 smb_fid_t *smb_FindFIDByScacheDbg(smb_vc_t *vcp, cm_scache_t * scp, char *file, long line)
1606 #else
1607 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1608 #endif
1609 {
1610     smb_fid_t *fidp = NULL, *nextp = NULL;
1611
1612     if (!scp)
1613         return NULL;
1614
1615     /*
1616      * If the fidp->scp changes out from under us then
1617      * we must not grab a refCount.  It means the *fidp
1618      * was processed by smb_CloseFID() and the *fidp is
1619      * no longer valid for use.
1620      */
1621     lock_ObtainWrite(&smb_rctLock);
1622         for(fidp = vcp->fidsp, (fidp ? fidp->refCount++ : 0); fidp; fidp = nextp, nextp = NULL) {
1623         nextp = (smb_fid_t *) osi_QNext(&fidp->q);
1624         if (nextp)
1625             nextp->refCount++;
1626
1627         if (scp == fidp->scp) {
1628             lock_ReleaseWrite(&smb_rctLock);
1629             lock_ObtainMutex(&fidp->mx);
1630             lock_ObtainWrite(&smb_rctLock);
1631             if (scp == fidp->scp) {
1632                 lock_ReleaseMutex(&fidp->mx);
1633                 break;
1634             }
1635             lock_ReleaseMutex(&fidp->mx);
1636         }
1637
1638         if (fidp->refCount > 1) {
1639             fidp->refCount--;
1640         } else {
1641             lock_ReleaseWrite(&smb_rctLock);
1642             smb_ReleaseFID(fidp);
1643             lock_ObtainWrite(&smb_rctLock);
1644         }
1645     }
1646
1647     if (nextp) {
1648         if (nextp->refCount > 1) {
1649             nextp->refCount--;
1650         } else {
1651             lock_ReleaseWrite(&smb_rctLock);
1652             smb_ReleaseFID(nextp);
1653             lock_ObtainWrite(&smb_rctLock);
1654         }
1655     }
1656
1657 #ifdef DEBUG_SMB_REFCOUNT
1658     if (fidp) {
1659         afsi_log("%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1660         osi_Log4(smb_logp,"%s:%d smb_FindFIDByScache fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1661       }
1662 #endif
1663     lock_ReleaseWrite(&smb_rctLock);
1664     return (fidp);
1665 }
1666
1667 #ifdef DEBUG_SMB_REFCOUNT
1668 void smb_HoldFIDNoLockDbg(smb_fid_t *fidp, char *file, long line)
1669 #else
1670 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1671 #endif
1672 {
1673     lock_AssertWrite(&smb_rctLock);
1674     fidp->refCount++;
1675 #ifdef DEBUG_SMB_REFCOUNT
1676     afsi_log("%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1677     osi_Log4(smb_logp,"%s:%d smb_HoldFIDNoLock fidp 0x%p ref %d", file, line, fidp, fidp->refCount);
1678 #endif
1679 }
1680
1681
1682 /* smb_ReleaseFID cannot be called while a cm_scache_t rwlock is held */
1683 /* the smb_fid_t->mx and smb_rctLock must not be held */
1684 #ifdef DEBUG_SMB_REFCOUNT
1685 void smb_ReleaseFIDDbg(smb_fid_t *fidp, char *file, long line)
1686 #else
1687 void smb_ReleaseFID(smb_fid_t *fidp)
1688 #endif
1689 {
1690     cm_scache_t *scp = NULL;
1691     cm_user_t *userp = NULL;
1692     smb_vc_t *vcp = NULL;
1693     smb_ioctl_t *ioctlp;
1694
1695     lock_ObtainMutex(&fidp->mx);
1696     lock_ObtainWrite(&smb_rctLock);
1697     osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1698 #ifdef DEBUG_SMB_REFCOUNT
1699     afsi_log("%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1700     osi_Log5(smb_logp,"%s:%d smb_ReleaseFID fidp 0x%p ref %d deleteOk %d", file, line, fidp, fidp->refCount, fidp->deleteOk);
1701 #endif
1702     if (fidp->refCount == 0) {
1703         if (fidp->deleteOk) {
1704             vcp = fidp->vcp;
1705             fidp->vcp = NULL;
1706             scp = fidp->scp;    /* release after lock is released */
1707             if (scp) {
1708                 lock_ObtainWrite(&scp->rw);
1709                 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1710                 lock_ReleaseWrite(&scp->rw);
1711                 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1712                 fidp->scp = NULL;
1713             }
1714             userp = fidp->userp;
1715             fidp->userp = NULL;
1716
1717             if (vcp->fidsp)
1718                 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1719             thrd_CloseHandle(fidp->raw_write_event);
1720
1721             /* and see if there is ioctl stuff to free */
1722             ioctlp = fidp->ioctlp;
1723             if (ioctlp) {
1724                 if (ioctlp->prefix)
1725                 cm_FreeSpace(ioctlp->prefix);
1726                 if (ioctlp->ioctl.inAllocp)
1727                     free(ioctlp->ioctl.inAllocp);
1728                 if (ioctlp->ioctl.outAllocp)
1729                     free(ioctlp->ioctl.outAllocp);
1730                 free(ioctlp);
1731             }
1732
1733             smb_CleanupRPCFid(fidp);
1734
1735             lock_ReleaseMutex(&fidp->mx);
1736             lock_FinalizeMutex(&fidp->mx);
1737             free(fidp);
1738             fidp = NULL;
1739
1740             if (vcp)
1741                 smb_ReleaseVCNoLock(vcp);
1742         }
1743     }
1744     if (fidp)
1745         lock_ReleaseMutex(&fidp->mx);
1746
1747     lock_ReleaseWrite(&smb_rctLock);
1748
1749     /* now release the scache structure */
1750     if (scp)
1751         cm_ReleaseSCache(scp);
1752
1753     if (userp)
1754         cm_ReleaseUser(userp);
1755 }
1756
1757 /*
1758  * Case-insensitive search for one string in another;
1759  * used to find variable names in submount pathnames.
1760  */
1761 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1762 {
1763     clientchar_t *cursor;
1764
1765     for (cursor = str1; *cursor; cursor++)
1766         if (cm_ClientStrCmpI(cursor, str2) == 0)
1767             return cursor;
1768
1769     return NULL;
1770 }
1771
1772 /*
1773  * Substitute a variable value for its name in a submount pathname.  Variable
1774  * name has been identified by smb_stristr() and is in substr.  Variable name
1775  * length (plus one) is in substr_size.  Variable value is in newstr.
1776  */
1777 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1778                       unsigned int substr_size, clientchar_t *newstr)
1779 {
1780     clientchar_t temp[1024];
1781
1782     cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1783     cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1784     cm_ClientStrCat(str1, cchstr1, temp);
1785 }
1786
1787 clientchar_t VNUserName[] = _C("%USERNAME%");
1788 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1789 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1790 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1791
1792 typedef struct smb_findShare_rock {
1793     clientchar_t * shareName;
1794     clientchar_t * match;
1795     int matchType;
1796 } smb_findShare_rock_t;
1797
1798 #define SMB_FINDSHARE_EXACT_MATCH 1
1799 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1800
1801 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1802                        osi_hyper_t *offp)
1803 {
1804     int matchType = 0;
1805     smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1806     normchar_t normName[MAX_PATH];
1807
1808     if (cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0])) == 0) {
1809         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
1810                  osi_LogSaveString(smb_logp, dep->name));
1811         return 0;
1812     }
1813
1814     if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1815         if(!cm_ClientStrCmpI(normName, vrock->shareName))
1816             matchType = SMB_FINDSHARE_EXACT_MATCH;
1817         else
1818             matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1819         if(vrock->match)
1820             free(vrock->match);
1821         vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1822         vrock->matchType = matchType;
1823
1824         if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1825             return CM_ERROR_STOPNOW;
1826     }
1827     return 0;
1828 }
1829
1830
1831 /* find a shareName in the table of submounts */
1832 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1833                   clientchar_t *shareName,
1834                   clientchar_t **pathNamep)
1835 {
1836     DWORD cblen;
1837     DWORD cchlen;
1838     clientchar_t pathName[1024];
1839     clientchar_t *var;
1840     DWORD sizeTemp;
1841     clientchar_t *p, *q;
1842     fschar_t *cellname = NULL;
1843     HKEY parmKey;
1844     DWORD code;
1845     DWORD allSubmount = 1;
1846
1847     /* if allSubmounts == 0, only return the //mountRoot/all share
1848      * if in fact it has been been created in the subMounts table.
1849      * This is to allow sites that want to restrict access to the
1850      * world to do so.
1851      */
1852     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1853                         0, KEY_QUERY_VALUE, &parmKey);
1854     if (code == ERROR_SUCCESS) {
1855         cblen = sizeof(allSubmount);
1856         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1857                                (BYTE *) &allSubmount, &cblen);
1858         if (code != ERROR_SUCCESS) {
1859             allSubmount = 1;
1860         }
1861         RegCloseKey (parmKey);
1862     }
1863
1864     if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1865         *pathNamep = NULL;
1866         return 1;
1867     }
1868
1869     /* In case, the all share is disabled we need to still be able
1870      * to handle ioctl requests
1871      */
1872     if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1873         *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1874         return 1;
1875     }
1876
1877     if (MSRPC_IsWellKnownService(shareName) ||
1878         cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1879         cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1880         ) {
1881         *pathNamep = NULL;
1882         return 0;
1883     }
1884
1885     /* Check for volume references
1886      *
1887      * They look like <cell>{%,#}<volume>
1888      */
1889     if (cm_ClientStrChr(shareName, '%') != NULL ||
1890         cm_ClientStrChr(shareName, '#') != NULL) {
1891         clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1892         /* make room for '/@vol:' + mountchar + NULL terminator*/
1893
1894         osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1895                  osi_LogSaveClientString(smb_logp, shareName));
1896
1897         cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1898                             _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1899         cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1900
1901         *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1902         if (*pathNamep) {
1903             cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1904             cm_ClientStrLwr(*pathNamep);
1905             osi_Log1(smb_logp, "   returning pathname [%S]",
1906                      osi_LogSaveClientString(smb_logp, *pathNamep));
1907
1908             return 1;
1909         } else {
1910             return 0;
1911         }
1912     }
1913
1914     code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1915                         0, KEY_QUERY_VALUE, &parmKey);
1916     if (code == ERROR_SUCCESS) {
1917         cblen = sizeof(pathName);
1918         code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1919                                 (BYTE *) pathName, &cblen);
1920         if (code != ERROR_SUCCESS)
1921             cblen = 0;
1922         RegCloseKey (parmKey);
1923     } else {
1924         cblen = 0;
1925     }
1926     cchlen = cblen / sizeof(clientchar_t);
1927     if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1928         /* We can accept either unix or PC style AFS pathnames.  Convert
1929          * Unix-style to PC style here for internal use.
1930          */
1931         p = pathName;
1932         cchlen = lengthof(pathName);
1933
1934         /* within this code block, we maintain, cchlen = writable
1935            buffer length of p */
1936
1937         if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1938             p += cm_mountRootCLen;  /* skip mount path */
1939             cchlen -= (DWORD)(p - pathName);
1940         }
1941
1942         q = p;
1943         while (*q) {
1944             if (*q == _C('/')) *q = _C('\\');    /* change to \ */
1945             q++;
1946         }
1947
1948         while (1)
1949         {
1950             clientchar_t temp[1024];
1951
1952             if (var = smb_stristr(p, VNUserName)) {
1953                 if (uidp && uidp->unp)
1954                     smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1955                 else
1956                     smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1957             }
1958             else if (var = smb_stristr(p, VNLCUserName))
1959             {
1960                 if (uidp && uidp->unp)
1961                     cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1962                 else
1963                     cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1964                 cm_ClientStrLwr(temp);
1965                 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1966             }
1967             else if (var = smb_stristr(p, VNComputerName))
1968             {
1969                 sizeTemp = lengthof(temp);
1970                 GetComputerNameW(temp, &sizeTemp);
1971                 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1972             }
1973             else if (var = smb_stristr(p, VNLCComputerName))
1974             {
1975                 sizeTemp = lengthof(temp);
1976                 GetComputerName((LPTSTR)temp, &sizeTemp);
1977                 cm_ClientStrLwr(temp);
1978                 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1979             }
1980             else
1981                 break;
1982         }
1983         *pathNamep = cm_ClientStrDup(p);
1984         return 1;
1985     }
1986     else
1987     {
1988         /* First lookup shareName in root.afs */
1989         cm_req_t req;
1990         smb_findShare_rock_t vrock;
1991         osi_hyper_t thyper;
1992         fschar_t ftemp[1024];
1993         clientchar_t * p = shareName;
1994         int rw = 0;
1995         cm_scache_t * rscp;
1996         cm_user_t *userp;
1997
1998         /*  attempt to locate a partial match in root.afs.  This is because
1999             when using the ANSI RAP calls, the share name is limited to 13 chars
2000             and hence is truncated. Of course we prefer exact matches. */
2001         smb_InitReq(&req);
2002         thyper.HighPart = 0;
2003         thyper.LowPart = 0;
2004
2005         vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
2006         if (vrock.shareName == NULL)
2007             return 0;
2008         vrock.match = NULL;
2009         vrock.matchType = 0;
2010
2011         userp = (uidp? (uidp->unp ? uidp->unp->userp : cm_rootUserp) : cm_rootUserp);
2012         rscp = cm_RootSCachep(userp, &req);
2013         cm_HoldSCache(rscp);
2014         code = cm_ApplyDir(rscp, smb_FindShareProc, &vrock, &thyper,
2015                            userp, &req, NULL);
2016         cm_ReleaseSCache(rscp);
2017
2018         free(vrock.shareName);
2019         vrock.shareName = NULL;
2020
2021         if (vrock.matchType) {
2022             cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
2023             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2024             free(vrock.match);
2025             return 1;
2026         }
2027
2028         /* if we get here, there was no match for the share in root.afs */
2029         /* so try to create  \\<netbiosName>\<cellname>  */
2030         if ( *p == '.' ) {
2031             p++;
2032             rw = 1;
2033         }
2034         /* Get the full name for this cell */
2035         cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
2036         code = cm_SearchCellRegistry(1, cellname, ftemp, 0, 0, 0);
2037         if (code && code != CM_ERROR_FORCE_DNS_LOOKUP)
2038             code = cm_SearchCellFile(cellname, ftemp, 0, 0);
2039         if (code && cm_dnsEnabled) {
2040             int ttl;
2041             code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
2042         }
2043         if (cellname)
2044             free(cellname);
2045
2046         /* construct the path */
2047         if (code == 0) {
2048             clientchar_t temp[1024];
2049
2050             if (cm_FsStringToClientString(ftemp, -1, temp, 1024) != 0) {
2051             cm_ClientStrPrintfN(pathName, (int)lengthof(pathName),
2052                                 rw ? _C("/.%S/") : _C("/%S/"), temp);
2053             *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
2054             return 1;
2055         }
2056     }
2057     }
2058     /* failure */
2059     *pathNamep = NULL;
2060     return 0;
2061 }
2062
2063 /* Client-side offline caching policy types */
2064 #define CSC_POLICY_MANUAL 0
2065 #define CSC_POLICY_DOCUMENTS 1
2066 #define CSC_POLICY_PROGRAMS 2
2067 #define CSC_POLICY_DISABLE 3
2068
2069 int smb_FindShareCSCPolicy(clientchar_t *shareName)
2070 {
2071     DWORD len;
2072     clientchar_t policy[1024];
2073     DWORD dwType;
2074     HKEY hkCSCPolicy;
2075     int  retval = CSC_POLICY_MANUAL;
2076
2077     if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
2078                         AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
2079                         0,
2080                         "AFS",
2081                         REG_OPTION_NON_VOLATILE,
2082                         KEY_READ,
2083                         NULL,
2084                         &hkCSCPolicy,
2085                         NULL ) != ERROR_SUCCESS)
2086         retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2087
2088     len = sizeof(policy);
2089     if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
2090          len == 0) {
2091         retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
2092     }
2093     else if (cm_ClientStrCmpIA(policy, _C("manual")) == 0)
2094     {
2095         retval = CSC_POLICY_MANUAL;
2096     }
2097     else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
2098     {
2099         retval = CSC_POLICY_DOCUMENTS;
2100     }
2101     else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
2102     {
2103         retval = CSC_POLICY_PROGRAMS;
2104     }
2105     else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
2106     {
2107         retval = CSC_POLICY_DISABLE;
2108     }
2109
2110     RegCloseKey(hkCSCPolicy);
2111     return retval;
2112 }
2113
2114 /* find a dir search structure by cookie value, and return it held.
2115  * Must be called with smb_globalLock held.
2116  */
2117 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
2118 {
2119     smb_dirSearch_t *dsp;
2120
2121     for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2122         if (dsp->cookie == cookie) {
2123             if (dsp != smb_firstDirSearchp) {
2124                 /* move to head of LRU queue, too, if we're not already there */
2125                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
2126                     smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2127                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2128                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2129                 if (!smb_lastDirSearchp)
2130                     smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2131             }
2132             dsp->refCount++;
2133             break;
2134         }
2135     }
2136
2137     if (dsp == NULL) {
2138         osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
2139         for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
2140             osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
2141         }
2142     }
2143     return dsp;
2144 }
2145
2146 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
2147 {
2148     lock_ObtainMutex(&dsp->mx);
2149     osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
2150               dsp->cookie, dsp, dsp->scp);
2151     dsp->flags |= SMB_DIRSEARCH_DELETE;
2152     if (dsp->scp != NULL) {
2153         lock_ObtainWrite(&dsp->scp->rw);
2154         if (dsp->flags & SMB_DIRSEARCH_BULKST) {
2155             dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2156             dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2157             dsp->scp->bulkStatProgress = hzero;
2158         }
2159         lock_ReleaseWrite(&dsp->scp->rw);
2160     }
2161     lock_ReleaseMutex(&dsp->mx);
2162 }
2163
2164 /* Must be called with the smb_globalLock held */
2165 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
2166 {
2167     cm_scache_t *scp = NULL;
2168
2169     osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
2170     if (dsp->refCount == 0) {
2171         lock_ObtainMutex(&dsp->mx);
2172         if (dsp->flags & SMB_DIRSEARCH_DELETE) {
2173             if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
2174                 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
2175             osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2176             lock_ReleaseMutex(&dsp->mx);
2177             lock_FinalizeMutex(&dsp->mx);
2178             scp = dsp->scp;
2179             osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
2180                      dsp->cookie, dsp, scp);
2181             free(dsp);
2182         } else {
2183             lock_ReleaseMutex(&dsp->mx);
2184         }
2185     }
2186     /* do this now to avoid spurious locking hierarchy creation */
2187     if (scp)
2188         cm_ReleaseSCache(scp);
2189 }
2190
2191 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
2192 {
2193     lock_ObtainWrite(&smb_globalLock);
2194     smb_ReleaseDirSearchNoLock(dsp);
2195     lock_ReleaseWrite(&smb_globalLock);
2196 }
2197
2198 /* find a dir search structure by cookie value, and return it held */
2199 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2200 {
2201     smb_dirSearch_t *dsp;
2202
2203     lock_ObtainWrite(&smb_globalLock);
2204     dsp = smb_FindDirSearchNoLock(cookie);
2205     lock_ReleaseWrite(&smb_globalLock);
2206     return dsp;
2207 }
2208
2209 /* GC some dir search entries, in the address space expected by the specific protocol.
2210  * Must be called with smb_globalLock held; release the lock temporarily.
2211  */
2212 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
2213 void smb_GCDirSearches(int isV3)
2214 {
2215     smb_dirSearch_t *prevp;
2216     smb_dirSearch_t *dsp;
2217     smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2218     int victimCount;
2219     int i;
2220
2221     victimCount = 0;    /* how many have we got so far */
2222     for (dsp = smb_lastDirSearchp; dsp; dsp=prevp) {
2223         /* we'll move tp from queue, so
2224          * do this early.
2225          */
2226         prevp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
2227         /* if no one is using this guy, and we're either in the new protocol,
2228          * or we're in the old one and this is a small enough ID to be useful
2229          * to the old protocol, GC this guy.
2230          */
2231         if (dsp->refCount == 0 && (isV3 || dsp->cookie <= 255)) {
2232             /* hold and delete */
2233             lock_ObtainMutex(&dsp->mx);
2234             dsp->flags |= SMB_DIRSEARCH_DELETE;
2235             lock_ReleaseMutex(&dsp->mx);
2236             victimsp[victimCount++] = dsp;
2237             dsp->refCount++;
2238         }
2239
2240         /* don't do more than this */
2241         if (victimCount >= SMB_DIRSEARCH_GCMAX)
2242             break;
2243     }
2244
2245     /* now release them */
2246     for (i = 0; i < victimCount; i++) {
2247         smb_ReleaseDirSearchNoLock(victimsp[i]);
2248     }
2249 }
2250
2251 /* function for allocating a dir search entry.  We need these to remember enough context
2252  * since we don't get passed the path from call to call during a directory search.
2253  *
2254  * Returns a held dir search structure, and bumps the reference count on the vnode,
2255  * since it saves a pointer to the vnode.
2256  */
2257 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2258 {
2259     smb_dirSearch_t *dsp;
2260     int counter;
2261     int maxAllowed;
2262     int start;
2263     int wrapped = 0;
2264
2265     lock_ObtainWrite(&smb_globalLock);
2266     counter = 0;
2267
2268     /* what's the biggest ID allowed in this version of the protocol */
2269     /* TODO: do we really want a non v3 dir search request to wrap
2270        smb_dirSearchCounter? */
2271     maxAllowed = isV3 ? 65535 : 255;
2272     if (smb_dirSearchCounter > maxAllowed)
2273         smb_dirSearchCounter = 1;
2274
2275     start = smb_dirSearchCounter;
2276
2277     while (1) {
2278         /* twice so we have enough tries to find guys we GC after one pass;
2279          * 10 extra is just in case I mis-counted.
2280          */
2281         if (++counter > 2*maxAllowed+10)
2282             osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2283
2284         if (smb_dirSearchCounter > maxAllowed) {
2285             smb_dirSearchCounter = 1;
2286         }
2287         if (smb_dirSearchCounter == start) {
2288             if (wrapped)
2289                 smb_GCDirSearches(isV3);
2290             wrapped++;
2291         }
2292         dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2293         if (dsp) {
2294             /* don't need to watch for refcount zero and deleted, since
2295             * we haven't dropped the global lock.
2296             */
2297             dsp->refCount--;
2298             ++smb_dirSearchCounter;
2299             continue;
2300         }
2301
2302         dsp = malloc(sizeof(*dsp));
2303         memset(dsp, 0, sizeof(*dsp));
2304         dsp->cookie = smb_dirSearchCounter;
2305         ++smb_dirSearchCounter;
2306         dsp->refCount = 1;
2307         lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t", LOCK_HIERARCHY_SMB_DIRSEARCH);
2308         dsp->lastTime = osi_Time();
2309         osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2310         if (!smb_lastDirSearchp)
2311             smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2312
2313         osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2314                  dsp->cookie, dsp);
2315         break;
2316     }
2317     lock_ReleaseWrite(&smb_globalLock);
2318     return dsp;
2319 }
2320
2321 static smb_packet_t *smb_GetPacket(void)
2322 {
2323     smb_packet_t *tbp;
2324
2325     lock_ObtainWrite(&smb_globalLock);
2326     tbp = smb_packetFreeListp;
2327     if (tbp)
2328         smb_packetFreeListp = tbp->nextp;
2329     lock_ReleaseWrite(&smb_globalLock);
2330     if (!tbp) {
2331         tbp = calloc(sizeof(*tbp),1);
2332         tbp->magic = SMB_PACKETMAGIC;
2333         tbp->ncbp = NULL;
2334         tbp->vcp = NULL;
2335         tbp->resumeCode = 0;
2336         tbp->inCount = 0;
2337         tbp->fid = 0;
2338         tbp->wctp = NULL;
2339         tbp->inCom = 0;
2340         tbp->oddByte = 0;
2341         tbp->ncb_length = 0;
2342         tbp->flags = 0;
2343         tbp->spacep = NULL;
2344         tbp->stringsp = NULL;
2345     }
2346     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2347
2348     return tbp;
2349 }
2350
2351 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2352 {
2353     smb_packet_t *tbp;
2354     tbp = smb_GetPacket();
2355     memcpy(tbp, pkt, sizeof(smb_packet_t));
2356     tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2357     tbp->stringsp = NULL;
2358     if (tbp->vcp)
2359         smb_HoldVC(tbp->vcp);
2360     return tbp;
2361 }
2362
2363 static NCB *smb_GetNCB(void)
2364 {
2365     smb_ncb_t *tbp;
2366     NCB *ncbp;
2367
2368     lock_ObtainWrite(&smb_globalLock);
2369     tbp = smb_ncbFreeListp;
2370     if (tbp)
2371         smb_ncbFreeListp = tbp->nextp;
2372     lock_ReleaseWrite(&smb_globalLock);
2373     if (!tbp) {
2374         tbp = calloc(sizeof(*tbp),1);
2375         tbp->magic = SMB_NCBMAGIC;
2376     }
2377
2378     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2379
2380     memset(&tbp->ncb, 0, sizeof(NCB));
2381     ncbp = &tbp->ncb;
2382     return ncbp;
2383 }
2384
2385 static void FreeSMBStrings(smb_packet_t * pkt)
2386 {
2387     cm_space_t * s;
2388     cm_space_t * ns;
2389
2390     for (s = pkt->stringsp; s; s = ns) {
2391         ns = s->nextp;
2392         cm_FreeSpace(s);
2393     }
2394     pkt->stringsp = NULL;
2395 }
2396
2397 void smb_FreePacket(smb_packet_t *tbp)
2398 {
2399     smb_vc_t * vcp = NULL;
2400     osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2401
2402     lock_ObtainWrite(&smb_globalLock);
2403     tbp->nextp = smb_packetFreeListp;
2404     smb_packetFreeListp = tbp;
2405     tbp->magic = SMB_PACKETMAGIC;
2406     tbp->ncbp = NULL;
2407     vcp = tbp->vcp;
2408     tbp->vcp = NULL;
2409     tbp->resumeCode = 0;
2410     tbp->inCount = 0;
2411     tbp->fid = 0;
2412     tbp->wctp = NULL;
2413     tbp->inCom = 0;
2414     tbp->oddByte = 0;
2415     tbp->ncb_length = 0;
2416     tbp->flags = 0;
2417     FreeSMBStrings(tbp);
2418     lock_ReleaseWrite(&smb_globalLock);
2419
2420     if (vcp)
2421         smb_ReleaseVC(vcp);
2422 }
2423
2424 static void smb_FreeNCB(NCB *bufferp)
2425 {
2426     smb_ncb_t *tbp;
2427
2428     tbp = (smb_ncb_t *) bufferp;
2429     osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2430
2431     lock_ObtainWrite(&smb_globalLock);
2432     tbp->nextp = smb_ncbFreeListp;
2433     smb_ncbFreeListp = tbp;
2434     lock_ReleaseWrite(&smb_globalLock);
2435 }
2436
2437 /* get a ptr to the data part of a packet, and its count */
2438 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2439 {
2440     int parmBytes;
2441     int dataBytes;
2442     unsigned char *afterParmsp;
2443
2444     parmBytes = *smbp->wctp << 1;
2445     afterParmsp = smbp->wctp + parmBytes + 1;
2446
2447     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2448     if (nbytesp) *nbytesp = dataBytes;
2449
2450     /* don't forget to skip the data byte count, since it follows
2451      * the parameters; that's where the "2" comes from below.
2452      */
2453     return (unsigned char *) (afterParmsp + 2);
2454 }
2455
2456 /* must set all the returned parameters before playing around with the
2457  * data region, since the data region is located past the end of the
2458  * variable number of parameters.
2459  */
2460 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2461 {
2462     unsigned char *afterParmsp;
2463
2464     afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2465
2466     *afterParmsp++ = dsize & 0xff;
2467     *afterParmsp = (dsize>>8) & 0xff;
2468 }
2469
2470 /* return the parm'th parameter in the smbp packet */
2471 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2472 {
2473     int parmCount;
2474     unsigned char *parmDatap;
2475
2476     parmCount = *smbp->wctp;
2477
2478     if (parm >= parmCount) {
2479         char s[100];
2480
2481         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2482                 parm, parmCount, smbp->ncb_length);
2483         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2484                  parm, parmCount, smbp->ncb_length);
2485         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2486                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2487         osi_panic(s, __FILE__, __LINE__);
2488     }
2489     parmDatap = smbp->wctp + (2*parm) + 1;
2490
2491     return parmDatap[0] + (parmDatap[1] << 8);
2492 }
2493
2494 /* return the parm'th parameter in the smbp packet */
2495 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2496 {
2497     int parmCount;
2498     unsigned char *parmDatap;
2499
2500     parmCount = *smbp->wctp;
2501
2502     if (parm >= parmCount) {
2503         char s[100];
2504
2505         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2506                 parm, parmCount, smbp->ncb_length);
2507         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2508                  parm, parmCount, smbp->ncb_length);
2509         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2510                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2511         osi_panic(s, __FILE__, __LINE__);
2512     }
2513     parmDatap = smbp->wctp + (2*parm) + 1;
2514
2515     return parmDatap[0];
2516 }
2517
2518 /* return the parm'th parameter in the smbp packet */
2519 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2520 {
2521     int parmCount;
2522     unsigned char *parmDatap;
2523
2524     parmCount = *smbp->wctp;
2525
2526     if (parm + 1 >= parmCount) {
2527         char s[100];
2528
2529         sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2530                 parm, parmCount, smbp->ncb_length);
2531         osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2532                  parm, parmCount, smbp->ncb_length);
2533         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2534                  __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2535         osi_panic(s, __FILE__, __LINE__);
2536     }
2537     parmDatap = smbp->wctp + (2*parm) + 1;
2538
2539     return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2540 }
2541
2542 /* return the parm'th parameter in the smbp packet */
2543 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2544 {
2545     int parmCount;
2546     unsigned char *parmDatap;
2547
2548     parmCount = *smbp->wctp;
2549
2550     if (parm * 2 + offset >= parmCount * 2) {
2551         char s[100];
2552
2553         sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2554                 parm, offset, parmCount, smbp->ncb_length);
2555         LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2556                  __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2557         osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2558                 parm, offset, parmCount, smbp->ncb_length);
2559         osi_panic(s, __FILE__, __LINE__);
2560     }
2561     parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2562
2563     return parmDatap[0] + (parmDatap[1] << 8);
2564 }
2565
2566 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2567 {
2568     unsigned char *parmDatap;
2569
2570     /* make sure we have enough slots */
2571     if (*smbp->wctp <= slot)
2572         *smbp->wctp = slot+1;
2573
2574     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2575     *parmDatap++ = parmValue & 0xff;
2576     *parmDatap = (parmValue>>8) & 0xff;
2577 }
2578
2579 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2580 {
2581     unsigned char *parmDatap;
2582
2583     /* make sure we have enough slots */
2584     if (*smbp->wctp <= slot)
2585         *smbp->wctp = slot+2;
2586
2587     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2588     *parmDatap++ = parmValue & 0xff;
2589     *parmDatap++ = (parmValue>>8) & 0xff;
2590     *parmDatap++ = (parmValue>>16) & 0xff;
2591     *parmDatap   = (parmValue>>24) & 0xff;
2592 }
2593
2594 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2595 {
2596     unsigned char *parmDatap;
2597     int i;
2598
2599     /* make sure we have enough slots */
2600     if (*smbp->wctp <= slot)
2601         *smbp->wctp = slot+4;
2602
2603     parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2604     for (i=0; i<8; i++)
2605         *parmDatap++ = *parmValuep++;
2606 }
2607
2608 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2609 {
2610     unsigned char *parmDatap;
2611
2612     /* make sure we have enough slots */
2613     if (*smbp->wctp <= slot) {
2614         if (smbp->oddByte) {
2615             smbp->oddByte = 0;
2616             *smbp->wctp = slot+1;
2617         } else
2618             smbp->oddByte = 1;
2619     }
2620
2621     parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2622     *parmDatap++ = parmValue & 0xff;
2623 }
2624
2625
2626
2627 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2628                             clientchar_t *inPathp)
2629 {
2630     clientchar_t *lastSlashp;
2631     clientchar_t *streamp = NULL;
2632     clientchar_t *typep = NULL;
2633
2634     lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2635     if (lastComponentp) {
2636         *lastComponentp = lastSlashp;
2637     }
2638     if (lastSlashp) {
2639         /*
2640          * If the name contains a stream name and a type
2641          * and the stream name is the nul-string and the
2642          * type is $DATA, then strip "::$DATA" from the
2643          * last component string that is returned.
2644          *
2645          * Otherwise, return the full path name and allow
2646          * the file name to be rejected because it contains
2647          * a colon.
2648          */
2649         typep = cm_ClientStrRChr(lastSlashp, L':');
2650         if (typep && cm_ClientStrCmpI(typep, L":$DATA") == 0) {
2651             *typep = '\0';
2652             streamp = cm_ClientStrRChr(lastSlashp, L':');
2653             if (streamp && cm_ClientStrCmpI(streamp, L":") == 0) {
2654                 *streamp = '\0';
2655             } else
2656                 *typep = ':';
2657             osi_Log2(smb_logp, "smb_StripLastComponent found stream [%S] type [%S]",
2658                      osi_LogSaveClientString(smb_logp,streamp),
2659                      osi_LogSaveClientString(smb_logp,typep));
2660         }
2661
2662         while (1) {
2663             if (inPathp == lastSlashp)
2664                 break;
2665             *outPathp++ = *inPathp++;
2666         }
2667         *outPathp++ = 0;
2668     }
2669     else {
2670         *outPathp++ = 0;
2671     }
2672 }
2673
2674 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2675                                   char **chainpp, int flags)
2676 {
2677     size_t cb;
2678     afs_uint32 type = *inp++;
2679
2680     /*
2681      * The first byte specifies the type of the input string.
2682      * CIFS TR 1.0 3.2.10.  This function only parses null terminated
2683      * strings.
2684      */
2685     switch (type) {
2686     /* Length Counted */
2687     case 0x1: /* Data Block */
2688     case 0x5: /* Variable Block */
2689         cb = *inp++ << 16 | *inp++;
2690         break;
2691
2692     /* Null-terminated string */
2693     case 0x4: /* ASCII */
2694     case 0x3: /* Pathname */
2695     case 0x2: /* Dialect */
2696         cb = sizeof(pktp->data) - (inp - pktp->data);
2697         if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2698 #ifdef DEBUG_UNICODE
2699             DebugBreak();
2700 #endif
2701             cb = sizeof(pktp->data);
2702         }
2703         break;
2704
2705     default:
2706         return NULL;            /* invalid input */
2707     }
2708
2709 #ifdef SMB_UNICODE
2710     if (type == 0x2 /* Dialect */ || !WANTS_UNICODE(pktp))
2711         flags |= SMB_STRF_FORCEASCII;
2712 #endif
2713
2714     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2715 }
2716
2717 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2718                               char ** chainpp, int flags)
2719 {
2720     size_t cb;
2721
2722 #ifdef SMB_UNICODE
2723     if (!WANTS_UNICODE(pktp))
2724         flags |= SMB_STRF_FORCEASCII;
2725 #endif
2726
2727     cb = sizeof(pktp->data) - (inp - pktp->data);
2728     if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2729 #ifdef DEBUG_UNICODE
2730         DebugBreak();
2731 #endif
2732         cb = sizeof(pktp->data);
2733     }
2734     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp,
2735                               flags | SMB_STRF_SRCNULTERM);
2736 }
2737
2738 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2739                                 size_t cb, char ** chainpp, int flags)
2740 {
2741 #ifdef SMB_UNICODE
2742     if (!WANTS_UNICODE(pktp))
2743         flags |= SMB_STRF_FORCEASCII;
2744 #endif
2745
2746     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2747 }
2748
2749 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2750                                  size_t cch, char ** chainpp, int flags)
2751 {
2752     size_t cb = cch;
2753
2754 #ifdef SMB_UNICODE
2755     if (!WANTS_UNICODE(pktp))
2756         flags |= SMB_STRF_FORCEASCII;
2757     else
2758         cb = cch * sizeof(wchar_t);
2759 #endif
2760
2761     return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2762 }
2763
2764 clientchar_t *
2765 smb_ParseStringBuf(const unsigned char * bufbase,
2766                    cm_space_t ** stringspp,
2767                    unsigned char *inp, size_t *pcb_max,
2768                    char **chainpp, int flags)
2769 {
2770 #ifdef SMB_UNICODE
2771     if (!(flags & SMB_STRF_FORCEASCII)) {
2772         size_t cch_src;
2773         cm_space_t * spacep;
2774         int    null_terms = 0;
2775
2776         if (bufbase && ((inp - bufbase) % 2) != 0) {
2777             inp++;              /* unicode strings are always word aligned */
2778         }
2779
2780         if (*pcb_max > 0) {
2781             if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2782                                         &cch_src))) {
2783                 cch_src = *pcb_max / sizeof(wchar_t);
2784                 *pcb_max = 0;
2785                 null_terms = 0;
2786             } else {
2787                 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2788                 null_terms = 1;
2789             }
2790         } else {
2791             cch_src = 0;
2792         }
2793
2794         spacep = cm_GetSpace();
2795         spacep->nextp = *stringspp;
2796         *stringspp = spacep;
2797
2798         if (cch_src == 0) {
2799             if (chainpp) {
2800                 *chainpp = inp + sizeof(wchar_t);
2801             }
2802
2803             *(spacep->wdata) = 0;
2804             return spacep->wdata;
2805         }
2806
2807         StringCchCopyNW(spacep->wdata,
2808                         lengthof(spacep->wdata),
2809                         (const clientchar_t *) inp, cch_src);
2810
2811         if (chainpp)
2812             *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2813
2814         return spacep->wdata;
2815
2816     } else {
2817 #endif
2818         cm_space_t * spacep;
2819         int cchdest;
2820
2821         /* Not using Unicode */
2822         if (chainpp) {
2823             *chainpp = inp + strlen(inp) + 1;
2824         }
2825
2826         spacep = cm_GetSpace();
2827         spacep->nextp = *stringspp;
2828         *stringspp = spacep;
2829
2830         cchdest = lengthof(spacep->wdata);
2831         cm_Utf8ToUtf16(inp, (int)((flags & SMB_STRF_SRCNULTERM)? -1 : *pcb_max),
2832                        spacep->wdata, cchdest);
2833
2834         return spacep->wdata;
2835 #ifdef SMB_UNICODE
2836     }
2837 #endif
2838 }
2839
2840 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2841                             clientchar_t * str,
2842                             size_t * plen, int flags)
2843 {
2844     size_t buffersize;
2845     int align = 0;
2846
2847     if (outp == NULL) {
2848         /* we are only calculating the required size */
2849
2850         if (plen == NULL)
2851             return NULL;
2852
2853 #ifdef SMB_UNICODE
2854
2855         if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2856
2857             StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2858             if (!(flags & SMB_STRF_IGNORENUL))
2859                 *plen += sizeof(wchar_t);
2860
2861             return (unsigned char *) 1; /* return TRUE if we are using unicode */
2862         }
2863         else
2864 #endif
2865         {
2866             /* Storing ANSI */
2867
2868             size_t cch_str;
2869             size_t cch_dest;
2870
2871             cch_str = cm_ClientStrLen(str);
2872             cch_dest = cm_ClientStringToUtf8(str, (int)cch_str, NULL, 0);
2873
2874             if (plen)
2875                 *plen = ((flags & SMB_STRF_IGNORENUL)? cch_dest: cch_dest+1);
2876
2877             return NULL;
2878         }
2879
2880         /* Not reached. */
2881     }
2882
2883     /* if outp != NULL ... */
2884
2885     /* Number of bytes left in the buffer.
2886
2887        If outp lies inside the packet data buffer, we assume that the
2888        buffer is the packet data buffer.  Otherwise we assume that the
2889        buffer is sizeof(packet->data).
2890
2891     */
2892     if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2893         align = (int)((outp - pktp->data) % 2);
2894         buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2895     } else {
2896         align = (int)(((size_t) outp) % 2);
2897         buffersize = (int)sizeof(pktp->data);
2898     }
2899
2900 #ifdef SMB_UNICODE
2901
2902     if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2903         int nchars;
2904
2905         if (align)
2906             *outp++ = '\0';
2907
2908         if (*str == _C('\0')) {
2909
2910             if (buffersize < sizeof(wchar_t))
2911                 return NULL;
2912
2913             *((wchar_t *) outp) = L'\0';
2914             if (plen && !(flags & SMB_STRF_IGNORENUL))
2915                 *plen += sizeof(wchar_t);
2916             return outp + sizeof(wchar_t);
2917         }
2918
2919         nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, (int)(buffersize / sizeof(wchar_t)));
2920         if (nchars == 0) {
2921             osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2922                      osi_LogSaveClientString(smb_logp, str),
2923                      GetLastError());
2924             return NULL;
2925         }
2926
2927         if (plen)
2928             *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENUL)? nchars - 1: nchars);
2929
2930         return outp + sizeof(wchar_t) * nchars;
2931     }
2932     else
2933 #endif
2934     {
2935         /* Storing ANSI */
2936         size_t cch_dest;
2937
2938         cch_dest = cm_ClientStringToUtf8(str, -1, outp, (int)buffersize);
2939
2940         if (plen)
2941             *plen += ((flags & SMB_STRF_IGNORENUL)? cch_dest - 1: cch_dest);
2942
2943         return outp + cch_dest;
2944     }
2945 }
2946
2947 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2948 {
2949     int tlen;
2950
2951     if (*inp++ != 0x5)
2952         return NULL;
2953     tlen = inp[0] + (inp[1]<<8);
2954     inp += 2;           /* skip length field */
2955
2956     if (chainpp) {
2957         *chainpp = inp + tlen;
2958     }
2959
2960     if (lengthp)
2961         *lengthp = tlen;
2962
2963     return inp;
2964 }
2965
2966 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2967 {
2968     int tlen;
2969
2970     if (*inp++ != 0x1) return NULL;
2971     tlen = inp[0] + (inp[1]<<8);
2972     inp += 2;           /* skip length field */
2973
2974     if (chainpp) {
2975         *chainpp = inp + tlen;
2976     }
2977
2978     if (lengthp) *lengthp = tlen;
2979
2980     return inp;
2981 }
2982
2983 /* format a packet as a response */
2984 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2985 {
2986     smb_t *outp;
2987     smb_t *inSmbp;
2988
2989     outp = (smb_t *) op;
2990
2991     /* zero the basic structure through the smb_wct field, and zero the data
2992      * size field, assuming that wct stays zero; otherwise, you have to
2993      * explicitly set the data size field, too.
2994      */
2995     inSmbp = (smb_t *) inp;
2996     memset(outp, 0, sizeof(smb_t)+2);
2997     outp->id[0] = 0xff;
2998     outp->id[1] = 'S';
2999     outp->id[2] = 'M';
3000     outp->id[3] = 'B';
3001     if (inp) {
3002         outp->com = inSmbp->com;
3003         outp->tid = inSmbp->tid;
3004         outp->pid = inSmbp->pid;
3005         outp->uid = inSmbp->uid;
3006         outp->mid = inSmbp->mid;
3007         outp->res[0] = inSmbp->res[0];
3008         outp->res[1] = inSmbp->res[1];
3009         op->inCom = inSmbp->com;
3010     }
3011     outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
3012 #ifdef SEND_CANONICAL_PATHNAMES
3013     outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
3014 #endif
3015     outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
3016 #ifdef SMB_UNICODE
3017     if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
3018         outp->flg2 |= SMB_FLAGS2_UNICODE;
3019 #endif
3020
3021     /* copy fields in generic packet area */
3022     op->wctp = &outp->wct;
3023 }
3024
3025 /* send a (probably response) packet; vcp tells us to whom to send it.
3026  * we compute the length by looking at wct and bcc fields.
3027  */
3028 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
3029 {
3030     NCB *ncbp;
3031     int extra;
3032     long code = 0;
3033     unsigned char *tp;
3034     int localNCB = 0;
3035
3036     ncbp = inp->ncbp;
3037     if (ncbp == NULL) {
3038         ncbp = smb_GetNCB();
3039         localNCB = 1;
3040     }
3041
3042     memset(ncbp, 0, sizeof(NCB));
3043
3044     extra = 2 * (*inp->wctp);   /* space used by parms, in bytes */
3045     tp = inp->wctp + 1+ extra;  /* points to count of data bytes */
3046     extra += tp[0] + (tp[1]<<8);
3047     extra += (unsigned int)(inp->wctp - inp->data);     /* distance to last wct field */
3048     extra += 3;                 /* wct and length fields */
3049
3050     ncbp->ncb_length = extra;   /* bytes to send */
3051     ncbp->ncb_lsn = (unsigned char) vcp->lsn;   /* vc to use */
3052     ncbp->ncb_lana_num = vcp->lana;
3053     ncbp->ncb_command = NCBSEND;        /* op means send data */
3054     ncbp->ncb_buffer = (char *) inp;/* packet */
3055     code = Netbios(ncbp);
3056
3057     if (code != 0) {
3058         const char * s = ncb_error_string(code);
3059         osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
3060         LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
3061
3062         lock_ObtainMutex(&vcp->mx);
3063         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
3064             osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
3065                       vcp, vcp->usersp);
3066             vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
3067             lock_ReleaseMutex(&vcp->mx);
3068             lock_ObtainWrite(&smb_globalLock);
3069             dead_sessions[vcp->session] = TRUE;
3070             lock_ReleaseWrite(&smb_globalLock);
3071             smb_CleanupDeadVC(vcp);
3072         } else {
3073             lock_ReleaseMutex(&vcp->mx);
3074         }
3075     }
3076
3077     if (localNCB)
3078         smb_FreeNCB(ncbp);
3079 }
3080
3081 void smb_MapNTError(long code, unsigned long *NTStatusp)
3082 {
3083     unsigned long NTStatus;
3084
3085     /* map CM_ERROR_* errors to NT 32-bit status codes */
3086     /* NT Status codes are listed in ntstatus.h not winerror.h */
3087     if (code == 0) {
3088         NTStatus = 0;
3089     }
3090     else if (code == CM_ERROR_NOSUCHCELL) {
3091         NTStatus = 0xC0000034L; /* Name not found */
3092     }
3093     else if (code == CM_ERROR_NOSUCHVOLUME) {
3094         NTStatus = 0xC0000034L; /* Name not found */
3095     }
3096     else if (code == CM_ERROR_TIMEDOUT) {
3097 #ifdef COMMENT
3098         NTStatus = 0xC00000CFL; /* Sharing Paused */
3099
3100         /* Do not send Timeout to the SMB redirector.
3101          * It causes the redirector to drop the connection */
3102         NTStatus = 0x00000102L; /* Timeout */
3103         /* do not send Retry to the SMB redirector.
3104          * It believes the error comes from the transport
3105          * layer not from the SMB server. */
3106         NTStatus = 0xC000022DL; /* Retry */
3107 #else
3108         NTStatus = 0xC00000B5L; /* I/O Timeout */
3109 #endif
3110     }
3111     else if (code == CM_ERROR_RETRY) {
3112 #ifdef COMMENT
3113         NTStatus = 0xC000022DL; /* Retry */
3114 #else
3115         NTStatus = 0xC00000B5L; /* I/O Timeout */
3116 #endif
3117     }
3118     else if (code == CM_ERROR_NOACCESS) {
3119         NTStatus = 0xC0000022L; /* Access denied */
3120     }
3121     else if (code == CM_ERROR_READONLY) {
3122         NTStatus = 0xC00000A2L; /* Write protected */
3123     }
3124     else if (code == CM_ERROR_NOSUCHFILE ||
3125              code == CM_ERROR_BPLUS_NOMATCH) {
3126         NTStatus = 0xC0000034L; /* Name not found */
3127     }
3128     else if (code == CM_ERROR_NOSUCHPATH) {
3129         NTStatus = 0xC000003AL; /* Object path not found */
3130     }
3131     else if (code == CM_ERROR_TOOBIG) {
3132         NTStatus = 0xC000007BL; /* Invalid image format */
3133     }
3134     else if (code == CM_ERROR_INVAL) {
3135         NTStatus = 0xC000000DL; /* Invalid parameter */
3136     }
3137     else if (code == CM_ERROR_BADFD) {
3138         NTStatus = 0xC0000008L; /* Invalid handle */
3139     }
3140     else if (code == CM_ERROR_BADFDOP) {
3141         NTStatus = 0xC0000022L; /* Access denied */
3142     }
3143     else if (code == CM_ERROR_UNKNOWN) {
3144         NTStatus = 0xC0000022L; /* Access denied */
3145     }
3146     else if (code == CM_ERROR_EXISTS) {
3147         NTStatus = 0xC0000035L; /* Object name collision */
3148     }
3149     else if (code == CM_ERROR_NOTEMPTY) {
3150         NTStatus = 0xC0000101L; /* Directory not empty */
3151     }
3152     else if (code == CM_ERROR_CROSSDEVLINK) {
3153         NTStatus = 0xC00000D4L; /* Not same device */
3154     }
3155     else if (code == CM_ERROR_NOTDIR) {
3156         NTStatus = 0xC0000103L; /* Not a directory */
3157     }
3158     else if (code == CM_ERROR_ISDIR) {
3159         NTStatus = 0xC00000BAL; /* File is a directory */
3160     }
3161     else if (code == CM_ERROR_BADOP) {
3162 #ifdef COMMENT
3163         /* I have no idea where this comes from */
3164         NTStatus = 0xC09820FFL; /* SMB no support */
3165 #else
3166         NTStatus = 0xC00000BBL;     /* Not supported */
3167 #endif /* COMMENT */
3168     }
3169     else if (code == CM_ERROR_BADSHARENAME) {
3170         NTStatus = 0xC00000BEL; /* Bad network path (server valid, share bad) */
3171     }
3172     else if (code == CM_ERROR_NOIPC) {
3173 #ifdef COMMENT
3174         NTStatus = 0xC0000022L; /* Access Denied */
3175 #else
3176         NTStatus = 0xC000013DL; /* Remote Resources */
3177 #endif
3178     }
3179     else if (code == CM_ERROR_CLOCKSKEW ||
3180              code == RXKADNOAUTH) {
3181         NTStatus = 0xC0000133L; /* Time difference at DC */
3182     }
3183     else if (code == CM_ERROR_BADTID) {
3184         NTStatus = 0xC0982005L; /* SMB bad TID */
3185     }
3186     else if (code == CM_ERROR_USESTD) {
3187         NTStatus = 0xC09820FBL; /* SMB use standard */
3188     }
3189     else if (code == CM_ERROR_QUOTA) {
3190         NTStatus = 0xC0000044L; /* Quota exceeded */
3191     }
3192     else if (code == CM_ERROR_SPACE) {
3193         NTStatus = 0xC000007FL; /* Disk full */
3194     }
3195     else if (code == CM_ERROR_ATSYS) {
3196         NTStatus = 0xC0000033L; /* Object name invalid */
3197     }
3198     else if (code == CM_ERROR_BADNTFILENAME) {
3199         NTStatus = 0xC0000033L; /* Object name invalid */
3200     }
3201     else if (code == CM_ERROR_WOULDBLOCK) {
3202         NTStatus = 0xC00000D8L; /* Can't wait */
3203     }
3204     else if (code == CM_ERROR_SHARING_VIOLATION) {
3205         NTStatus = 0xC0000043L; /* Sharing violation */
3206     }
3207     else if (code == CM_ERROR_LOCK_CONFLICT) {
3208         NTStatus = 0xC0000054L; /* Lock conflict */
3209     }
3210     else if (code == CM_ERROR_PARTIALWRITE) {
3211         NTStatus = 0xC000007FL; /* Disk full */
3212     }
3213     else if (code == CM_ERROR_BUFFERTOOSMALL) {
3214         NTStatus = 0xC0000023L; /* Buffer too small */
3215     }
3216     else if (code == CM_ERROR_BUFFER_OVERFLOW) {
3217         NTStatus = 0x80000005L; /* Buffer overflow */
3218     }
3219     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3220         NTStatus = 0xC0000035L; /* Object name collision */
3221     }
3222     else if (code == CM_ERROR_BADPASSWORD) {
3223         NTStatus = 0xC000006DL; /* unknown username or bad password */
3224     }
3225     else if (code == CM_ERROR_BADLOGONTYPE) {
3226         NTStatus = 0xC000015BL; /* logon type not granted */
3227     }
3228     else if (code == CM_ERROR_GSSCONTINUE) {
3229         NTStatus = 0xC0000016L; /* more processing required */
3230     }
3231     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3232 #ifdef COMMENT
3233         NTStatus = 0xC0000280L; /* reparse point not resolved */
3234 #else
3235         NTStatus = 0xC0000022L; /* Access Denied */
3236 #endif
3237     }
3238     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3239         NTStatus = 0xC0000257L; /* Path Not Covered */
3240     }
3241     else if (code == CM_ERROR_ALLBUSY) {
3242 #ifdef COMMENT
3243         NTStatus = 0xC000022DL; /* Retry */
3244 #else
3245         NTStatus = 0xC0020018L; /* RPC_NT_SERVER_TOO_BUSY */
3246 #endif
3247     }
3248     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3249 #ifdef COMMENT
3250         NTStatus = 0xC000003AL; /* Path not found */
3251 #else
3252         NTStatus = 0xC0020017L; /* RPC_NT_SERVER_UNAVAILABLE */
3253 #endif
3254     }
3255     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3256         NTStatus = 0xC0000322L; /* No Kerberos key */
3257     }
3258     else if (code == CM_ERROR_BAD_LEVEL) {
3259         NTStatus = 0xC0000148L; /* Invalid Level */
3260     }
3261     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3262         NTStatus = 0xC000007EL; /* Range Not Locked */
3263     }
3264     else if (code == CM_ERROR_NOSUCHDEVICE) {
3265         NTStatus = 0xC000000EL; /* No Such Device */
3266     }
3267     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3268         NTStatus = 0xC0000055L; /* Lock Not Granted */
3269     }
3270     else if (code == ENOMEM) {
3271         NTStatus = 0xC0000017L; /* Out of Memory */
3272     }
3273     else if (code == CM_ERROR_RPC_MOREDATA) {
3274         NTStatus = 0x80000005L; /* Buffer overflow */
3275     }
3276     else  {
3277         NTStatus = 0xC0982001L; /* SMB non-specific error */
3278     }
3279
3280     *NTStatusp = NTStatus;
3281     osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3282 }
3283
3284 /*
3285  * NTSTATUS <-> Win32 Error Translation
3286  * http://support.microsoft.com/kb/113996
3287  */
3288 void smb_MapWin32Error(long code, unsigned long *Win32Ep)
3289 {
3290     unsigned long Win32E;
3291
3292     /* map CM_ERROR_* errors to Win32 32-bit error codes */
3293     if (code == 0) {
3294         Win32E = 0;
3295     }
3296     else if (code == CM_ERROR_NOSUCHCELL) {
3297         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3298     }
3299     else if (code == CM_ERROR_NOSUCHVOLUME) {
3300         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3301     }
3302     else if (code == CM_ERROR_TIMEDOUT) {
3303 #ifdef COMMENT
3304         Win32E = ERROR_SHARING_PAUSED;  /* Sharing Paused */
3305 #else
3306         Win32E = ERROR_UNEXP_NET_ERR;   /* Timeout */
3307 #endif
3308     }
3309     else if (code == CM_ERROR_RETRY) {
3310         Win32E = ERROR_RETRY;           /* Retry */
3311     }
3312     else if (code == CM_ERROR_NOACCESS) {
3313         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3314     }
3315     else if (code == CM_ERROR_READONLY) {
3316         Win32E = ERROR_WRITE_PROTECT;   /* Write protected */
3317     }
3318     else if (code == CM_ERROR_NOSUCHFILE ||
3319              code == CM_ERROR_BPLUS_NOMATCH) {
3320         Win32E = ERROR_FILE_NOT_FOUND;  /* No such file */
3321     }
3322     else if (code == CM_ERROR_NOSUCHPATH) {
3323         Win32E = ERROR_PATH_NOT_FOUND;  /* Object path not found */
3324     }
3325     else if (code == CM_ERROR_TOOBIG) {
3326         Win32E = ERROR_BAD_EXE_FORMAT;  /* Invalid image format */
3327     }
3328     else if (code == CM_ERROR_INVAL) {
3329         Win32E = ERROR_INVALID_PARAMETER;/* Invalid parameter */
3330     }
3331     else if (code == CM_ERROR_BADFD) {
3332         Win32E = ERROR_INVALID_HANDLE;  /* Invalid handle */
3333     }
3334     else if (code == CM_ERROR_BADFDOP) {
3335         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3336     }
3337     else if (code == CM_ERROR_UNKNOWN) {
3338         Win32E = ERROR_ACCESS_DENIED;   /* Access denied */
3339     }
3340     else if (code == CM_ERROR_EXISTS) {
3341         Win32E = ERROR_ALREADY_EXISTS;  /* Object name collision */
3342     }
3343     else if (code == CM_ERROR_NOTEMPTY) {
3344         Win32E = ERROR_DIR_NOT_EMPTY;   /* Directory not empty */
3345     }
3346     else if (code == CM_ERROR_CROSSDEVLINK) {
3347         Win32E = ERROR_NOT_SAME_DEVICE; /* Not same device */
3348     }
3349     else if (code == CM_ERROR_NOTDIR) {
3350         Win32E = ERROR_DIRECTORY;       /* Not a directory */
3351     }
3352     else if (code == CM_ERROR_ISDIR) {
3353         Win32E = ERROR_ACCESS_DENIED;   /* File is a directory */
3354     }
3355     else if (code == CM_ERROR_BADOP) {
3356         Win32E = ERROR_NOT_SUPPORTED;   /* Not supported */
3357     }
3358     else if (code == CM_ERROR_BADSHARENAME) {
3359         Win32E = ERROR_BAD_NETPATH;     /* Bad network path (server valid, share bad) */
3360     }
3361     else if (code == CM_ERROR_NOIPC) {
3362 #ifdef COMMENT
3363         Win32E = ERROR_ACCESS_DENIED;   /* Access Denied */
3364 #else
3365         Win32E = ERROR_REM_NOT_LIST;    /* Remote Resources */
3366 #endif
3367     }
3368     else if (code == CM_ERROR_CLOCKSKEW ||
3369              code == RXKADNOAUTH) {
3370         Win32E = ERROR_TIME_SKEW;       /* Time difference at DC */
3371     }
3372     else if (code == CM_ERROR_BADTID) {
3373         Win32E = ERROR_FILE_NOT_FOUND;  /* SMB bad TID */
3374     }
3375     else if (code == CM_ERROR_USESTD) {
3376         Win32E = ERROR_ACCESS_DENIED;   /* SMB use standard */
3377     }
3378     else if (code == CM_ERROR_QUOTA) {
3379         Win32E = ERROR_NOT_ENOUGH_QUOTA;/* Quota exceeded */
3380     }
3381     else if (code == CM_ERROR_SPACE) {
3382         Win32E = ERROR_DISK_FULL;       /* Disk full */
3383     }
3384     else if (code == CM_ERROR_ATSYS) {
3385         Win32E = ERROR_INVALID_NAME;    /* Object name invalid */
3386     }
3387     else if (code == CM_ERROR_BADNTFILENAME) {
3388         Win32E = ERROR_INVALID_NAME;    /* Object name invalid */
3389     }
3390     else if (code == CM_ERROR_WOULDBLOCK) {
3391         Win32E = WAIT_TIMEOUT;          /* Can't wait */
3392     }
3393     else if (code == CM_ERROR_SHARING_VIOLATION) {
3394         Win32E = ERROR_SHARING_VIOLATION; /* Sharing violation */
3395     }
3396     else if (code == CM_ERROR_LOCK_CONFLICT) {
3397         Win32E = ERROR_LOCK_VIOLATION;   /* Lock conflict */
3398     }
3399     else if (code == CM_ERROR_PARTIALWRITE) {
3400         Win32E = ERROR_DISK_FULL;       /* Disk full */
3401     }
3402     else if (code == CM_ERROR_BUFFERTOOSMALL) {
3403         Win32E = ERROR_INSUFFICIENT_BUFFER;     /* Buffer too small */
3404     }
3405     else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
3406         Win32E = ERROR_ALREADY_EXISTS;  /* Object name collision */
3407     }
3408     else if (code == CM_ERROR_BADPASSWORD) {
3409         Win32E = ERROR_LOGON_FAILURE;   /* unknown username or bad password */
3410     }
3411     else if (code == CM_ERROR_BADLOGONTYPE) {
3412         Win32E = ERROR_INVALID_LOGON_TYPE; /* logon type not granted */
3413     }
3414     else if (code == CM_ERROR_GSSCONTINUE) {
3415         Win32E = ERROR_MORE_DATA;       /* more processing required */
3416     }
3417     else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
3418 #ifdef COMMENT
3419         Win32E = ERROR_CANT_RESOLVE_FILENAME; /* reparse point not resolved */
3420 #else
3421         Win32E = ERROR_ACCESS_DENIED;   /* Access Denied */
3422 #endif
3423     }
3424     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3425         Win32E = ERROR_HOST_UNREACHABLE; /* Path Not Covered */
3426     }
3427     else if (code == CM_ERROR_ALLBUSY) {
3428         Win32E = ERROR_RETRY;           /* Retry */
3429     }
3430     else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
3431         Win32E = ERROR_HOST_UNREACHABLE; /* Path not found */
3432     }
3433     else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
3434         Win32E = SEC_E_NO_KERB_KEY;     /* No Kerberos key */
3435     }
3436     else if (code == CM_ERROR_BAD_LEVEL) {
3437         Win32E = ERROR_INVALID_LEVEL;   /* Invalid Level */
3438     }
3439     else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
3440         Win32E = ERROR_NOT_LOCKED;      /* Range Not Locked */
3441     }
3442     else if (code == CM_ERROR_NOSUCHDEVICE) {
3443         Win32E = ERROR_FILE_NOT_FOUND;  /* No Such Device */
3444     }
3445     else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
3446         Win32E = ERROR_LOCK_VIOLATION;  /* Lock Not Granted */
3447     }
3448     else if (code == ENOMEM) {
3449         Win32E = ERROR_NOT_ENOUGH_MEMORY; /* Out of Memory */
3450     }
3451     else if (code == CM_ERROR_RPC_MOREDATA) {
3452         Win32E = ERROR_MORE_DATA;       /* Buffer overflow */
3453     }
3454     else  {
3455         Win32E = ERROR_GEN_FAILURE;     /* SMB non-specific error */
3456     }
3457
3458     *Win32Ep = Win32E;
3459     osi_Log2(smb_logp, "SMB SEND code %lX as Win32 %lX", code, Win32E);
3460 }
3461
3462 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3463                       unsigned char *classp)
3464 {
3465     unsigned char class;
3466     unsigned short error;
3467
3468     /* map CM_ERROR_* errors to SMB errors */
3469     if (code == CM_ERROR_NOSUCHCELL) {
3470         class = 1;
3471         error = 3;      /* bad path */
3472     }
3473     else if (code == CM_ERROR_NOSUCHVOLUME) {
3474         class = 1;
3475         error = 3;      /* bad path */
3476     }
3477     else if (code == CM_ERROR_TIMEDOUT) {
3478         class = 2;
3479         error = 81;     /* server is paused */
3480     }
3481     else if (code == CM_ERROR_RETRY) {
3482         class = 2;      /* shouldn't happen */
3483         error = 1;
3484     }
3485     else if (code == CM_ERROR_NOACCESS) {
3486         class = 2;
3487         error = 4;      /* bad access */
3488     }
3489     else if (code == CM_ERROR_READONLY) {
3490         class = 3;
3491         error = 19;     /* read only */
3492     }
3493     else if (code == CM_ERROR_NOSUCHFILE ||
3494              code == CM_ERROR_BPLUS_NOMATCH) {
3495         class = 1;
3496         error = 2;      /* ENOENT! */
3497     }
3498     else if (code == CM_ERROR_NOSUCHPATH) {
3499         class = 1;
3500         error = 3;      /* Bad path */
3501     }
3502     else if (code == CM_ERROR_TOOBIG) {
3503         class = 1;
3504         error = 11;     /* bad format */
3505     }
3506     else if (code == CM_ERROR_INVAL) {
3507         class = 2;      /* server non-specific error code */
3508         error = 1;
3509     }
3510     else if (code == CM_ERROR_BADFD) {
3511         class = 1;
3512         error = 6;      /* invalid file handle */
3513     }
3514     else if (code == CM_ERROR_BADFDOP) {
3515         class = 1;      /* invalid op on FD */
3516         error = 5;
3517     }
3518     else if (code == CM_ERROR_EXISTS) {
3519         class = 1;
3520         error = 80;     /* file already exists */
3521     }
3522     else if (code == CM_ERROR_NOTEMPTY) {
3523         class = 1;
3524         error = 5;      /* delete directory not empty */
3525     }
3526     else if (code == CM_ERROR_CROSSDEVLINK) {
3527         class = 1;
3528         error = 17;     /* EXDEV */
3529     }
3530     else if (code == CM_ERROR_NOTDIR) {
3531         class = 1;      /* bad path */
3532         error = 3;
3533     }
3534     else if (code == CM_ERROR_ISDIR) {
3535         class = 1;      /* access denied; DOS doesn't have a good match */
3536         error = 5;
3537     }
3538     else if (code == CM_ERROR_BADOP) {
3539         class = 2;
3540         error = 65535;
3541     }
3542     else if (code == CM_ERROR_BADSHARENAME) {
3543         class = 2;
3544         error = 6;
3545     }
3546     else if (code == CM_ERROR_NOIPC) {
3547         class = 2;
3548         error = 4; /* bad access */
3549     }
3550     else if (code == CM_ERROR_CLOCKSKEW) {
3551         class = 1;      /* invalid function */
3552         error = 1;
3553     }
3554     else if (code == CM_ERROR_BADTID) {
3555         class = 2;
3556         error = 5;
3557     }
3558     else if (code == CM_ERROR_USESTD) {
3559         class = 2;
3560         error = 251;
3561     }
3562     else if (code == CM_ERROR_REMOTECONN) {
3563         class = 2;
3564         error = 82;
3565     }
3566     else if (code == CM_ERROR_QUOTA) {
3567         if (vcp->flags & SMB_VCFLAG_USEV3) {
3568             class = 3;
3569             error = 39; /* disk full */
3570         }
3571         else {
3572             class = 1;
3573             error = 5;  /* access denied */
3574         }
3575     }
3576     else if (code == CM_ERROR_SPACE) {
3577         if (vcp->flags & SMB_VCFLAG_USEV3) {
3578             class = 3;
3579             error = 39; /* disk full */
3580         }
3581         else {
3582             class = 1;
3583             error = 5;  /* access denied */
3584         }
3585     }
3586     else if (code == CM_ERROR_PARTIALWRITE) {
3587         class = 3;
3588         error = 39;     /* disk full */
3589     }
3590     else if (code == CM_ERROR_ATSYS) {
3591         class = 1;
3592         error = 2;      /* ENOENT */
3593     }
3594     else if (code == CM_ERROR_WOULDBLOCK) {
3595         class = 1;
3596         error = 33;     /* lock conflict */
3597     }
3598     else if (code == CM_ERROR_LOCK_CONFLICT) {
3599         class = 1;
3600         error = 33;     /* lock conflict */
3601     }
3602     else if (code == CM_ERROR_SHARING_VIOLATION) {
3603         class = 1;
3604         error = 33;     /* lock conflict */
3605     }
3606     else if (code == CM_ERROR_NOFILES) {
3607         class = 1;
3608         error = 18;     /* no files in search */
3609     }
3610     else if (code == CM_ERROR_RENAME_IDENTICAL) {
3611         class = 1;
3612         error = 183;     /* Samba uses this */
3613     }
3614     else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3615         /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3616         class = 2;
3617         error = 2; /* bad password */
3618     }
3619     else if (code == CM_ERROR_PATH_NOT_COVERED) {
3620         class = 2;
3621         error = 3;     /* bad path */
3622     }
3623     else {
3624         class = 2;
3625         error = 1;
3626     }
3627
3628     *scodep = error;
3629     *classp = class;
3630     osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3631 }
3632
3633 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3634 {
3635     osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3636     return CM_ERROR_BADOP;
3637 }
3638
3639 /* SMB_COM_ECHO */
3640 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3641 {
3642     unsigned short EchoCount, i;
3643     char *data, *outdata;
3644     int dataSize;
3645
3646     EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3647
3648     for (i=1; i<=EchoCount; i++) {
3649         data = smb_GetSMBData(inp, &dataSize);
3650         smb_SetSMBParm(outp, 0, i);
3651         smb_SetSMBDataLength(outp, dataSize);
3652         outdata = smb_GetSMBData(outp, NULL);
3653         memcpy(outdata, data, dataSize);
3654         smb_SendPacket(vcp, outp);
3655     }
3656
3657     return 0;
3658 }
3659
3660 /* SMB_COM_READ_RAW */
3661 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3662 {
3663     osi_hyper_t offset;
3664     long count, minCount, finalCount;
3665     unsigned short fd;
3666     unsigned pid;
3667     smb_fid_t *fidp;
3668     smb_t *smbp = (smb_t*) inp;
3669     long code = 0;
3670     cm_user_t *userp = NULL;
3671     NCB *ncbp;
3672     int rc;
3673     char *rawBuf = NULL;
3674
3675     rawBuf = NULL;
3676     finalCount = 0;
3677
3678     fd = smb_GetSMBParm(inp, 0);
3679     count = smb_GetSMBParm(inp, 3);
3680     minCount = smb_GetSMBParm(inp, 4);
3681     offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3682
3683     if (*inp->wctp == 10) {
3684         /* we were sent a request with 64-bit file offsets */
3685         offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3686
3687         if (LargeIntegerLessThanZero(offset)) {
3688             osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3689             goto send1;
3690         }
3691     } else {
3692         /* we were sent a request with 32-bit file offsets */
3693         offset.HighPart = 0;
3694     }
3695
3696     osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3697              fd, offset.HighPart, offset.LowPart, count);
3698
3699     fidp = smb_FindFID(vcp, fd, 0);
3700     if (!fidp) {
3701         osi_Log2(smb_logp, "smb_ReceiveCoreReadRaw Unknown SMB Fid vcp 0x%p fid %d",
3702                  vcp, fd);
3703         goto send1;
3704     }
3705     lock_ObtainMutex(&fidp->mx);
3706     if (!fidp->scp) {
3707         lock_ReleaseMutex(&fidp->mx);
3708         smb_ReleaseFID(fidp);
3709         return CM_ERROR_BADFD;
3710     }
3711
3712     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
3713         lock_ReleaseMutex(&fidp->mx);
3714         smb_CloseFID(vcp, fidp, NULL, 0);
3715         code = CM_ERROR_NOSUCHFILE;
3716         goto send1a;
3717     }
3718
3719     pid = smbp->pid;
3720     {
3721         LARGE_INTEGER LOffset, LLength;
3722         cm_key_t key;
3723
3724         key = cm_GenerateKey(vcp->vcID, pid, fd);
3725
3726         LOffset.HighPart = offset.HighPart;
3727         LOffset.LowPart = offset.LowPart;
3728         LLength.HighPart = 0;
3729         LLength.LowPart = count;
3730
3731         lock_ObtainWrite(&fidp->scp->rw);
3732         code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3733         lock_ReleaseWrite(&fidp->scp->rw);
3734     }
3735     if (code) {
3736         lock_ReleaseMutex(&fidp->mx);
3737         goto send1a;
3738     }
3739
3740     lock_ObtainMutex(&smb_RawBufLock);
3741     if (smb_RawBufs) {
3742         /* Get a raw buf, from head of list */
3743         rawBuf = smb_RawBufs;
3744         smb_RawBufs = *(char **)smb_RawBufs;
3745     }
3746     lock_ReleaseMutex(&smb_RawBufLock);
3747     if (!rawBuf) {
3748         lock_ReleaseMutex(&fidp->mx);
3749         goto send1a;
3750     }
3751
3752     if (fidp->flags & SMB_FID_IOCTL)
3753     {
3754         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3755         if (rawBuf) {
3756             /* Give back raw buffer */
3757             lock_ObtainMutex(&smb_RawBufLock);
3758             *((char **) rawBuf) = smb_RawBufs;
3759
3760             smb_RawBufs = rawBuf;
3761             lock_ReleaseMutex(&smb_RawBufLock);
3762         }
3763
3764         lock_ReleaseMutex(&fidp->mx);
3765         smb_ReleaseFID(fidp);
3766         return rc;
3767     }
3768     lock_ReleaseMutex(&fidp->mx);
3769
3770     userp = smb_GetUserFromVCP(vcp, inp);
3771
3772     code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3773
3774     if (code != 0)
3775         goto send;
3776
3777   send:
3778     cm_ReleaseUser(userp);
3779
3780   send1a:
3781     smb_ReleaseFID(fidp);
3782
3783   send1:
3784     ncbp = outp->ncbp;
3785     memset(ncbp, 0, sizeof(NCB));
3786
3787     ncbp->ncb_length = (unsigned short) finalCount;
3788     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3789     ncbp->ncb_lana_num = vcp->lana;
3790     ncbp->ncb_command = NCBSEND;
3791     ncbp->ncb_buffer = rawBuf;
3792
3793     code = Netbios(ncbp);
3794     if (code != 0)
3795         osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3796
3797     if (rawBuf) {
3798         /* Give back raw buffer */
3799         lock_ObtainMutex(&smb_RawBufLock);
3800         *((char **) rawBuf) = smb_RawBufs;
3801
3802         smb_RawBufs = rawBuf;
3803         lock_ReleaseMutex(&smb_RawBufLock);
3804     }
3805
3806     return 0;
3807 }
3808
3809 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3810 {
3811     osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3812                          ongoingOps - 1);
3813     return 0;
3814 }
3815
3816 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3817 {
3818     osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3819                          ongoingOps - 1);
3820     return 0;
3821 }
3822
3823 /* SMB_COM_NEGOTIATE */
3824 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3825 {
3826     char *namep;
3827     char *datap;
3828     int coreProtoIndex;
3829     int v3ProtoIndex;
3830     int NTProtoIndex;
3831     int VistaProtoIndex;
3832     int protoIndex;                             /* index we're using */
3833     int namex;
3834     int dbytes;
3835     int entryLength;
3836     int tcounter;
3837     char protocol_array[10][1024];  /* protocol signature of the client */
3838     int caps;                       /* capabilities */
3839     time_t unixTime;
3840     afs_uint32 dosTime;
3841     TIME_ZONE_INFORMATION tzi;
3842
3843     osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3844                          ongoingOps - 1);
3845
3846     namep = smb_GetSMBData(inp, &dbytes);
3847     namex = 0;
3848     tcounter = 0;
3849     coreProtoIndex = -1;                /* not found */
3850     v3ProtoIndex = -1;
3851     NTProtoIndex = -1;
3852     VistaProtoIndex = -1;
3853     while(namex < dbytes) {
3854         osi_Log1(smb_logp, "Protocol %s",
3855                   osi_LogSaveString(smb_logp, namep+1));
3856         strcpy(protocol_array[tcounter], namep+1);
3857
3858         /* namep points at the first protocol, or really, a 0x02
3859          * byte preceding the null-terminated ASCII name.
3860          */
3861         if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3862             coreProtoIndex = tcounter;
3863         }
3864         else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3865             v3ProtoIndex = tcounter;
3866         }
3867         else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3868             NTProtoIndex = tcounter;
3869         }
3870         else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3871             VistaProtoIndex = tcounter;
3872         }
3873
3874         /* compute size of protocol entry */
3875         entryLength = (int)strlen(namep+1);
3876         entryLength += 2;       /* 0x02 bytes and null termination */
3877
3878         /* advance over this protocol entry */
3879         namex += entryLength;
3880         namep += entryLength;
3881         tcounter++;             /* which proto entry we're looking at */
3882     }
3883
3884     lock_ObtainMutex(&vcp->mx);
3885 #if 0
3886     if (VistaProtoIndex != -1) {
3887         protoIndex = VistaProtoIndex;
3888         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3889     } else
3890 #endif
3891         if (NTProtoIndex != -1) {
3892         protoIndex = NTProtoIndex;
3893         vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3894     }
3895     else if (v3ProtoIndex != -1) {
3896         protoIndex = v3ProtoIndex;
3897         vcp->flags |= SMB_VCFLAG_USEV3;
3898     }
3899     else if (coreProtoIndex != -1) {
3900         protoIndex = coreProtoIndex;
3901         vcp->flags |= SMB_VCFLAG_USECORE;
3902     }
3903     else protoIndex = -1;
3904     lock_ReleaseMutex(&vcp->mx);
3905
3906     if (protoIndex == -1)
3907         return CM_ERROR_INVAL;
3908     else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3909         smb_SetSMBParm(outp, 0, protoIndex);
3910         if (smb_authType != SMB_AUTH_NONE) {
3911             smb_SetSMBParmByte(outp, 1,
3912                                NEGOTIATE_SECURITY_USER_LEVEL |
3913                                NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);  /* user level security, challenge response */
3914         } else {
3915             smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3916         }
3917         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
3918         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
3919         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE);    /* xmit buffer size */
3920         smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE);    /* raw buffer size */
3921         /* The session key is not a well documented field however most clients
3922          * will echo back the session key to the server.  Currently we are using
3923          * the same value for all sessions.  We should generate a random value
3924          * and store it into the vcp
3925          */
3926         smb_SetSMBParmLong(outp, 7, 0x1a2b3c4d);        /* session key */
3927         /*
3928          * Tried changing the capabilities to support for W2K - defect 117695
3929          * Maybe something else needs to be changed here?
3930          */
3931         /*
3932         if (isWindows2000)
3933         smb_SetSMBParmLong(outp, 9, 0x43fd);
3934         else
3935         smb_SetSMBParmLong(outp, 9, 0x251);
3936         */
3937         /* Capabilities: *
3938          * 32-bit error codes *
3939          * and NT Find *
3940          * and NT SMB's *
3941          * and raw mode
3942          * and DFS
3943          * and Unicode */
3944         caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3945 #ifdef DFS_SUPPORT
3946                NTNEGOTIATE_CAPABILITY_DFS |
3947 #endif
3948                NTNEGOTIATE_CAPABILITY_LARGEFILES |
3949                NTNEGOTIATE_CAPABILITY_NTFIND |
3950                NTNEGOTIATE_CAPABILITY_RAWMODE |
3951                NTNEGOTIATE_CAPABILITY_NTSMB;
3952
3953         if ( smb_authType == SMB_AUTH_EXTENDED )
3954             caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3955
3956 #ifdef SMB_UNICODE
3957         if ( smb_UseUnicode ) {
3958             caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3959         }
3960 #endif
3961
3962         smb_SetSMBParmLong(outp, 9, caps);
3963         time(&unixTime);
3964         cm_SearchTimeFromUnixTime(&dosTime, unixTime);
3965         smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3966         smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3967
3968         GetTimeZoneInformation(&tzi);
3969         smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias);    /* server tzone */
3970
3971         if (smb_authType == SMB_AUTH_NTLM) {
3972             smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3973             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3974             /* paste in encryption key */
3975             datap = smb_GetSMBData(outp, NULL);
3976             memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3977             /* and the faux domain name */
3978             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3979                                   datap + MSV1_0_CHALLENGE_LENGTH,
3980                                   (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
3981         } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3982             void * secBlob;
3983             int secBlobLength;
3984
3985             smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3986
3987             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3988
3989             smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3990
3991             datap = smb_GetSMBData(outp, NULL);
3992             memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3993
3994             if (secBlob) {
3995                 datap += sizeof(smb_ServerGUID);
3996                 memcpy(datap, secBlob, secBlobLength);
3997                 free(secBlob);
3998             }
3999         } else {
4000             smb_SetSMBParmByte(outp, 16, 0);/* Challenge length */
4001             smb_SetSMBDataLength(outp, smb_ServerDomainNameLength);
4002             datap = smb_GetSMBData(outp, NULL);
4003             /* the faux domain name */
4004             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4005                                   datap,
4006                                   (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4007         }
4008     }
4009     else if (v3ProtoIndex != -1) {
4010         smb_SetSMBParm(outp, 0, protoIndex);
4011
4012         /* NOTE: Extended authentication cannot be negotiated with v3
4013          * therefore we fail over to NTLM
4014          */
4015         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4016             smb_SetSMBParm(outp, 1,
4017                            NEGOTIATE_SECURITY_USER_LEVEL |
4018                            NEGOTIATE_SECURITY_CHALLENGE_RESPONSE);      /* user level security, challenge response */
4019         } else {
4020             smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
4021         }
4022         smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
4023         smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
4024         smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
4025         smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
4026         smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
4027         smb_SetSMBParm(outp, 7, 1);
4028         time(&unixTime);
4029         cm_SearchTimeFromUnixTime(&dosTime, unixTime);
4030         smb_SetSMBParm(outp, 8, LOWORD(dosTime));       /* server time */
4031         smb_SetSMBParm(outp, 9, HIWORD(dosTime));       /* server date */
4032
4033         GetTimeZoneInformation(&tzi);
4034         smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias);    /* server tzone */
4035
4036         /* NOTE: Extended authentication cannot be negotiated with v3
4037          * therefore we fail over to NTLM
4038          */
4039         if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
4040             smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH);  /* encryption key length */
4041             smb_SetSMBParm(outp, 12, 0);        /* resvd */
4042             smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);   /* perhaps should specify 8 bytes anyway */
4043             datap = smb_GetSMBData(outp, NULL);
4044             /* paste in a new encryption key */
4045             memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
4046             /* and the faux domain name */
4047             cm_ClientStringToUtf8(smb_ServerDomainName, -1,
4048                                   datap + MSV1_0_CHALLENGE_LENGTH,
4049                                   (int)(sizeof(outp->data)/sizeof(char) - (datap - outp->data)));
4050         } else {
4051             smb_SetSMBParm(outp, 11, 0); /* encryption key length */
4052             smb_SetSMBParm(outp, 12, 0); /* resvd */
4053             smb_SetSMBDataLength(outp, 0);
4054         }
4055     }
4056     else if (coreProtoIndex != -1) {     /* not really supported anymore */
4057         smb_SetSMBParm(outp, 0, protoIndex);
4058         smb_SetSMBDataLength(outp, 0);
4059     }
4060     return 0;
4061 }
4062
4063 void smb_CheckVCs(void)
4064 {
4065     smb_vc_t * vcp, *nextp;
4066     smb_packet_t * outp = smb_GetPacket();
4067     smb_t *smbp;
4068
4069     lock_ObtainWrite(&smb_rctLock);
4070     for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
4071     {
4072         if (vcp->magic != SMB_VC_MAGIC)
4073             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
4074                        __FILE__, __LINE__);
4075
4076         /* on the first pass hold 'vcp' which was not held as 'nextp' */
4077         if (vcp != nextp)
4078             smb_HoldVCNoLock(vcp);
4079
4080         /*
4081          * obtain a reference to 'nextp' now because we drop the
4082          * smb_rctLock later and the list contents could change
4083          * or 'vcp' could be destroyed when released.
4084          */
4085         nextp = vcp->nextp;
4086         if (nextp)
4087             smb_HoldVCNoLock(nextp);
4088
4089         if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
4090             smb_ReleaseVCNoLock(vcp);
4091             continue;
4092         }
4093
4094         smb_FormatResponsePacket(vcp, NULL, outp);
4095         smbp = (smb_t *)outp;
4096         outp->inCom = smbp->com = 0x2b /* Echo */;
4097         smbp->tid = 0xFFFF;
4098         smbp->pid = 0;
4099         smbp->uid = 0;
4100         smbp->mid = 0;
4101         smbp->res[0] = 0;
4102         smbp->res[1] = 0;
4103
4104         smb_SetSMBParm(outp, 0, 0);
4105         smb_SetSMBDataLength(outp, 0);
4106         lock_ReleaseWrite(&smb_rctLock);
4107
4108         smb_SendPacket(vcp, outp);
4109
4110         lock_ObtainWrite(&smb_rctLock);
4111         smb_ReleaseVCNoLock(vcp);
4112     }
4113     lock_ReleaseWrite(&smb_rctLock);
4114     smb_FreePacket(outp);
4115 }
4116
4117 void smb_Daemon(void *parmp)
4118 {
4119     afs_uint32 count = 0;
4120     smb_username_t    **unpp;
4121     time_t              now;
4122
4123     while(smbShutdownFlag == 0) {
4124         count++;
4125         thrd_Sleep(10000);
4126
4127         if (smbShutdownFlag == 1)
4128             break;
4129
4130         if ((count % 72) == 0)  {       /* every five minutes */
4131             struct tm myTime;
4132             time_t old_localZero = smb_localZero;
4133
4134             /* Initialize smb_localZero */
4135             myTime.tm_isdst = -1;               /* compute whether on DST or not */
4136             myTime.tm_year = 70;
4137             myTime.tm_mon = 0;
4138             myTime.tm_mday = 1;
4139             myTime.tm_hour = 0;
4140             myTime.tm_min = 0;
4141             myTime.tm_sec = 0;
4142             smb_localZero = mktime(&myTime);
4143
4144 #ifdef AFS_FREELANCE
4145             if ( smb_localZero != old_localZero )
4146                 cm_noteLocalMountPointChange(FALSE);
4147 #endif
4148
4149             smb_CheckVCs();
4150         }
4151
4152         /* GC smb_username_t objects that will no longer be used */
4153         now = osi_Time();
4154         lock_ObtainWrite(&smb_rctLock);
4155         for ( unpp=&usernamesp; *unpp; ) {
4156             int deleteOk = 0;
4157             smb_username_t *unp;
4158
4159             lock_ObtainMutex(&(*unpp)->mx);
4160             if ( (*unpp)->refCount > 0 ||
4161                  ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
4162                  !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
4163                 ;
4164             else if (!smb_LogoffTokenTransfer ||
4165                      ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
4166                 deleteOk = 1;
4167             lock_ReleaseMutex(&(*unpp)->mx);
4168
4169             if (deleteOk) {
4170                 cm_user_t * userp;
4171
4172                 unp = *unpp;
4173                 *unpp = unp->nextp;
4174                 unp->nextp = NULL;
4175                 lock_FinalizeMutex(&unp->mx);
4176                 userp = unp->userp;
4177                 free(unp->name);
4178                 free(unp->machine);
4179                 free(unp);
4180                 if (userp)
4181                     cm_ReleaseUser(userp);
4182             } else {
4183                 unpp = &(*unpp)->nextp;
4184             }
4185         }
4186         lock_ReleaseWrite(&smb_rctLock);
4187
4188         /* XXX GC dir search entries */
4189     }
4190 }
4191
4192 void smb_WaitingLocksDaemon()
4193 {
4194     smb_waitingLockRequest_t *wlRequest, *nwlRequest;
4195     smb_waitingLock_t *wl, *wlNext;
4196     int first;
4197     smb_vc_t *vcp;
4198     smb_packet_t *inp, *outp;
4199     NCB *ncbp;
4200     long code = 0;
4201
4202     while (smbShutdownFlag == 0) {
4203         lock_ObtainWrite(&smb_globalLock);
4204         nwlRequest = smb_allWaitingLocks;
4205         if (nwlRequest == NULL) {
4206             osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
4207             thrd_Sleep(1000);
4208             continue;
4209         } else {
4210             first = 1;
4211             osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
4212         }
4213
4214         do {
4215             if (first)
4216                 first = 0;
4217             else
4218                 lock_ObtainWrite(&smb_globalLock);
4219
4220             osi_Log1(smb_logp, "    Checking waiting lock request %p", nwlRequest);
4221
4222             wlRequest = nwlRequest;
4223             nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
4224             lock_ReleaseWrite(&smb_globalLock);
4225
4226             code = 0;
4227
4228             for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
4229                 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4230                     continue;
4231
4232                 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
4233                     code = CM_ERROR_LOCK_NOT_GRANTED;
4234                     break;
4235                 }
4236
4237                 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
4238
4239                 /* wl->state is either _DONE or _WAITING.  _ERROR
4240                    would no longer be on the queue. */
4241                 code = cm_RetryLock( wl->lockp,
4242                                      !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
4243
4244                 if (code == 0) {
4245                     wl->state = SMB_WAITINGLOCKSTATE_DONE;
4246                 } else if (code != CM_ERROR_WOULDBLOCK) {
4247                     wl->state = SMB_WAITINGLOCKSTATE_ERROR;
4248                     break;
4249                 }
4250             }
4251
4252             if (code == CM_ERROR_WOULDBLOCK) {
4253
4254                 /* no progress */
4255                 if (wlRequest->msTimeout != 0xffffffff
4256                      && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
4257                     goto endWait;
4258
4259                 continue;
4260             }
4261
4262           endWait:
4263
4264             if (code != 0) {
4265                 cm_scache_t * scp;
4266                 cm_req_t req;
4267
4268                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
4269                          wlRequest);
4270
4271                 scp = wlRequest->scp;
4272                 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
4273
4274                 smb_InitReq(&req);
4275
4276                 lock_ObtainWrite(&scp->rw);
4277
4278                 for (wl = wlRequest->locks; wl; wl = wlNext) {
4279                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4280
4281                     if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
4282                         cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
4283                                   wl->LLength, wl->key, 0, NULL, &req);
4284
4285                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4286
4287                     free(wl);
4288                 }
4289
4290                 lock_ReleaseWrite(&scp->rw);
4291
4292             } else {
4293
4294                 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
4295                          wlRequest);
4296
4297                 for (wl = wlRequest->locks; wl; wl = wlNext) {
4298                     wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
4299                     osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
4300                     free(wl);
4301                 }
4302             }
4303
4304             vcp = wlRequest->vcp;
4305             inp = wlRequest->inp;
4306             outp = wlRequest->outp;
4307             ncbp = smb_GetNCB();
4308             ncbp->ncb_length = inp->ncb_length;
4309             inp->spacep = cm_GetSpace();
4310
4311             /* Remove waitingLock from list */
4312             lock_ObtainWrite(&smb_globalLock);
4313             osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
4314                          &wlRequest->q);
4315             lock_ReleaseWrite(&smb_globalLock);
4316
4317             /* Resume packet processing */
4318             if (code == 0)
4319                 smb_SetSMBDataLength(outp, 0);
4320             outp->flags |= SMB_PACKETFLAG_SUSPENDED;
4321             outp->resumeCode = code;
4322             outp->ncbp = ncbp;
4323             smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
4324
4325             /* Clean up */
4326             cm_FreeSpace(inp->spacep);
4327             smb_FreePacket(inp);
4328             smb_FreePacket(outp);
4329             smb_ReleaseVC(vcp);
4330             cm_ReleaseSCache(wlRequest->scp);
4331             smb_FreeNCB(ncbp);
4332             free(wlRequest);
4333         } while (nwlRequest && smbShutdownFlag == 0);
4334         thrd_Sleep(1000);
4335     }
4336 }
4337
4338 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4339 {
4340     osi_Log0(smb_logp, "SMB receive get disk attributes");
4341
4342     smb_SetSMBParm(outp, 0, 32000);
4343     smb_SetSMBParm(outp, 1, 64);
4344     smb_SetSMBParm(outp, 2, 1024);
4345     smb_SetSMBParm(outp, 3, 30000);
4346     smb_SetSMBParm(outp, 4, 0);
4347     smb_SetSMBDataLength(outp, 0);
4348     return 0;
4349 }
4350
4351 /* SMB_COM_TREE_CONNECT */
4352 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
4353 {
4354     smb_tid_t *tidp;
4355     smb_user_t *uidp;
4356     unsigned short newTid;
4357     clientchar_t shareName[AFSPATHMAX];
4358     clientchar_t *sharePath;
4359     int shareFound;
4360     clientchar_t *tp;
4361     clientchar_t *pathp;
4362     cm_user_t *userp;
4363
4364     osi_Log0(smb_logp, "SMB receive tree connect");
4365
4366     /* parse input parameters */
4367     {
4368         char *tbp;
4369         tbp = smb_GetSMBData(inp, NULL);
4370         pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
4371         if (!pathp)
4372             return CM_ERROR_BADSMB;
4373     }
4374     tp = cm_ClientStrRChr(pathp, '\\');
4375     if (!tp)
4376         return CM_ERROR_BADSMB;
4377     cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
4378
4379     lock_ObtainMutex(&vcp->mx);
4380     newTid = vcp->tidCounter++;
4381     lock_ReleaseMutex(&vcp->mx);
4382
4383     tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
4384     uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
4385     if (!uidp)
4386         return CM_ERROR_BADSMB;
4387     userp = smb_GetUserFromUID(uidp);
4388     shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
4389     smb_ReleaseUID(uidp);
4390     if (!shareFound) {
4391         smb_ReleaseTID(tidp, FALSE);
4392         return CM_ERROR_BADSHARENAME;
4393     }
4394     lock_ObtainMutex(&tidp->mx);
4395     tidp->userp = userp;
4396     tidp->pathname = sharePath;
4397     lock_ReleaseMutex(&tidp->mx);
4398     smb_ReleaseTID(tidp, FALSE);
4399
4400     smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
4401     smb_SetSMBParm(rsp, 1, newTid);
4402     smb_SetSMBDataLength(rsp, 0);
4403
4404     osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
4405     return 0;
4406 }
4407
4408 /* set maskp to the mask part of the incoming path.
4409  * Mask is 11 bytes long (8.3 with the dot elided).
4410  * Returns true if succeeds with a valid name, otherwise it does
4411  * its best, but returns false.
4412  */
4413 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
4414 {
4415     clientchar_t *tp;
4416     clientchar_t *up;
4417     int i;
4418     int tc;
4419     int valid8Dot3;
4420
4421     /* starts off valid */
4422     valid8Dot3 = 1;
4423
4424     /* mask starts out all blanks */
4425     memset(maskp, ' ', 11);
4426     maskp[11] = '\0';
4427
4428     /* find last backslash, or use whole thing if there is none */
4429     tp = cm_ClientStrRChr(pathp, '\\');
4430     if (!tp)
4431         tp = pathp;
4432     else
4433         tp++;   /* skip slash */
4434
4435     up = maskp;
4436
4437     /* names starting with a dot are illegal */
4438     if (*tp == '.')
4439         valid8Dot3 = 0;
4440
4441     for(i=0;; i++) {
4442         tc = *tp++;
4443         if (tc == 0)
4444             return valid8Dot3;
4445         if (tc == '.' || tc == '"')
4446             break;
4447         if (i < 8)
4448             *up++ = tc;
4449         else
4450             valid8Dot3 = 0;
4451     }
4452
4453     /* if we get here, tp point after the dot */
4454     up = maskp+8;       /* ext goes here */
4455     for(i=0;;i++) {
4456         tc = *tp++;
4457         if (tc == 0)
4458             return valid8Dot3;
4459
4460         /* too many dots */
4461         if (tc == '.' || tc == '"')
4462             valid8Dot3 = 0;
4463
4464         /* copy extension if not too long */
4465         if (i < 3)
4466             *up++ = tc;
4467         else
4468             valid8Dot3 = 0;
4469     }
4470
4471     /* unreachable */
4472 }
4473
4474 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4475 {
4476     clientchar_t umask[11];
4477     int valid;
4478     int i;
4479     clientchar_t tc1;
4480     clientchar_t tc2;
4481     clientchar_t *tp1;
4482     clientchar_t *tp2;
4483
4484     /* XXX redo this, calling cm_MatchMask with a converted mask */
4485
4486     valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4487     if (!valid)
4488         return 0;
4489
4490     /* otherwise, we have a valid 8.3 name; see if we have a match,
4491      * treating '?' as a wildcard in maskp (but not in the file name).
4492      */
4493     tp1 = umask;        /* real name, in mask format */
4494     tp2 = maskp;        /* mask, in mask format */
4495     for(i=0; i<11; i++) {
4496         tc1 = *tp1++;   /* clientchar_t from real name */
4497         tc2 = *tp2++;   /* clientchar_t from mask */
4498         tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4499         tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4500         if (tc1 == tc2)
4501             continue;
4502         if (tc2 == '?' && tc1 != ' ')
4503             continue;
4504         if (tc2 == '>')
4505             continue;
4506         return 0;
4507     }
4508
4509     /* we got a match */
4510     return 1;
4511 }
4512
4513 clientchar_t *smb_FindMask(clientchar_t *pathp)
4514 {
4515     clientchar_t *tp;
4516
4517     tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4518
4519     if (tp)
4520         return tp+1;    /* skip the slash */
4521     else
4522         return pathp;   /* no slash, return the entire path */
4523 }
4524
4525 /* SMB_COM_SEARCH for a volume label
4526
4527    (This is called from smb_ReceiveCoreSearchDir() and not an actual
4528    dispatch function.) */
4529 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4530 {
4531     clientchar_t *pathp;
4532     unsigned char *tp;
4533     clientchar_t mask[12];
4534     unsigned char *statBlockp;
4535     unsigned char initStatBlock[21];
4536     int statLen;
4537
4538     osi_Log0(smb_logp, "SMB receive search volume");
4539
4540     /* pull pathname and stat block out of request */
4541     tp = smb_GetSMBData(inp, NULL);
4542     pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4543                                 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4544     if (!pathp)
4545         return CM_ERROR_BADSMB;
4546     statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4547     osi_assertx(statBlockp != NULL, "null statBlock");
4548     if (statLen == 0) {
4549         statBlockp = initStatBlock;
4550         statBlockp[0] = 8;
4551     }
4552
4553     /* for returning to caller */
4554     smb_Get8Dot3MaskFromPath(mask, pathp);
4555
4556     smb_SetSMBParm(outp, 0, 1);         /* we're returning one entry */
4557     tp = smb_GetSMBData(outp, NULL);
4558     *tp++ = 5;
4559     *tp++ = 43; /* bytes in a dir entry */
4560     *tp++ = 0;  /* high byte in counter */
4561
4562     /* now marshall the dir entry, starting with the search status */
4563     *tp++ = statBlockp[0];              /* Reserved */
4564     memcpy(tp, mask, 11); tp += 11;     /* FileName */
4565
4566     /* now pass back server use info, with 1st byte non-zero */
4567     *tp++ = 1;
4568     memset(tp, 0, 4); tp += 4;  /* reserved for server use */
4569
4570     memcpy(tp, statBlockp+17, 4); tp += 4;      /* reserved for consumer */
4571
4572     *tp++ = 0x8;                /* attribute: volume */
4573
4574     /* copy out time */
4575     *tp++ = 0;
4576     *tp++ = 0;
4577
4578     /* copy out date */
4579     *tp++ = 18;
4580     *tp++ = 178;
4581
4582     /* 4 byte file size */
4583     *tp++ = 0;
4584     *tp++ = 0;
4585     *tp++ = 0;
4586     *tp++ = 0;
4587
4588     /* The filename is a UCHAR buffer that is ASCII even if Unicode
4589        was negotiated. */
4590
4591     /* finally, null-terminated 8.3 pathname, which we set to AFS */
4592     memset(tp, ' ', 13);
4593     strcpy(tp, "AFS");
4594
4595     /* set the length of the data part of the packet to 43 + 3, for the dir
4596      * entry plus the 5 and the length fields.
4597      */
4598     smb_SetSMBDataLength(outp, 46);
4599     return 0;
4600 }
4601
4602 static long
4603 smb_ApplyDirListPatches(cm_scache_t * dscp, smb_dirListPatch_t **dirPatchespp,
4604                         clientchar_t * tidPathp, clientchar_t * relPathp,
4605                         cm_user_t *userp, cm_req_t *reqp)
4606 {
4607     long code = 0;
4608     cm_scache_t *scp;
4609     char *dptr;
4610     afs_uint32 dosTime;
4611     u_short shortTemp;
4612     char attr;
4613     smb_dirListPatch_t *patchp;
4614     smb_dirListPatch_t *npatchp;
4615     clientchar_t path[AFSPATHMAX];
4616     afs_uint32 rights;
4617     afs_int32 mustFake = 0;
4618
4619     code = cm_FindACLCache(dscp, userp, &rights);
4620     if (code == -1) {
4621         lock_ObtainWrite(&dscp->rw);
4622         code = cm_SyncOp(dscp, NULL, userp, reqp, PRSFS_READ,
4623                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4624         lock_ReleaseWrite(&dscp->rw);
4625         if (code == CM_ERROR_NOACCESS) {
4626             mustFake = 1;
4627             code = 0;
4628         }
4629     }
4630     if (code)
4631         goto cleanup;
4632
4633     if (!mustFake) {    /* Bulk Stat */
4634         afs_uint32 count;
4635         cm_bulkStat_t *bsp = malloc(sizeof(cm_bulkStat_t));
4636
4637         memset(bsp, 0, sizeof(cm_bulkStat_t));
4638
4639         for (patchp = *dirPatchespp, count=0;
4640              patchp;
4641              patchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4642             cm_scache_t *tscp = cm_FindSCache(&patchp->fid);
4643             int i;
4644
4645             if (tscp) {
4646                 if (lock_TryWrite(&tscp->rw)) {
4647                     /* we have an entry that we can look at */
4648                     if (!(tscp->flags & CM_SCACHEFLAG_EACCESS) && cm_HaveCallback(tscp)) {
4649                         /* we have a callback on it.  Don't bother
4650                         * fetching this stat entry, since we're happy
4651                         * with the info we have.
4652                         */
4653                         lock_ReleaseWrite(&tscp->rw);
4654                         cm_ReleaseSCache(tscp);
4655                         continue;
4656                     }
4657                     lock_ReleaseWrite(&tscp->rw);
4658                 } /* got lock */
4659                 cm_ReleaseSCache(tscp);
4660             }   /* found entry */
4661
4662             i = bsp->counter++;
4663             bsp->fids[i].Volume = patchp->fid.volume;
4664             bsp->fids[i].Vnode = patchp->fid.vnode;
4665             bsp->fids[i].Unique = patchp->fid.unique;
4666
4667             if (bsp->counter == AFSCBMAX) {
4668                 code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4669                 memset(bsp, 0, sizeof(cm_bulkStat_t));
4670             }
4671         }
4672
4673         if (bsp->counter > 0)
4674             code = cm_TryBulkStatRPC(dscp, bsp, userp, reqp);
4675
4676         free(bsp);
4677     }
4678
4679     for (patchp = *dirPatchespp; patchp; patchp =
4680          (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4681
4682         dptr = patchp->dptr;
4683
4684         cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4685                             relPathp ? relPathp : _C(""), patchp->dep->name);
4686         reqp->relPathp = path;
4687         reqp->tidPathp = tidPathp;
4688
4689         code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4690         reqp->relPathp = reqp->tidPathp = NULL;
4691
4692         if (code) {
4693             if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4694                 *dptr++ = SMB_ATTR_HIDDEN;
4695             continue;
4696         }
4697         lock_ObtainWrite(&scp->rw);
4698         if (mustFake || (scp->flags & CM_SCACHEFLAG_EACCESS) || !cm_HaveCallback(scp)) {
4699             lock_ReleaseWrite(&scp->rw);
4700
4701             /* set the attribute */
4702             switch (scp->fileType) {
4703             case CM_SCACHETYPE_DIRECTORY:
4704             case CM_SCACHETYPE_MOUNTPOINT:
4705             case CM_SCACHETYPE_INVALID:
4706                 attr = SMB_ATTR_DIRECTORY;
4707                 break;
4708             case CM_SCACHETYPE_SYMLINK:
4709                 if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
4710                     attr = SMB_ATTR_DIRECTORY;
4711                 else
4712                     attr = SMB_ATTR_NORMAL;
4713                 break;
4714             default:
4715                 /* if we get here we either have a normal file
4716                 * or we have a file for which we have never
4717                 * received status info.  In this case, we can
4718                 * check the even/odd value of the entry's vnode.
4719                 * odd means it is to be treated as a directory
4720                 * and even means it is to be treated as a file.
4721                 */
4722                 if (mustFake && (scp->fid.vnode & 0x1))
4723                     attr = SMB_ATTR_DIRECTORY;
4724                 else
4725                     attr = SMB_ATTR_NORMAL;
4726             }
4727             *dptr++ = attr;
4728
4729             /* 1969-12-31 23:59:58 +00*/
4730             dosTime = 0xEBBFBF7D;
4731
4732             /* copy out time */
4733             shortTemp = (unsigned short) (dosTime & 0xffff);
4734             *((u_short *)dptr) = shortTemp;
4735             dptr += 2;
4736
4737             /* and copy out date */
4738             shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4739             *((u_short *)dptr) = shortTemp;
4740             dptr += 2;
4741
4742             /* copy out file length */
4743             *((u_long *)dptr) = 0;
4744             dptr += 4;
4745         } else {
4746             lock_ConvertWToR(&scp->rw);
4747             attr = smb_Attributes(scp);
4748             /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4749             if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4750                 attr |= SMB_ATTR_HIDDEN;
4751             *dptr++ = attr;
4752
4753             /* get dos time */
4754             cm_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4755
4756             /* copy out time */
4757             shortTemp = (unsigned short) (dosTime & 0xffff);
4758             *((u_short *)dptr) = shortTemp;
4759             dptr += 2;
4760
4761             /* and copy out date */
4762             shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4763             *((u_short *)dptr) = shortTemp;
4764             dptr += 2;
4765
4766             /* copy out file length */
4767             *((u_long *)dptr) = scp->length.LowPart;
4768             dptr += 4;
4769             lock_ReleaseRead(&scp->rw);
4770         }
4771         cm_ReleaseSCache(scp);
4772     }
4773
4774     /* now free the patches */
4775     for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4776         npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4777         free(patchp);
4778     }
4779
4780     /* and mark the list as empty */
4781     *dirPatchespp = NULL;
4782
4783   cleanup:
4784     return code;
4785 }
4786
4787 /* SMB_COM_SEARCH */
4788 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4789 {
4790     int attribute;
4791     long nextCookie;
4792     unsigned char *tp;
4793     long code = 0;
4794     clientchar_t *pathp;
4795     cm_dirEntry_t *dep = 0;
4796     int maxCount;
4797     smb_dirListPatch_t *dirListPatchesp;
4798     smb_dirListPatch_t *curPatchp;
4799     int dataLength;
4800     cm_buf_t *bufferp;
4801     long temp;
4802     osi_hyper_t dirLength;
4803     osi_hyper_t bufferOffset;
4804     osi_hyper_t curOffset;
4805     osi_hyper_t thyper;
4806     unsigned char *inCookiep;
4807     smb_dirSearch_t *dsp;
4808     cm_scache_t *scp;
4809     long entryInDir;
4810     long entryInBuffer;
4811     unsigned long clientCookie;
4812     cm_pageHeader_t *pageHeaderp;
4813     cm_user_t *userp = NULL;
4814     int slotInPage;
4815     clientchar_t mask[12];
4816     int returnedNames;
4817     long nextEntryCookie;
4818     int numDirChunks;           /* # of 32 byte dir chunks in this entry */
4819     char resByte;               /* reserved byte from the cookie */
4820     char *op;                   /* output data ptr */
4821     char *origOp;               /* original value of op */
4822     cm_space_t *spacep;         /* for pathname buffer */
4823     int starPattern;
4824     int rootPath = 0;
4825     int caseFold;
4826     clientchar_t *tidPathp = 0;
4827     cm_req_t req;
4828     cm_fid_t fid;
4829     int fileType;
4830
4831     smb_InitReq(&req);
4832
4833     maxCount = smb_GetSMBParm(inp, 0);
4834
4835     dirListPatchesp = NULL;
4836
4837     caseFold = CM_FLAG_CASEFOLD;
4838
4839     tp = smb_GetSMBData(inp, NULL);
4840     pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4841                                 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4842     if (!pathp)
4843         return CM_ERROR_BADSMB;
4844
4845     inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4846     if (!tp)
4847         return CM_ERROR_BADSMB;
4848
4849     /* We can handle long names */
4850     if (vcp->flags & SMB_VCFLAG_USENT)
4851         ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4852
4853     /* make sure we got a whole search status */
4854     if (dataLength < 21) {
4855         nextCookie = 0;         /* start at the beginning of the dir */
4856         resByte = 0;
4857         clientCookie = 0;
4858         attribute = smb_GetSMBParm(inp, 1);
4859
4860         /* handle volume info in another function */
4861         if (attribute & 0x8)
4862             return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4863
4864         osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4865                  maxCount, osi_LogSaveClientString(smb_logp, pathp));
4866
4867         if (*pathp == 0) {      /* null pathp, treat as root dir */
4868             if (!(attribute & SMB_ATTR_DIRECTORY))      /* exclude dirs */
4869                 return CM_ERROR_NOFILES;
4870             rootPath = 1;
4871         }
4872
4873         dsp = smb_NewDirSearch(0);
4874         dsp->attribute = attribute;
4875         smb_Get8Dot3MaskFromPath(mask, pathp);
4876         memcpy(dsp->mask, mask, 12);
4877
4878         /* track if this is likely to match a lot of entries */
4879         if (smb_Is8Dot3StarMask(mask))
4880             starPattern = 1;
4881         else
4882             starPattern = 0;
4883     } else {
4884         /* pull the next cookie value out of the search status block */
4885         nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4886             + (inCookiep[16]<<24);
4887         dsp = smb_FindDirSearch(inCookiep[12]);
4888         if (!dsp) {
4889             /* can't find dir search status; fatal error */
4890             osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4891                      inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4892             return CM_ERROR_BADFD;
4893         }
4894         attribute = dsp->attribute;
4895         resByte = inCookiep[0];
4896
4897         /* copy out client cookie, in host byte order.  Don't bother
4898          * interpreting it, since we're just passing it through, anyway.
4899          */
4900         memcpy(&clientCookie, &inCookiep[17], 4);
4901
4902         memcpy(mask, dsp->mask, 12);
4903
4904         /* assume we're doing a star match if it has continued for more
4905          * than one call.
4906          */
4907         starPattern = 1;
4908     }
4909
4910     osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4911              nextCookie, dsp->cookie, attribute);
4912
4913     userp = smb_GetUserFromVCP(vcp, inp);
4914
4915     /* try to get the vnode for the path name next */
4916     lock_ObtainMutex(&dsp->mx);
4917     if (dsp->scp) {
4918         scp = dsp->scp;
4919         osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4920         cm_HoldSCache(scp);
4921         code = 0;
4922     } else {
4923         spacep = inp->spacep;
4924         smb_StripLastComponent(spacep->wdata, NULL, pathp);
4925         code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4926         if (code) {
4927             lock_ReleaseMutex(&dsp->mx);
4928             cm_ReleaseUser(userp);
4929             smb_DeleteDirSearch(dsp);
4930             smb_ReleaseDirSearch(dsp);
4931             return CM_ERROR_NOFILES;
4932         }
4933         cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4934         cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4935
4936         code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
4937                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4938         if (code == 0) {
4939 #ifdef DFS_SUPPORT
4940             if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4941                 int pnc;
4942
4943                 pnc  = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4944                 cm_ReleaseSCache(scp);
4945                 lock_ReleaseMutex(&dsp->mx);
4946                 cm_ReleaseUser(userp);
4947                 smb_DeleteDirSearch(dsp);
4948                 smb_ReleaseDirSearch(dsp);
4949                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4950                     return CM_ERROR_PATH_NOT_COVERED;
4951                 else
4952                     return CM_ERROR_NOSUCHPATH;
4953             }
4954 #endif /* DFS_SUPPORT */
4955
4956             dsp->scp = scp;
4957             osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4958             /* we need one hold for the entry we just stored into,
4959              * and one for our own processing.  When we're done with this
4960              * function, we'll drop the one for our own processing.
4961              * We held it once from the namei call, and so we do another hold
4962              * now.
4963              */
4964             cm_HoldSCache(scp);
4965             lock_ObtainWrite(&scp->rw);
4966             dsp->flags |= SMB_DIRSEARCH_BULKST;
4967             lock_ReleaseWrite(&scp->rw);
4968         }
4969     }
4970     lock_ReleaseMutex(&dsp->mx);
4971     if (code) {
4972         cm_ReleaseUser(userp);
4973         smb_DeleteDirSearch(dsp);
4974         smb_ReleaseDirSearch(dsp);
4975         return code;
4976     }
4977
4978     /* reserves space for parameter; we'll adjust it again later to the
4979      * real count of the # of entries we returned once we've actually
4980      * assembled the directory listing.
4981      */
4982     smb_SetSMBParm(outp, 0, 0);
4983
4984     /* get the directory size */
4985     lock_ObtainWrite(&scp->rw);
4986     code = cm_SyncOp(scp, NULL, userp, &req, 0,
4987                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4988     if (code) {
4989         lock_ReleaseWrite(&scp->rw);
4990         cm_ReleaseSCache(scp);
4991         cm_ReleaseUser(userp);
4992         smb_DeleteDirSearch(dsp);
4993         smb_ReleaseDirSearch(dsp);
4994         return code;
4995     }
4996
4997     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4998
4999     dirLength = scp->length;
5000     bufferp = NULL;
5001     bufferOffset.LowPart = bufferOffset.HighPart = 0;
5002     curOffset.HighPart = 0;
5003     curOffset.LowPart = nextCookie;
5004     origOp = op = smb_GetSMBData(outp, NULL);
5005     /* and write out the basic header */
5006     *op++ = 5;          /* variable block */
5007     op += 2;            /* skip vbl block length; we'll fill it in later */
5008     code = 0;
5009     returnedNames = 0;
5010     while (1) {
5011         clientchar_t *actualName = NULL;
5012         int           free_actualName = 0;
5013         clientchar_t shortName[13];
5014         clientchar_t *shortNameEnd;
5015
5016         /* make sure that curOffset.LowPart doesn't point to the first
5017          * 32 bytes in the 2nd through last dir page, and that it doesn't
5018          * point at the first 13 32-byte chunks in the first dir page,
5019          * since those are dir and page headers, and don't contain useful
5020          * information.
5021          */
5022         temp = curOffset.LowPart & (2048-1);
5023         if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
5024             /* we're in the first page */
5025             if (temp < 13*32) temp = 13*32;
5026         }
5027         else {
5028             /* we're in a later dir page */
5029             if (temp < 32) temp = 32;
5030         }
5031
5032         /* make sure the low order 5 bits are zero */
5033         temp &= ~(32-1);
5034
5035         /* now put temp bits back ito curOffset.LowPart */
5036         curOffset.LowPart &= ~(2048-1);
5037         curOffset.LowPart |= temp;
5038
5039         /* check if we've returned all the names that will fit in the
5040          * response packet.
5041          */
5042         if (returnedNames >= maxCount) {
5043             osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
5044                       returnedNames, maxCount);
5045             break;
5046         }
5047
5048         /* check if we've passed the dir's EOF */
5049         if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
5050
5051         /* see if we can use the bufferp we have now; compute in which page
5052          * the current offset would be, and check whether that's the offset
5053          * of the buffer we have.  If not, get the buffer.
5054          */
5055         thyper.HighPart = curOffset.HighPart;
5056         thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
5057         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
5058             /* wrong buffer */
5059             if (bufferp) {
5060                 buf_Release(bufferp);
5061                 bufferp = NULL;
5062             }
5063             lock_ReleaseWrite(&scp->rw);
5064             code = buf_Get(scp, &thyper, &req, &bufferp);
5065             lock_ObtainMutex(&dsp->mx);
5066
5067             /* now, if we're doing a star match, do bulk fetching of all of
5068              * the status info for files in the dir.
5069              */
5070             if (starPattern)
5071                 smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5072
5073             lock_ObtainWrite(&scp->rw);
5074             lock_ReleaseMutex(&dsp->mx);
5075             if (code) {
5076                 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
5077                 break;
5078             }
5079
5080             bufferOffset = thyper;
5081
5082             /* now get the data in the cache */
5083             while (1) {
5084                 code = cm_SyncOp(scp, bufferp, userp, &req,
5085                                  PRSFS_LOOKUP,
5086                                  CM_SCACHESYNC_NEEDCALLBACK |
5087                                  CM_SCACHESYNC_READ);
5088                 if (code) {
5089                     osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
5090                     break;
5091                 }
5092
5093                 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
5094
5095                 if (cm_HaveBuffer(scp, bufferp, 0)) {
5096                     osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
5097                     break;
5098                 }
5099
5100                 /* otherwise, load the buffer and try again */
5101                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
5102                 if (code) {
5103                     osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
5104                               scp, bufferp, code);
5105                     break;
5106                 }
5107             }
5108             if (code) {
5109                 buf_Release(bufferp);
5110                 bufferp = NULL;
5111                 break;
5112             }
5113         }       /* if (wrong buffer) ... */
5114
5115         /* now we have the buffer containing the entry we're interested in; copy
5116          * it out if it represents a non-deleted entry.
5117          */
5118         entryInDir = curOffset.LowPart & (2048-1);
5119         entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
5120
5121         /* page header will help tell us which entries are free.  Page header
5122          * can change more often than once per buffer, since AFS 3 dir page size
5123          * may be less than (but not more than a buffer package buffer.
5124          */
5125         temp = curOffset.LowPart & (cm_data.buf_blockSize - 1);  /* only look intra-buffer */
5126         temp &= ~(2048 - 1);    /* turn off intra-page bits */
5127         pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
5128
5129         /* now determine which entry we're looking at in the page.  If it is
5130          * free (there's a free bitmap at the start of the dir), we should
5131          * skip these 32 bytes.
5132          */
5133         slotInPage = (entryInDir & 0x7e0) >> 5;
5134         if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
5135             /* this entry is free */
5136             numDirChunks = 1;           /* only skip this guy */
5137             goto nextEntry;
5138         }
5139
5140         tp = bufferp->datap + entryInBuffer;
5141         dep = (cm_dirEntry_t *) tp;             /* now points to AFS3 dir entry */
5142
5143         /* while we're here, compute the next entry's location, too,
5144          * since we'll need it when writing out the cookie into the dir
5145          * listing stream.
5146          *
5147          * XXXX Probably should do more sanity checking.
5148          */
5149         numDirChunks = cm_NameEntries(dep->name, NULL);
5150
5151         /* compute the offset of the cookie representing the next entry */
5152         nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
5153
5154         /* Compute 8.3 name if necessary */
5155         actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
5156         if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
5157             if (actualName)
5158                 free(actualName);
5159             cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
5160             actualName = shortName;
5161             free_actualName = 0;
5162         } else {
5163             free_actualName = 1;
5164         }
5165
5166         if (actualName == NULL) {
5167             /* Couldn't convert the name for some reason */
5168             osi_Log1(smb_logp, "SMB search dir skipping entry :[%s]",
5169                      osi_LogSaveString(smb_logp, dep->name));
5170             goto nextEntry;
5171         }
5172
5173         osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
5174                  dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
5175                  osi_LogSaveClientString(smb_logp, actualName));
5176
5177         if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
5178             /* this is one of the entries to use: it is not deleted
5179              * and it matches the star pattern we're looking for.
5180              */
5181
5182             /* Eliminate entries that don't match requested
5183              * attributes */
5184
5185             /* no hidden files */
5186             if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
5187                 osi_Log0(smb_logp, "SMB search dir skipping hidden");
5188                 goto nextEntry;
5189             }
5190
5191             if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
5192             {
5193                 /* We have already done the cm_TryBulkStat above */
5194                 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5195                 fileType = cm_FindFileType(&fid);
5196                 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
5197                          "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
5198                           fileType);
5199                 if (fileType == CM_SCACHETYPE_DIRECTORY ||
5200                     fileType == CM_SCACHETYPE_MOUNTPOINT ||
5201                     fileType == CM_SCACHETYPE_DFSLINK ||
5202                     fileType == CM_SCACHETYPE_INVALID)
5203                     osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
5204                 goto nextEntry;
5205             }
5206
5207             *op++ = resByte;
5208             memcpy(op, mask, 11); op += 11;
5209             *op++ = (unsigned char) dsp->cookie;        /* they say it must be non-zero */
5210             *op++ = (unsigned char)(nextEntryCookie & 0xff);
5211             *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
5212             *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
5213             *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
5214             memcpy(op, &clientCookie, 4); op += 4;
5215
5216             /* now we emit the attribute.  This is sort of tricky,
5217              * since we need to really stat the file to find out
5218              * what type of entry we've got.  Right now, we're
5219              * copying out data from a buffer, while holding the
5220              * scp locked, so it isn't really convenient to stat
5221              * something now.  We'll put in a place holder now,
5222              * and make a second pass before returning this to get
5223              * the real attributes.  So, we just skip the data for
5224              * now, and adjust it later.  We allocate a patch
5225              * record to make it easy to find this point later.
5226              * The replay will happen at a time when it is safe to
5227              * unlock the directory.
5228              */
5229             curPatchp = malloc(sizeof(*curPatchp));
5230             osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
5231             curPatchp->dptr = op;
5232             cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
5233
5234             /* do hidden attribute here since name won't be around when applying
5235              * dir list patches
5236              */
5237
5238             if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
5239                 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
5240             else
5241                 curPatchp->flags = 0;
5242
5243             op += 9;    /* skip attr, time, date and size */
5244
5245             /* zero out name area.  The spec says to pad with
5246              * spaces, but Samba doesn't, and neither do we.
5247              */
5248             memset(op, 0, 13);
5249
5250             /* finally, we get to copy out the name; we know that
5251              * it fits in 8.3 or the pattern wouldn't match, but it
5252              * never hurts to be sure.
5253              */
5254             cm_ClientStringToUtf8(actualName, -1, op, 13);
5255             if (smb_StoreAnsiFilenames)
5256                 CharToOem(op, op);
5257             /* This is a UCHAR field, which is ASCII even if Unicode
5258                is negotiated. */
5259
5260             /* Uppercase if requested by client */
5261             if (!KNOWS_LONG_NAMES(inp))
5262                 _strupr(op);
5263
5264             op += 13;
5265
5266             /* now, adjust the # of entries copied */
5267             returnedNames++;
5268         }       /* if we're including this name */
5269
5270       nextEntry:
5271         if (free_actualName && actualName) {
5272             free(actualName);
5273             actualName = NULL;
5274         }
5275
5276         /* and adjust curOffset to be where the new cookie is */
5277         thyper.HighPart = 0;
5278         thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
5279         curOffset = LargeIntegerAdd(thyper, curOffset);
5280     }           /* while copying data for dir listing */
5281
5282     /* release the mutex */
5283     lock_ReleaseWrite(&scp->rw);
5284     if (bufferp) {
5285         buf_Release(bufferp);
5286         bufferp = NULL;
5287     }
5288
5289     /* apply and free last set of patches; if not doing a star match, this
5290      * will be empty, but better safe (and freeing everything) than sorry.
5291      */
5292     smb_ApplyDirListPatches(scp, &dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
5293
5294     /* special return code for unsuccessful search */
5295     if (code == 0 && dataLength < 21 && returnedNames == 0)
5296         code = CM_ERROR_NOFILES;
5297
5298     osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
5299              returnedNames, code);
5300
5301     if (code != 0) {
5302         smb_DeleteDirSearch(dsp);
5303         smb_ReleaseDirSearch(dsp);
5304         cm_ReleaseSCache(scp);
5305         cm_ReleaseUser(userp);
5306         return code;
5307     }
5308
5309     /* finalize the output buffer */
5310     smb_SetSMBParm(outp, 0, returnedNames);
5311     temp = (long) (op - origOp);
5312     smb_SetSMBDataLength(outp, temp);
5313
5314     /* the data area is a variable block, which has a 5 (already there)
5315      * followed by the length of the # of data bytes.  We now know this to
5316      * be "temp," although that includes the 3 bytes of vbl block header.
5317      * Deduct for them and fill in the length field.
5318      */
5319     temp -= 3;          /* deduct vbl block info */
5320     osi_assertx(temp == (43 * returnedNames), "unexpected data length");
5321     origOp[1] = (unsigned char)(temp & 0xff);
5322     origOp[2] = (unsigned char)((temp>>8) & 0xff);
5323     if (returnedNames == 0)
5324         smb_DeleteDirSearch(dsp);
5325     smb_ReleaseDirSearch(dsp);
5326     cm_ReleaseSCache(scp);
5327     cm_ReleaseUser(userp);
5328     return code;
5329 }
5330
5331
5332 /* verify that this is a valid path to a directory.  I don't know why they
5333  * don't use the get file attributes call.
5334  *
5335  * SMB_COM_CHECK_DIRECTORY
5336  */
5337 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5338 {
5339     clientchar_t *pathp;
5340     long code = 0;
5341     cm_scache_t *rootScp;
5342     cm_scache_t *newScp;
5343     cm_user_t *userp;
5344     unsigned int attrs;
5345     int caseFold;
5346     clientchar_t *tidPathp;
5347     cm_req_t req;
5348     char * pdata;
5349
5350     smb_InitReq(&req);
5351
5352     pdata = smb_GetSMBData(inp, NULL);
5353     pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
5354     if (!pathp)
5355         return CM_ERROR_BADSMB;
5356     osi_Log1(smb_logp, "SMB receive check path %S",
5357              osi_LogSaveClientString(smb_logp, pathp));
5358
5359     userp = smb_GetUserFromVCP(vcp, inp);
5360
5361     rootScp = cm_RootSCachep(userp, &req);
5362
5363     caseFold = CM_FLAG_CASEFOLD;
5364
5365     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5366     if (code) {
5367         cm_ReleaseUser(userp);
5368         return CM_ERROR_NOSUCHPATH;
5369     }
5370     code = cm_NameI(rootScp, pathp,
5371                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5372                     userp, tidPathp, &req, &newScp);
5373
5374     if (code) {
5375         cm_ReleaseUser(userp);
5376         return code;
5377     }
5378
5379 #ifdef DFS_SUPPORT
5380     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5381         int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5382         cm_ReleaseSCache(newScp);
5383         cm_ReleaseUser(userp);
5384         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5385             return CM_ERROR_PATH_NOT_COVERED;
5386         else
5387             return CM_ERROR_NOSUCHPATH;
5388     }
5389 #endif /* DFS_SUPPORT */
5390
5391     /* now lock the vnode with a callback; returns with newScp locked */
5392     lock_ObtainWrite(&newScp->rw);
5393     code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
5394                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5395     if (code) {
5396         if (code != CM_ERROR_NOACCESS) {
5397             lock_ReleaseWrite(&newScp->rw);
5398             cm_ReleaseSCache(newScp);
5399             cm_ReleaseUser(userp);
5400             return code;
5401         }
5402     } else {
5403         cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5404     }
5405
5406     attrs = smb_Attributes(newScp);
5407
5408     if (!(attrs & SMB_ATTR_DIRECTORY))
5409         code = CM_ERROR_NOTDIR;
5410
5411     lock_ReleaseWrite(&newScp->rw);
5412
5413     cm_ReleaseSCache(newScp);
5414     cm_ReleaseUser(userp);
5415     return code;
5416 }
5417
5418 /* SMB_COM_SET_INFORMATION */
5419 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5420 {
5421     clientchar_t *pathp;
5422     long code = 0;
5423     cm_scache_t *rootScp;
5424     unsigned short attribute;
5425     cm_attr_t attr;
5426     cm_scache_t *newScp;
5427     afs_uint32 dosTime;
5428     cm_user_t *userp;
5429     int caseFold;
5430     clientchar_t *tidPathp;
5431     char * datap;
5432     cm_req_t req;
5433
5434     smb_InitReq(&req);
5435
5436     /* decode basic attributes we're passed */
5437     attribute = smb_GetSMBParm(inp, 0);
5438     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5439
5440     datap = smb_GetSMBData(inp, NULL);
5441     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5442     if (!pathp)
5443         return CM_ERROR_BADSMB;
5444
5445     osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
5446              dosTime, attribute);
5447
5448     userp = smb_GetUserFromVCP(vcp, inp);
5449
5450     rootScp = cm_RootSCachep(userp, &req);
5451
5452     caseFold = CM_FLAG_CASEFOLD;
5453
5454     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5455     if (code) {
5456         cm_ReleaseUser(userp);
5457         return CM_ERROR_NOSUCHFILE;
5458     }
5459     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5460                     tidPathp, &req, &newScp);
5461
5462     if (code) {
5463         cm_ReleaseUser(userp);
5464         return code;
5465     }
5466
5467 #ifdef DFS_SUPPORT
5468     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5469         int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5470         cm_ReleaseSCache(newScp);
5471         cm_ReleaseUser(userp);
5472         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5473             return CM_ERROR_PATH_NOT_COVERED;
5474         else
5475             return CM_ERROR_NOSUCHPATH;
5476     }
5477 #endif /* DFS_SUPPORT */
5478
5479     /* now lock the vnode with a callback; returns with newScp locked; we
5480      * need the current status to determine what the new status is, in some
5481      * cases.
5482      */
5483     lock_ObtainWrite(&newScp->rw);
5484     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5485                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5486     if (code) {
5487         lock_ReleaseWrite(&newScp->rw);
5488         cm_ReleaseSCache(newScp);
5489         cm_ReleaseUser(userp);
5490         return code;
5491     }
5492
5493     cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5494
5495     /* Check for RO volume */
5496     if (newScp->flags & CM_SCACHEFLAG_RO) {
5497         lock_ReleaseWrite(&newScp->rw);
5498         cm_ReleaseSCache(newScp);
5499         cm_ReleaseUser(userp);
5500         return CM_ERROR_READONLY;
5501     }
5502
5503     /* prepare for setattr call */
5504     attr.mask = 0;
5505     if (dosTime != 0) {
5506         attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
5507         smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
5508     }
5509     if ((newScp->unixModeBits & 0200) && (attribute & SMB_ATTR_READONLY) != 0) {
5510         /* we're told to make a writable file read-only */
5511         attr.unixModeBits = newScp->unixModeBits & ~0222;
5512         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5513     }
5514     else if ((newScp->unixModeBits & 0200) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
5515         /* we're told to make a read-only file writable */
5516         attr.unixModeBits = newScp->unixModeBits | 0222;
5517         attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
5518     }
5519     lock_ReleaseWrite(&newScp->rw);
5520
5521     /* now call setattr */
5522     if (attr.mask)
5523         code = cm_SetAttr(newScp, &attr, userp, &req);
5524     else
5525         code = 0;
5526
5527     cm_ReleaseSCache(newScp);
5528     cm_ReleaseUser(userp);
5529
5530     return code;
5531 }
5532
5533
5534 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5535 {
5536     clientchar_t *pathp;
5537     long code = 0;
5538     cm_scache_t *rootScp;
5539     cm_scache_t *newScp, *dscp;
5540     afs_uint32 dosTime;
5541     int attrs;
5542     cm_user_t *userp;
5543     int caseFold;
5544     clientchar_t *tidPathp;
5545     cm_space_t *spacep;
5546     clientchar_t *lastComp;
5547     char * datap;
5548     cm_req_t req;
5549
5550     smb_InitReq(&req);
5551
5552     datap = smb_GetSMBData(inp, NULL);
5553     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5554     if (!pathp)
5555         return CM_ERROR_BADSMB;
5556
5557     if (*pathp == 0)            /* null path */
5558         pathp = _C("\\");
5559
5560     osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
5561              osi_LogSaveClientString(smb_logp, pathp));
5562
5563     userp = smb_GetUserFromVCP(vcp, inp);
5564
5565     rootScp = cm_RootSCachep(userp, &req);
5566
5567     /* we shouldn't need this for V3 requests, but we seem to */
5568     caseFold = CM_FLAG_CASEFOLD;
5569
5570     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5571     if (code) {
5572         cm_ReleaseUser(userp);
5573         return CM_ERROR_NOSUCHFILE;
5574     }
5575
5576     /*
5577      * XXX Strange hack XXX
5578      *
5579      * As of Patch 5 (16 July 97), we are having the following problem:
5580      * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5581      * requests to look up "desktop.ini" in all the subdirectories.
5582      * This can cause zillions of timeouts looking up non-existent cells
5583      * and volumes, especially in the top-level directory.
5584      *
5585      * We have not found any way to avoid this or work around it except
5586      * to explicitly ignore the requests for mount points that haven't
5587      * yet been evaluated and for directories that haven't yet been
5588      * fetched.
5589      *
5590      * We should modify this hack to provide a fake desktop.ini file
5591      * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5592      */
5593     spacep = inp->spacep;
5594     smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5595 #ifndef SPECIAL_FOLDERS
5596     if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5597         code = cm_NameI(rootScp, spacep->wdata,
5598                         caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5599                         userp, tidPathp, &req, &dscp);
5600         if (code == 0) {
5601 #ifdef DFS_SUPPORT
5602             if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5603                 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5604                                                           spacep->wdata);
5605                 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5606                     return CM_ERROR_PATH_NOT_COVERED;
5607                 else
5608                     return CM_ERROR_NOSUCHPATH;
5609             } else
5610 #endif /* DFS_SUPPORT */
5611             if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5612                 code = CM_ERROR_NOSUCHFILE;
5613             else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5614                 cm_buf_t *bp = buf_Find(&dscp->fid, &hzero);
5615                 if (bp) {
5616                     buf_Release(bp);
5617                     bp = NULL;
5618                 } else
5619                     code = CM_ERROR_NOSUCHFILE;
5620             }
5621             cm_ReleaseSCache(dscp);
5622             if (code) {
5623                 cm_ReleaseUser(userp);
5624                 return code;
5625             }
5626         }
5627         else if (code != CM_ERROR_NOSUCHFILE &&
5628                  code != CM_ERROR_NOSUCHPATH &&
5629                  code != CM_ERROR_BPLUS_NOMATCH)
5630         {
5631             cm_ReleaseUser(userp);
5632             return code;
5633         }
5634     }
5635 #endif /* SPECIAL_FOLDERS */
5636
5637     code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5638                     tidPathp, &req, &newScp);
5639     if (code) {
5640         cm_ReleaseUser(userp);
5641         return code;
5642     }
5643
5644 #ifdef DFS_SUPPORT
5645     if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5646         int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5647         cm_ReleaseSCache(newScp);
5648         cm_ReleaseUser(userp);
5649         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5650             return CM_ERROR_PATH_NOT_COVERED;
5651         else
5652             return CM_ERROR_NOSUCHPATH;
5653     }
5654 #endif /* DFS_SUPPORT */
5655
5656     /* now lock the vnode with a callback; returns with newScp locked */
5657     lock_ObtainWrite(&newScp->rw);
5658     code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5659                      CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5660     if (code) {
5661         lock_ReleaseWrite(&newScp->rw);
5662         cm_ReleaseSCache(newScp);
5663         cm_ReleaseUser(userp);
5664         return code;
5665     }
5666
5667     cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5668
5669     attrs = smb_Attributes(newScp);
5670
5671     smb_SetSMBParm(outp, 0, attrs);
5672
5673     smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5674     smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5675     smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5676     smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5677     smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5678     smb_SetSMBParm(outp, 5, 0);
5679     smb_SetSMBParm(outp, 6, 0);
5680     smb_SetSMBParm(outp, 7, 0);
5681     smb_SetSMBParm(outp, 8, 0);
5682     smb_SetSMBParm(outp, 9, 0);
5683     smb_SetSMBDataLength(outp, 0);
5684     lock_ReleaseWrite(&newScp->rw);
5685
5686     cm_ReleaseSCache(newScp);
5687     cm_ReleaseUser(userp);
5688
5689     return 0;
5690 }
5691
5692 /* SMB_COM_TREE_DISCONNECT */
5693 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5694 {
5695     smb_tid_t *tidp;
5696
5697     osi_Log0(smb_logp, "SMB receive tree disconnect");
5698
5699     /* find the tree and free it */
5700     tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5701     if (tidp) {
5702         lock_ObtainWrite(&smb_rctLock);
5703         tidp->deleteOk = 1;
5704         smb_ReleaseTID(tidp, TRUE);
5705         lock_ReleaseWrite(&smb_rctLock);
5706     }
5707
5708     return 0;
5709 }
5710
5711 /* SMB_COM_0PEN */
5712 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5713 {
5714     smb_fid_t *fidp;
5715     clientchar_t *pathp;
5716     clientchar_t *lastNamep;
5717     int share;
5718     int attribute;
5719     long code = 0;
5720     cm_user_t *userp;
5721     cm_scache_t *scp;
5722     afs_uint32 dosTime;
5723     int caseFold;
5724     cm_space_t *spacep;
5725     clientchar_t *tidPathp;
5726     char * datap;
5727     cm_req_t req;
5728
5729     smb_InitReq(&req);
5730
5731     datap = smb_GetSMBData(inp, NULL);
5732     pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5733     if (!pathp)
5734         return CM_ERROR_BADSMB;
5735
5736     osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5737
5738 #ifdef DEBUG_VERBOSE
5739     {
5740         char *hexpath;
5741
5742         hexpath = osi_HexifyString( pathp );
5743         DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5744         free(hexpath);
5745     }
5746 #endif
5747
5748     share = smb_GetSMBParm(inp, 0);
5749     attribute = smb_GetSMBParm(inp, 1);
5750
5751     spacep = inp->spacep;
5752     /* smb_StripLastComponent will strip "::$DATA" if present */
5753     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5754
5755     if (!cm_IsValidClientString(pathp)) {
5756 #ifdef DEBUG
5757         clientchar_t * hexp;
5758
5759         hexp = cm_GetRawCharsAlloc(pathp, -1);
5760         osi_Log1(smb_logp, "CoreOpen rejecting invalid name. [%S]",
5761                  osi_LogSaveClientString(smb_logp, hexp));
5762         if (hexp)
5763             free(hexp);
5764 #else
5765         osi_Log0(smb_logp, "CoreOpen rejecting invalid name");
5766 #endif
5767         return CM_ERROR_BADNTFILENAME;
5768     }
5769
5770     if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5771         /* special case magic file name for receiving IOCTL requests
5772          * (since IOCTL calls themselves aren't getting through).
5773          */
5774         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5775         smb_SetupIoctlFid(fidp, spacep);
5776         smb_SetSMBParm(outp, 0, fidp->fid);
5777         smb_SetSMBParm(outp, 1, 0);     /* attrs */
5778         smb_SetSMBParm(outp, 2, 0);     /* next 2 are DOS time */
5779         smb_SetSMBParm(outp, 3, 0);
5780         smb_SetSMBParm(outp, 4, 0);     /* next 2 are length */
5781         smb_SetSMBParm(outp, 5, 0x7fff);
5782         /* pass the open mode back */
5783         smb_SetSMBParm(outp, 6, (share & 0xf));
5784         smb_SetSMBDataLength(outp, 0);
5785         smb_ReleaseFID(fidp);
5786         return 0;
5787     }
5788
5789     userp = smb_GetUserFromVCP(vcp, inp);
5790
5791     caseFold = CM_FLAG_CASEFOLD;
5792
5793     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5794     if (code) {
5795         cm_ReleaseUser(userp);
5796         return CM_ERROR_NOSUCHPATH;
5797     }
5798     code = cm_NameI(cm_RootSCachep(userp, &req), pathp, caseFold | CM_FLAG_FOLLOW, userp,
5799                     tidPathp, &req, &scp);
5800
5801     if (code) {
5802         cm_ReleaseUser(userp);
5803         return code;
5804     }
5805
5806 #ifdef DFS_SUPPORT
5807     if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5808         int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5809         cm_ReleaseSCache(scp);
5810         cm_ReleaseUser(userp);
5811         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5812             return CM_ERROR_PATH_NOT_COVERED;
5813         else
5814             return CM_ERROR_NOSUCHPATH;
5815     }
5816 #endif /* DFS_SUPPORT */
5817
5818     code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5819     if (code) {
5820         cm_ReleaseSCache(scp);
5821         cm_ReleaseUser(userp);
5822         return code;
5823     }
5824
5825     /* don't need callback to check file type, since file types never
5826      * change, and namei and cm_Lookup all stat the object at least once on
5827      * a successful return.
5828      */
5829     if (scp->fileType != CM_SCACHETYPE_FILE) {
5830         cm_ReleaseSCache(scp);
5831         cm_ReleaseUser(userp);
5832         return CM_ERROR_ISDIR;
5833     }
5834
5835     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5836     osi_assertx(fidp, "null smb_fid_t");
5837
5838     lock_ObtainMutex(&fidp->mx);
5839     if ((share & 0xf) == 0)
5840         fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5841     else if ((share & 0xf) == 1)
5842         fidp->flags |= SMB_FID_OPENWRITE;
5843     else
5844         fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5845
5846     /* save the  user */
5847     cm_HoldUser(userp);
5848     fidp->userp = userp;
5849
5850     /* and a pointer to the vnode */
5851     fidp->scp = scp;
5852     osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5853     lock_ObtainWrite(&scp->rw);
5854     scp->flags |= CM_SCACHEFLAG_SMB_FID;
5855
5856     smb_SetSMBParm(outp, 0, fidp->fid);
5857     smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5858     smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5859     smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5860     smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5861     smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5862     smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5863     /* pass the open mode back; XXXX add access checks */
5864     smb_SetSMBParm(outp, 6, (share & 0xf));
5865     smb_SetSMBDataLength(outp, 0);
5866         lock_ReleaseMutex(&fidp->mx);
5867     lock_ReleaseRead(&scp->rw);
5868
5869     /* notify open */
5870     cm_Open(scp, 0, userp);
5871
5872     /* send and free packet */
5873     smb_ReleaseFID(fidp);
5874     cm_ReleaseUser(userp);
5875     /* don't release scp, since we've squirreled away the pointer in the fid struct */
5876     return 0;
5877 }
5878
5879 typedef struct smb_unlinkRock {
5880     cm_scache_t *dscp;
5881     cm_user_t *userp;
5882     cm_req_t *reqp;
5883     smb_vc_t *vcp;
5884     clientchar_t *maskp;                /* pointer to the star pattern */
5885     int flags;
5886     int any;
5887     cm_dirEntryList_t * matches;
5888 } smb_unlinkRock_t;
5889
5890 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5891 {
5892     long code = 0;
5893     smb_unlinkRock_t *rockp;
5894     int caseFold;
5895     int match;
5896     normchar_t matchName[MAX_PATH];
5897
5898     rockp = vrockp;
5899
5900     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5901     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5902         caseFold |= CM_FLAG_8DOT3;
5903
5904     if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
5905         /* Can't convert name */
5906         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string.",
5907                  osi_LogSaveString(smb_logp, dep->name));
5908         return 0;
5909     }
5910
5911     match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5912     if (!match &&
5913         (rockp->flags & SMB_MASKFLAG_TILDE) &&
5914         !cm_Is8Dot3(matchName)) {
5915         cm_Gen8Dot3Name(dep, matchName, NULL);
5916         /* 8.3 matches are always case insensitive */
5917         match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5918     }
5919     if (match) {
5920         osi_Log1(smb_logp, "Found match %S",
5921                  osi_LogSaveClientString(smb_logp, matchName));
5922
5923         cm_DirEntryListAdd(dep->name, &rockp->matches);
5924
5925         rockp->any = 1;
5926
5927         /* If we made a case sensitive exact match, we might as well quit now. */
5928         if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5929             code = CM_ERROR_STOPNOW;
5930         else
5931             code = 0;
5932     }
5933     else code = 0;
5934
5935     return code;
5936 }
5937
5938 /* SMB_COM_DELETE */
5939 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5940 {
5941     int attribute;
5942     long code = 0;
5943     clientchar_t *pathp;
5944     unsigned char *tp;
5945     cm_space_t *spacep;
5946     cm_scache_t *dscp;
5947     clientchar_t *lastNamep;
5948     smb_unlinkRock_t rock;
5949     cm_user_t *userp;
5950     osi_hyper_t thyper;
5951     int caseFold;
5952     clientchar_t *tidPathp;
5953     cm_req_t req;
5954
5955     smb_InitReq(&req);
5956     memset(&rock, 0, sizeof(rock));
5957
5958     attribute = smb_GetSMBParm(inp, 0);
5959
5960     tp = smb_GetSMBData(inp, NULL);
5961     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5962     if (!pathp)
5963         return CM_ERROR_BADSMB;
5964
5965     osi_Log1(smb_logp, "SMB receive unlink %S",
5966              osi_LogSaveClientString(smb_logp, pathp));
5967
5968     spacep = inp->spacep;
5969     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5970
5971     userp = smb_GetUserFromVCP(vcp, inp);
5972
5973     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5974
5975     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5976     if (code) {
5977         cm_ReleaseUser(userp);
5978         return CM_ERROR_NOSUCHPATH;
5979     }
5980     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold, userp, tidPathp,
5981                     &req, &dscp);
5982     if (code) {
5983         cm_ReleaseUser(userp);
5984         return code;
5985     }
5986
5987 #ifdef DFS_SUPPORT
5988     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5989         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5990         cm_ReleaseSCache(dscp);
5991         cm_ReleaseUser(userp);
5992         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5993             return CM_ERROR_PATH_NOT_COVERED;
5994         else
5995             return CM_ERROR_NOSUCHPATH;
5996     }
5997 #endif /* DFS_SUPPORT */
5998
5999     /* otherwise, scp points to the parent directory. */
6000     if (!lastNamep)
6001         lastNamep = pathp;
6002     else
6003         lastNamep++;
6004
6005     rock.any = 0;
6006     rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
6007     if (!rock.maskp) {
6008         code = CM_ERROR_NOSUCHFILE;
6009         goto done;
6010     }
6011     rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6012
6013     thyper.LowPart = 0;
6014     thyper.HighPart = 0;
6015     rock.userp = userp;
6016     rock.reqp = &req;
6017     rock.dscp = dscp;
6018     rock.vcp = vcp;
6019     rock.matches = NULL;
6020
6021     /* Now, if we aren't dealing with a wildcard match, we first try an exact
6022      * match.  If that fails, we do a case insensitve match.
6023      */
6024     if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
6025         !smb_IsStarMask(rock.maskp)) {
6026         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6027         if (!rock.any) {
6028             thyper.LowPart = 0;
6029             thyper.HighPart = 0;
6030             rock.flags |= SMB_MASKFLAG_CASEFOLD;
6031         }
6032     }
6033
6034     if (!rock.any)
6035         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
6036
6037     if (code == CM_ERROR_STOPNOW)
6038         code = 0;
6039
6040     if (code == 0 && rock.matches) {
6041         cm_dirEntryList_t * entry;
6042
6043         for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6044             normchar_t normalizedName[MAX_PATH];
6045
6046             /* Note: entry->name is a non-normalized name */
6047
6048             osi_Log1(smb_logp, "Unlinking %s",
6049                      osi_LogSaveString(smb_logp, entry->name));
6050
6051             /* We assume this works because entry->name was
6052                successfully converted in smb_UnlinkProc() once. */
6053             cm_FsStringToNormString(entry->name, -1,
6054                                     normalizedName, lengthof(normalizedName));
6055
6056             code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
6057
6058             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6059                 smb_NotifyChange(FILE_ACTION_REMOVED,
6060                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6061                                  dscp, normalizedName, NULL, TRUE);
6062         }
6063     }
6064
6065     cm_DirEntryListFree(&rock.matches);
6066
6067   done:
6068     if (userp)
6069     cm_ReleaseUser(userp);
6070
6071     if (dscp)
6072     cm_ReleaseSCache(dscp);
6073
6074     if (rock.maskp)
6075     free(rock.maskp);
6076
6077     if (code == 0 && !rock.any)
6078         code = CM_ERROR_NOSUCHFILE;
6079     return code;
6080 }
6081
6082 typedef struct smb_renameRock {
6083     cm_scache_t *odscp;  /* old dir */
6084     cm_scache_t *ndscp;  /* new dir */
6085     cm_user_t *userp;    /* user */
6086     cm_req_t *reqp;      /* request struct */
6087     smb_vc_t *vcp;       /* virtual circuit */
6088     normchar_t *maskp;   /* pointer to star pattern of old file name */
6089     int flags;           /* tilde, casefold, etc */
6090     clientchar_t *newNamep;     /* ptr to the new file's name */
6091     fschar_t fsOldName[MAX_PATH]; /* raw FS name */
6092     clientchar_t clOldName[MAX_PATH]; /* client name */
6093     int any;
6094 } smb_renameRock_t;
6095
6096 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6097 {
6098     long code = 0;
6099     smb_renameRock_t *rockp;
6100     int caseFold;
6101     int match;
6102     normchar_t matchName[MAX_PATH];
6103
6104     rockp = (smb_renameRock_t *) vrockp;
6105
6106     if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6107         /* Can't convert string */
6108         osi_Log1(smb_logp, "Skpping entry [%s]. Can't normalize FS string",
6109                  osi_LogSaveString(smb_logp, dep->name));
6110         return 0;
6111     }
6112
6113     caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
6114     if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
6115         caseFold |= CM_FLAG_8DOT3;
6116
6117     match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6118     if (!match &&
6119         (rockp->flags & SMB_MASKFLAG_TILDE) &&
6120         !cm_Is8Dot3(matchName)) {
6121         cm_Gen8Dot3Name(dep, matchName, NULL);
6122         match = cm_MatchMask(matchName, rockp->maskp, caseFold);
6123     }
6124
6125     if (match) {
6126         rockp->any = 1;
6127         StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
6128         cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
6129                         matchName);
6130         code = CM_ERROR_STOPNOW;
6131     } else {
6132         code = 0;
6133     }
6134
6135     return code;
6136 }
6137
6138
6139 long
6140 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
6141 {
6142     long code = 0;
6143     cm_space_t *spacep = NULL;
6144     smb_renameRock_t rock;
6145     cm_scache_t *oldDscp = NULL;
6146     cm_scache_t *newDscp = NULL;
6147     cm_scache_t *tmpscp= NULL;
6148     cm_scache_t *tmpscp2 = NULL;
6149     clientchar_t *oldLastNamep;
6150     clientchar_t *newLastNamep;
6151     osi_hyper_t thyper;
6152     cm_user_t *userp;
6153     int caseFold;
6154     clientchar_t *tidPathp;
6155     DWORD filter;
6156     cm_req_t req;
6157
6158     userp = smb_GetUserFromVCP(vcp, inp);
6159     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6160     if (code) {
6161         cm_ReleaseUser(userp);
6162         return CM_ERROR_NOSUCHPATH;
6163     }
6164
6165     smb_InitReq(&req);
6166     memset(&rock, 0, sizeof(rock));
6167
6168     spacep = inp->spacep;
6169     smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6170
6171     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6172     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6173                     userp, tidPathp, &req, &oldDscp);
6174     if (code) {
6175         cm_ReleaseUser(userp);
6176         return code;
6177     }
6178
6179 #ifdef DFS_SUPPORT
6180     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6181         int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6182         cm_ReleaseSCache(oldDscp);
6183         cm_ReleaseUser(userp);
6184         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6185             return CM_ERROR_PATH_NOT_COVERED;
6186         else
6187             return CM_ERROR_NOSUCHPATH;
6188     }
6189 #endif /* DFS_SUPPORT */
6190
6191     smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6192     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6193                     userp, tidPathp, &req, &newDscp);
6194
6195     if (code) {
6196         cm_ReleaseSCache(oldDscp);
6197         cm_ReleaseUser(userp);
6198         return code;
6199     }
6200
6201 #ifdef DFS_SUPPORT
6202     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6203         int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6204         cm_ReleaseSCache(oldDscp);
6205         cm_ReleaseSCache(newDscp);
6206         cm_ReleaseUser(userp);
6207         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6208             return CM_ERROR_PATH_NOT_COVERED;
6209         else
6210             return CM_ERROR_NOSUCHPATH;
6211     }
6212 #endif /* DFS_SUPPORT */
6213
6214
6215     /* otherwise, oldDscp and newDscp point to the corresponding directories.
6216      * next, get the component names, and lower case them.
6217      */
6218
6219     /* handle the old name first */
6220     if (!oldLastNamep)
6221         oldLastNamep = oldPathp;
6222     else
6223         oldLastNamep++;
6224
6225     /* and handle the new name, too */
6226     if (!newLastNamep)
6227         newLastNamep = newPathp;
6228     else
6229         newLastNamep++;
6230
6231     /* TODO: The old name could be a wildcard.  The new name must not be */
6232
6233     /* Check if the file already exists; if so return error */
6234     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6235     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6236         (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6237     {
6238         osi_Log2(smb_logp, "  lookup returns %ld for [%S]", code,
6239                  osi_LogSaveClientString(smb_logp, newLastNamep));
6240
6241         /* Check if the old and the new names differ only in case. If so return
6242          * success, else return CM_ERROR_EXISTS
6243          */
6244         if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
6245
6246             /* This would be a success only if the old file is *as same as* the new file */
6247             code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
6248             if (!code) {
6249                 if (tmpscp == tmpscp2)
6250                     code = 0;
6251                 else
6252                     code = CM_ERROR_EXISTS;
6253                 cm_ReleaseSCache(tmpscp2);
6254                 tmpscp2 = NULL;
6255             } else {
6256                 code = CM_ERROR_NOSUCHFILE;
6257             }
6258         } else {
6259             /* file exist, do not rename, also fixes move */
6260             osi_Log0(smb_logp, "Can't rename.  Target already exists");
6261             code = CM_ERROR_EXISTS;
6262         }
6263         goto done;
6264     }
6265
6266     /* do the vnode call */
6267     rock.odscp = oldDscp;
6268     rock.ndscp = newDscp;
6269     rock.userp = userp;
6270     rock.reqp = &req;
6271     rock.vcp = vcp;
6272     rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
6273     if (!rock.maskp) {
6274         code = CM_ERROR_NOSUCHFILE;
6275         goto done;
6276     }
6277     rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6278     rock.newNamep = newLastNamep;
6279     rock.fsOldName[0] = '\0';
6280     rock.clOldName[0] = '\0';
6281     rock.any = 0;
6282
6283     /* Now search the directory for the pattern, and do the appropriate rename when found */
6284     thyper.LowPart = 0;         /* search dir from here */
6285     thyper.HighPart = 0;
6286
6287     code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6288     if (code == 0 && !rock.any) {
6289         thyper.LowPart = 0;
6290         thyper.HighPart = 0;
6291         rock.flags |= SMB_MASKFLAG_CASEFOLD;
6292         code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
6293     }
6294     osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
6295
6296     if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
6297         code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
6298                          rock.ndscp, rock.newNamep, rock.userp,
6299                          rock.reqp);
6300         /* if the call worked, stop doing the search now, since we
6301          * really only want to rename one file.
6302          */
6303     if (code)
6304         osi_Log0(smb_logp, "cm_Rename failure");
6305         osi_Log1(smb_logp, "cm_Rename returns %ld", code);
6306     } else if (code == 0) {
6307         code = CM_ERROR_NOSUCHFILE;
6308     }
6309
6310     /* Handle Change Notification */
6311     /*
6312     * Being lazy, not distinguishing between files and dirs in this
6313     * filter, since we'd have to do a lookup.
6314     */
6315     if (code == 0) {
6316         filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
6317         if (oldDscp == newDscp) {
6318             if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6319                 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6320                                  filter, oldDscp, rock.clOldName,
6321                                  newLastNamep, TRUE);
6322         } else {
6323             if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6324                 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
6325                                   filter, oldDscp, rock.clOldName,
6326                                   NULL, TRUE);
6327             if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6328                 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
6329                                  filter, newDscp, newLastNamep,
6330                                  NULL, TRUE);
6331         }
6332     }
6333
6334   done:
6335     if (tmpscp != NULL)
6336         cm_ReleaseSCache(tmpscp);
6337     if (userp)
6338         cm_ReleaseUser(userp);
6339     if (oldDscp)
6340         cm_ReleaseSCache(oldDscp);
6341     if (newDscp)
6342         cm_ReleaseSCache(newDscp);
6343     if (rock.maskp)
6344         free(rock.maskp);
6345
6346     return code;
6347 }
6348
6349 long
6350 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
6351 {
6352     long code = 0;
6353     cm_space_t *spacep = NULL;
6354     cm_scache_t *oldDscp = NULL;
6355     cm_scache_t *newDscp = NULL;
6356     cm_scache_t *tmpscp= NULL;
6357     cm_scache_t *tmpscp2 = NULL;
6358     cm_scache_t *sscp = NULL;
6359     clientchar_t *oldLastNamep;
6360     clientchar_t *newLastNamep;
6361     cm_user_t *userp;
6362     int caseFold;
6363     clientchar_t *tidPathp;
6364     DWORD filter;
6365     cm_req_t req;
6366
6367     userp = smb_GetUserFromVCP(vcp, inp);
6368
6369     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6370     if (code) {
6371         cm_ReleaseUser(userp);
6372         return CM_ERROR_NOSUCHPATH;
6373     }
6374
6375     smb_InitReq(&req);
6376
6377     caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
6378
6379     spacep = inp->spacep;
6380     smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
6381
6382     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6383                     userp, tidPathp, &req, &oldDscp);
6384     if (code) {
6385         cm_ReleaseUser(userp);
6386         return code;
6387     }
6388
6389 #ifdef DFS_SUPPORT
6390     if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6391         int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
6392         cm_ReleaseSCache(oldDscp);
6393         cm_ReleaseUser(userp);
6394         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6395             return CM_ERROR_PATH_NOT_COVERED;
6396         else
6397             return CM_ERROR_NOSUCHPATH;
6398     }
6399 #endif /* DFS_SUPPORT */
6400
6401     smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
6402     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold,
6403                     userp, tidPathp, &req, &newDscp);
6404     if (code) {
6405         cm_ReleaseSCache(oldDscp);
6406         cm_ReleaseUser(userp);
6407         return code;
6408     }
6409
6410 #ifdef DFS_SUPPORT
6411     if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
6412         int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
6413         cm_ReleaseSCache(newDscp);
6414         cm_ReleaseSCache(oldDscp);
6415         cm_ReleaseUser(userp);
6416         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6417             return CM_ERROR_PATH_NOT_COVERED;
6418         else
6419             return CM_ERROR_NOSUCHPATH;
6420     }
6421 #endif /* DFS_SUPPORT */
6422
6423     /* Now, although we did two lookups for the two directories (because the same
6424      * directory can be referenced through different paths), we only allow hard links
6425      * within the same directory. */
6426     if (oldDscp != newDscp) {
6427         cm_ReleaseSCache(oldDscp);
6428         cm_ReleaseSCache(newDscp);
6429         cm_ReleaseUser(userp);
6430         return CM_ERROR_CROSSDEVLINK;
6431     }
6432
6433     /* handle the old name first */
6434     if (!oldLastNamep)
6435         oldLastNamep = oldPathp;
6436     else
6437         oldLastNamep++;
6438
6439     /* and handle the new name, too */
6440     if (!newLastNamep)
6441         newLastNamep = newPathp;
6442     else
6443         newLastNamep++;
6444
6445     /* now lookup the old name */
6446     osi_Log1(smb_logp,"  looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
6447     code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
6448     if (code) {
6449         cm_ReleaseSCache(oldDscp);
6450         cm_ReleaseSCache(newDscp);
6451         cm_ReleaseUser(userp);
6452         return code;
6453     }
6454
6455     /* Check if the file already exists; if so return error */
6456     code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
6457     if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
6458         (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
6459     {
6460         osi_Log2(smb_logp, "  lookup returns %ld for [%S]", code,
6461                  osi_LogSaveClientString(smb_logp, newLastNamep));
6462
6463         /* if the existing link is to the same file, then we return success */
6464         if (!code) {
6465             if(sscp == tmpscp) {
6466                 code = 0;
6467             } else {
6468                 osi_Log0(smb_logp, "Can't create hardlink.  Target already exists");
6469                 code = CM_ERROR_EXISTS;
6470             }
6471         }
6472
6473         if (tmpscp != NULL)
6474             cm_ReleaseSCache(tmpscp);
6475         cm_ReleaseSCache(sscp);
6476         cm_ReleaseSCache(newDscp);
6477         cm_ReleaseSCache(oldDscp);
6478         cm_ReleaseUser(userp);
6479         return code;
6480     }
6481
6482     /* now create the hardlink */
6483     osi_Log1(smb_logp,"  Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
6484     code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
6485     osi_Log1(smb_logp,"  Link returns 0x%x", code);
6486
6487     /* Handle Change Notification */
6488     if (code == 0) {
6489         filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
6490         if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
6491             smb_NotifyChange(FILE_ACTION_ADDED,
6492                              filter, newDscp, newLastNamep,
6493                              NULL, TRUE);
6494     }
6495
6496     if (tmpscp != NULL)
6497         cm_ReleaseSCache(tmpscp);
6498     cm_ReleaseUser(userp);
6499     cm_ReleaseSCache(sscp);
6500     cm_ReleaseSCache(oldDscp);
6501     cm_ReleaseSCache(newDscp);
6502     return code;
6503 }
6504
6505 /* SMB_COM_RENAME */
6506 long
6507 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6508 {
6509     clientchar_t *oldPathp;
6510     clientchar_t *newPathp;
6511     unsigned char *tp;
6512     long code;
6513
6514     tp = smb_GetSMBData(inp, NULL);
6515     oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6516     if (!oldPathp)
6517         return CM_ERROR_BADSMB;
6518     newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6519     if (!newPathp)
6520         return CM_ERROR_BADSMB;
6521
6522     osi_Log2(smb_logp, "smb rename [%S] to [%S]",
6523              osi_LogSaveClientString(smb_logp, oldPathp),
6524              osi_LogSaveClientString(smb_logp, newPathp));
6525
6526     if (!cm_IsValidClientString(newPathp)) {
6527 #ifdef DEBUG
6528         clientchar_t * hexp;
6529
6530         hexp = cm_GetRawCharsAlloc(newPathp, -1);
6531         osi_Log1(smb_logp, "CoreRename rejecting invalid name. [%S]",
6532                  osi_LogSaveClientString(smb_logp, hexp));
6533         if (hexp)
6534             free(hexp);
6535 #else
6536         osi_Log0(smb_logp, "CoreRename rejecting invalid name");
6537 #endif
6538         return CM_ERROR_BADNTFILENAME;
6539     }
6540
6541     code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
6542
6543     osi_Log1(smb_logp, "smb rename returns 0x%x", code);
6544     return code;
6545 }
6546
6547
6548
6549 typedef struct smb_rmdirRock {
6550     cm_scache_t *dscp;
6551     cm_user_t *userp;
6552     cm_req_t *reqp;
6553     normchar_t *maskp;          /* pointer to the star pattern */
6554     int flags;
6555     int any;
6556     cm_dirEntryList_t * matches;
6557 } smb_rmdirRock_t;
6558
6559 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
6560 {
6561     long code = 0;
6562     smb_rmdirRock_t *rockp;
6563     int match;
6564     normchar_t matchName[MAX_PATH];
6565
6566     rockp = (smb_rmdirRock_t *) vrockp;
6567
6568     if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6569         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6570                  osi_LogSaveString(smb_logp, dep->name));
6571         return 0;
6572     }
6573
6574     if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
6575         match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6576     else
6577         match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
6578     if (!match &&
6579          (rockp->flags & SMB_MASKFLAG_TILDE) &&
6580          !cm_Is8Dot3(matchName)) {
6581         cm_Gen8Dot3Name(dep, matchName, NULL);
6582         match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
6583     }
6584
6585     if (match) {
6586         rockp->any = 1;
6587         cm_DirEntryListAdd(dep->name, &rockp->matches);
6588     }
6589
6590     return 0;
6591 }
6592
6593
6594 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6595 {
6596     long code = 0;
6597     clientchar_t *pathp;
6598     unsigned char *tp;
6599     cm_space_t *spacep;
6600     cm_scache_t *dscp;
6601     clientchar_t *lastNamep;
6602     smb_rmdirRock_t rock;
6603     cm_user_t *userp;
6604     osi_hyper_t thyper;
6605     int caseFold;
6606     clientchar_t *tidPathp;
6607     cm_req_t req;
6608
6609     smb_InitReq(&req);
6610     memset(&rock, 0, sizeof(rock));
6611
6612     tp = smb_GetSMBData(inp, NULL);
6613     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
6614     if (!pathp)
6615         return CM_ERROR_BADSMB;
6616
6617     spacep = inp->spacep;
6618     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
6619
6620     userp = smb_GetUserFromVCP(vcp, inp);
6621
6622     caseFold = CM_FLAG_CASEFOLD;
6623
6624     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6625     if (code) {
6626         cm_ReleaseUser(userp);
6627         return CM_ERROR_NOSUCHPATH;
6628     }
6629     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
6630                     userp, tidPathp, &req, &dscp);
6631
6632     if (code) {
6633         cm_ReleaseUser(userp);
6634         return code;
6635     }
6636
6637 #ifdef DFS_SUPPORT
6638     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6639         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6640         cm_ReleaseSCache(dscp);
6641         cm_ReleaseUser(userp);
6642         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6643             return CM_ERROR_PATH_NOT_COVERED;
6644         else
6645             return CM_ERROR_NOSUCHPATH;
6646     }
6647 #endif /* DFS_SUPPORT */
6648
6649     /* otherwise, scp points to the parent directory. */
6650     if (!lastNamep)
6651         lastNamep = pathp;
6652     else
6653         lastNamep++;
6654
6655     rock.any = 0;
6656     rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6657     if (!rock.maskp) {
6658         code = CM_ERROR_NOSUCHFILE;
6659         goto done;
6660     }
6661     rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6662
6663     thyper.LowPart = 0;
6664     thyper.HighPart = 0;
6665     rock.userp = userp;
6666     rock.reqp = &req;
6667     rock.dscp = dscp;
6668     rock.matches = NULL;
6669
6670     /* First do a case sensitive match, and if that fails, do a case insensitive match */
6671     code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6672     if (code == 0 && !rock.any) {
6673         thyper.LowPart = 0;
6674         thyper.HighPart = 0;
6675         rock.flags |= SMB_MASKFLAG_CASEFOLD;
6676         code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6677     }
6678
6679     if (code == 0 && rock.matches) {
6680         cm_dirEntryList_t * entry;
6681
6682         for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6683             clientchar_t clientName[MAX_PATH];
6684
6685             /* We assume this will succeed because smb_RmdirProc()
6686                successfully converted entry->name once above. */
6687             cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6688
6689             osi_Log1(smb_logp, "Removing directory %s",
6690                      osi_LogSaveString(smb_logp, entry->name));
6691
6692             code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6693
6694             if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6695                 smb_NotifyChange(FILE_ACTION_REMOVED,
6696                                  FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6697                                  dscp, clientName, NULL, TRUE);
6698         }
6699     }
6700
6701   done:
6702     if (rock.matches)
6703     cm_DirEntryListFree(&rock.matches);
6704
6705     if (userp)
6706     cm_ReleaseUser(userp);
6707
6708     if (dscp)
6709     cm_ReleaseSCache(dscp);
6710
6711     if (code == 0 && !rock.any)
6712         code = CM_ERROR_NOSUCHFILE;
6713
6714     if (rock.maskp)
6715     free(rock.maskp);
6716
6717     return code;
6718 }
6719
6720 /* SMB_COM_FLUSH */
6721 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6722 {
6723     unsigned short fid;
6724     smb_fid_t *fidp;
6725     cm_user_t *userp;
6726     long code = 0;
6727     cm_req_t req;
6728
6729     smb_InitReq(&req);
6730
6731     fid = smb_GetSMBParm(inp, 0);
6732
6733     osi_Log1(smb_logp, "SMB flush fid %d", fid);
6734
6735     fid = smb_ChainFID(fid, inp);
6736     fidp = smb_FindFID(vcp, fid, 0);
6737     if (!fidp) {
6738         osi_Log2(smb_logp, "smb_ReceiveCoreFlush Unknown SMB Fid vcp 0x%p fid %d",
6739                  vcp, fid);
6740         return CM_ERROR_BADFD;
6741     }
6742     userp = smb_GetUserFromVCP(vcp, inp);
6743
6744     lock_ObtainMutex(&fidp->mx);
6745     if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
6746         cm_ReleaseUser(userp);
6747         lock_ReleaseMutex(&fidp->mx);
6748         smb_ReleaseFID(fidp);
6749         return CM_ERROR_BADFD;
6750     }
6751
6752     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
6753         lock_ReleaseMutex(&fidp->mx);
6754         cm_ReleaseUser(userp);
6755         smb_CloseFID(vcp, fidp, NULL, 0);
6756         smb_ReleaseFID(fidp);
6757         return CM_ERROR_NOSUCHFILE;
6758     }
6759
6760     if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6761         cm_scache_t * scp = fidp->scp;
6762         cm_HoldSCache(scp);
6763         lock_ReleaseMutex(&fidp->mx);
6764         code = cm_FSync(scp, userp, &req, FALSE);
6765         cm_ReleaseSCache(scp);
6766     } else {
6767         lock_ReleaseMutex(&fidp->mx);
6768         code = 0;
6769     }
6770
6771     cm_ReleaseUser(userp);
6772     smb_ReleaseFID(fidp);
6773     return code;
6774 }
6775
6776 struct smb_FullNameRock {
6777     clientchar_t *name;
6778     cm_scache_t  *vnode;
6779     clientchar_t *fullName;
6780     fschar_t     *originalName;
6781 };
6782
6783 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6784                      osi_hyper_t *offp)
6785 {
6786     normchar_t matchName[MAX_PATH];
6787     struct smb_FullNameRock *vrockp;
6788
6789     vrockp = (struct smb_FullNameRock *)rockp;
6790
6791     if (cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName)) == 0) {
6792         osi_Log1(smb_logp, "Skipping entry [%s]. Can't normalize FS string",
6793                  osi_LogSaveString(smb_logp, dep->name));
6794         return 0;
6795     }
6796
6797     if (!cm_Is8Dot3(matchName)) {
6798         clientchar_t shortName[13];
6799
6800         cm_Gen8Dot3Name(dep, shortName, NULL);
6801
6802         if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6803             vrockp->fullName = cm_ClientStrDup(matchName);
6804             vrockp->originalName = cm_FsStrDup(dep->name);
6805             return CM_ERROR_STOPNOW;
6806         }
6807     }
6808     if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6809         ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6810         ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6811         vrockp->fullName = cm_ClientStrDup(matchName);
6812         vrockp->originalName = cm_FsStrDup(dep->name);
6813         return CM_ERROR_STOPNOW;
6814     }
6815     return 0;
6816 }
6817
6818 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6819                   clientchar_t **newPathp, fschar_t ** originalPathp,
6820                   cm_user_t *userp, cm_req_t *reqp)
6821 {
6822     struct smb_FullNameRock rock;
6823     long code = 0;
6824
6825     memset(&rock, 0, sizeof(rock));
6826     rock.name = pathp;
6827     rock.vnode = scp;
6828
6829     code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6830     if (code == CM_ERROR_STOPNOW) {
6831         *newPathp = rock.fullName;
6832         *originalPathp = rock.originalName;
6833     } else {
6834         *newPathp = cm_ClientStrDup(pathp);
6835         *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6836     }
6837 }
6838
6839 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6840                   afs_uint32 dosTime) {
6841     long code = 0;
6842     cm_req_t req;
6843     cm_scache_t *dscp = NULL;
6844     clientchar_t *pathp = NULL;
6845     cm_scache_t * scp = NULL;
6846     cm_scache_t *delscp = NULL;
6847     int nullcreator = 0;
6848
6849     osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6850              fidp, fidp->fid, scp, vcp);
6851
6852     if (!userp) {
6853         lock_ObtainMutex(&fidp->mx);
6854         if (!fidp->userp && !(fidp->flags & (SMB_FID_IOCTL|
6855                                              SMB_FID_RPC))) {
6856             lock_ReleaseMutex(&fidp->mx);
6857             osi_Log0(smb_logp, "  No user specified.  Not closing fid");
6858             return CM_ERROR_BADFD;
6859         }
6860
6861         userp = fidp->userp;    /* no hold required since fidp is held
6862                                    throughout the function */
6863         lock_ReleaseMutex(&fidp->mx);
6864     }
6865
6866     smb_InitReq(&req);
6867
6868     lock_ObtainWrite(&smb_rctLock);
6869     if (fidp->deleteOk) {
6870         osi_Log0(smb_logp, "  Fid already closed.");
6871         lock_ReleaseWrite(&smb_rctLock);
6872         return CM_ERROR_BADFD;
6873     }
6874     fidp->deleteOk = 1;
6875     lock_ReleaseWrite(&smb_rctLock);
6876
6877     lock_ObtainMutex(&fidp->mx);
6878     if (fidp->NTopen_dscp) {
6879         dscp = fidp->NTopen_dscp;
6880         cm_HoldSCache(dscp);
6881     }
6882
6883     if (fidp->NTopen_pathp)
6884         pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6885
6886     if (fidp->scp) {
6887         scp = fidp->scp;
6888         cm_HoldSCache(scp);
6889     }
6890
6891     /* Don't jump the gun on an async raw write */
6892     while (fidp->raw_writers) {
6893         lock_ReleaseMutex(&fidp->mx);
6894         thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6895         lock_ObtainMutex(&fidp->mx);
6896     }
6897
6898     /* watch for ioctl closes, and read-only opens */
6899     if (scp != NULL &&
6900         (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6901          == SMB_FID_OPENWRITE) {
6902         if (dosTime != 0 && dosTime != -1) {
6903             lock_ObtainWrite(&fidp->scp->rw);
6904             scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6905             /* This fixes defect 10958 */
6906             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6907             smb_UnixTimeFromDosUTime(&scp->clientModTime, dosTime);
6908             lock_ReleaseWrite(&fidp->scp->rw);
6909         }
6910         if (smb_AsyncStore != 2) {
6911             lock_ReleaseMutex(&fidp->mx);
6912             code = cm_FSync(scp, userp, &req, FALSE);
6913             lock_ObtainMutex(&fidp->mx);
6914         }
6915     }
6916     else
6917         code = 0;
6918
6919     /* unlock any pending locks */
6920     if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6921         scp->fileType == CM_SCACHETYPE_FILE) {
6922         cm_key_t key;
6923         long tcode;
6924
6925         lock_ReleaseMutex(&fidp->mx);
6926
6927         /* CM_UNLOCK_BY_FID doesn't look at the process ID.  We pass
6928               * in zero. */
6929         key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6930         lock_ObtainWrite(&scp->rw);
6931
6932         tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6933                           CM_SCACHESYNC_NEEDCALLBACK
6934                           | CM_SCACHESYNC_GETSTATUS
6935                           | CM_SCACHESYNC_LOCK);
6936
6937         if (tcode) {
6938             osi_Log1(smb_logp,
6939                      "smb CoreClose SyncOp failure code 0x%x", tcode);
6940             goto post_syncopdone;
6941         }
6942
6943         cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6944
6945         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6946
6947     post_syncopdone:
6948
6949         lock_ReleaseWrite(&scp->rw);
6950         lock_ObtainMutex(&fidp->mx);
6951     }
6952
6953     if (fidp->flags & SMB_FID_DELONCLOSE) {
6954         clientchar_t *fullPathp = NULL;
6955         fschar_t *originalNamep = NULL;
6956
6957         lock_ReleaseMutex(&fidp->mx);
6958
6959         code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6960         if (code) {
6961             cm_HoldSCache(scp);
6962             delscp = scp;
6963         }
6964         smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6965         if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6966             code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6967             if (code == 0) {
6968                 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6969                     smb_NotifyChange(FILE_ACTION_REMOVED,
6970                                       FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6971                                       dscp, fullPathp, NULL, TRUE);
6972             }
6973         } else {
6974             code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6975             if (code == 0) {
6976                 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6977                     smb_NotifyChange(FILE_ACTION_REMOVED,
6978                                       FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6979                                       dscp, fullPathp, NULL, TRUE);
6980             }
6981         }
6982
6983         if (fullPathp)
6984             free(fullPathp);
6985         if (originalNamep)
6986             free(originalNamep);
6987
6988         lock_ObtainMutex(&fidp->mx);
6989         fidp->flags &= ~SMB_FID_DELONCLOSE;
6990     }
6991
6992     /* if this was a newly created file, then clear the creator
6993      * in the stat cache entry. */
6994     if (fidp->flags & SMB_FID_CREATED) {
6995         nullcreator = 1;
6996         fidp->flags &= ~SMB_FID_CREATED;
6997     }
6998
6999     if (fidp->flags & SMB_FID_NTOPEN) {
7000         cm_ReleaseSCache(fidp->NTopen_dscp);
7001         fidp->NTopen_dscp = NULL;
7002         free(fidp->NTopen_pathp);
7003         fidp->NTopen_pathp = NULL;
7004         fidp->flags &= ~SMB_FID_NTOPEN;
7005     } else {
7006         osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
7007         osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
7008     }
7009
7010     if (fidp->NTopen_wholepathp) {
7011         free(fidp->NTopen_wholepathp);
7012         fidp->NTopen_wholepathp = NULL;
7013     }
7014
7015     if (fidp->scp) {
7016         cm_ReleaseSCache(fidp->scp);
7017         fidp->scp = NULL;
7018     }
7019     lock_ReleaseMutex(&fidp->mx);
7020
7021     if (dscp)
7022         cm_ReleaseSCache(dscp);
7023
7024     if (delscp) {
7025         cm_ReleaseSCache(delscp);
7026     }
7027
7028     if (scp) {
7029         lock_ObtainWrite(&scp->rw);
7030         if (nullcreator && scp->creator == userp)
7031             scp->creator = NULL;
7032         scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
7033         lock_ReleaseWrite(&scp->rw);
7034         cm_ReleaseSCache(scp);
7035     }
7036
7037     if (pathp)
7038         free(pathp);
7039
7040     return code;
7041 }
7042
7043 /* SMB_COM_CLOSE */
7044 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7045 {
7046     unsigned short fid;
7047     smb_fid_t *fidp;
7048     cm_user_t *userp;
7049     long code = 0;
7050     afs_uint32 dosTime;
7051
7052     fid = smb_GetSMBParm(inp, 0);
7053     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7054
7055     osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
7056
7057     fid = smb_ChainFID(fid, inp);
7058     fidp = smb_FindFID(vcp, fid, 0);
7059     if (!fidp) {
7060         osi_Log2(smb_logp, "smb_ReceiveCoreClose Unknown SMB Fid vcp 0x%p fid %d",
7061                  vcp, fid);
7062         return CM_ERROR_BADFD;
7063     }
7064
7065     userp = smb_GetUserFromVCP(vcp, inp);
7066
7067     code = smb_CloseFID(vcp, fidp, userp, dosTime);
7068
7069     smb_ReleaseFID(fidp);
7070     cm_ReleaseUser(userp);
7071     return code;
7072 }
7073
7074 /*
7075  * smb_ReadData -- common code for Read, Read And X, and Raw Read
7076  */
7077 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7078         cm_user_t *userp, long *readp)
7079 {
7080     osi_hyper_t offset;
7081     long code = 0;
7082     cm_scache_t *scp;
7083     cm_buf_t *bufferp;
7084     osi_hyper_t fileLength;
7085     osi_hyper_t thyper;
7086     osi_hyper_t lastByte;
7087     osi_hyper_t bufferOffset;
7088     long bufIndex;
7089     afs_uint32 nbytes;
7090     int chunk;
7091     int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
7092     cm_req_t req;
7093
7094     osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
7095               fidp->fid, offsetp->LowPart, count);
7096
7097     *readp = 0;
7098
7099     lock_ObtainMutex(&fidp->mx);
7100     /* make sure we have a readable FD */
7101     if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
7102         osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
7103                   fidp->fid, fidp->flags);
7104         lock_ReleaseMutex(&fidp->mx);
7105         code = CM_ERROR_BADFDOP;
7106         goto done2;
7107     }
7108
7109     if (!fidp->scp) {
7110         lock_ReleaseMutex(&fidp->mx);
7111         code = CM_ERROR_BADFD;
7112         goto done2;
7113     }
7114
7115     smb_InitReq(&req);
7116
7117     bufferp = NULL;
7118     offset = *offsetp;
7119
7120     scp = fidp->scp;
7121     cm_HoldSCache(scp);
7122     lock_ObtainWrite(&scp->rw);
7123
7124     if (offset.HighPart == 0) {
7125         chunk = offset.LowPart >> cm_logChunkSize;
7126         if (chunk != fidp->curr_chunk) {
7127             fidp->prev_chunk = fidp->curr_chunk;
7128             fidp->curr_chunk = chunk;
7129         }
7130         if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
7131             sequential = 1;
7132     }
7133     lock_ReleaseMutex(&fidp->mx);
7134
7135     /* start by looking up the file's end */
7136     code = cm_SyncOp(scp, NULL, userp, &req, 0,
7137                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7138     if (code)
7139         goto done;
7140
7141     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7142
7143     /* now we have the entry locked, look up the length */
7144     fileLength = scp->length;
7145
7146     /* adjust count down so that it won't go past EOF */
7147     thyper.LowPart = count;
7148     thyper.HighPart = 0;
7149     thyper = LargeIntegerAdd(offset, thyper);   /* where read should end */
7150     lastByte = thyper;
7151     if (LargeIntegerGreaterThan(thyper, fileLength)) {
7152         /* we'd read past EOF, so just stop at fileLength bytes.
7153          * Start by computing how many bytes remain in the file.
7154          */
7155         thyper = LargeIntegerSubtract(fileLength, offset);
7156
7157         /* if we are past EOF, read 0 bytes */
7158         if (LargeIntegerLessThanZero(thyper))
7159             count = 0;
7160         else
7161             count = thyper.LowPart;
7162     }
7163
7164     *readp = count;
7165
7166     /* now, copy the data one buffer at a time,
7167      * until we've filled the request packet
7168      */
7169     while (1) {
7170         /* if we've copied all the data requested, we're done */
7171         if (count <= 0) break;
7172
7173         /* otherwise, load up a buffer of data */
7174         thyper.HighPart = offset.HighPart;
7175         thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7176         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7177             /* wrong buffer */
7178             if (bufferp) {
7179                 buf_Release(bufferp);
7180                 bufferp = NULL;
7181             }
7182             lock_ReleaseWrite(&scp->rw);
7183
7184             code = buf_Get(scp, &thyper, &req, &bufferp);
7185
7186             lock_ObtainWrite(&scp->rw);
7187             if (code) goto done;
7188             bufferOffset = thyper;
7189
7190             /* now get the data in the cache */
7191             while (1) {
7192                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7193                                  CM_SCACHESYNC_NEEDCALLBACK |
7194                                  CM_SCACHESYNC_READ);
7195                 if (code)
7196                     goto done;
7197
7198                 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
7199
7200                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
7201
7202                 /* otherwise, load the buffer and try again */
7203                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
7204                 if (code) break;
7205             }
7206             if (code) {
7207                 buf_Release(bufferp);
7208                 bufferp = NULL;
7209                 goto done;
7210             }
7211         }       /* if (wrong buffer) ... */
7212
7213         /* now we have the right buffer loaded.  Copy out the
7214          * data from here to the user's buffer.
7215          */
7216         bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7217
7218         /* and figure out how many bytes we want from this buffer */
7219         nbytes = cm_data.buf_blockSize - bufIndex;      /* what remains in buffer */
7220         if (nbytes > count) nbytes = count;     /* don't go past EOF */
7221
7222         /* now copy the data */
7223         memcpy(op, bufferp->datap + bufIndex, nbytes);
7224
7225         /* adjust counters, pointers, etc. */
7226         op += nbytes;
7227         count -= nbytes;
7228         thyper.LowPart = nbytes;
7229         thyper.HighPart = 0;
7230         offset = LargeIntegerAdd(thyper, offset);
7231     } /* while 1 */
7232
7233   done:
7234     lock_ReleaseWrite(&scp->rw);
7235     if (bufferp)
7236         buf_Release(bufferp);
7237
7238     if (code == 0 && sequential)
7239         cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
7240
7241     cm_ReleaseSCache(scp);
7242
7243   done2:
7244     osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
7245               fidp->fid, code, *readp);
7246     return code;
7247 }
7248
7249 /*
7250  * smb_WriteData -- common code for Write and Raw Write
7251  */
7252 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
7253         cm_user_t *userp, long *writtenp)
7254 {
7255     osi_hyper_t offset = *offsetp;
7256     long code = 0;
7257     long written = 0;
7258     cm_scache_t *scp = NULL;
7259     osi_hyper_t fileLength;     /* file's length at start of write */
7260     osi_hyper_t minLength;      /* don't read past this */
7261     afs_uint32 nbytes;          /* # of bytes to transfer this iteration */
7262     cm_buf_t *bufferp = NULL;
7263     osi_hyper_t thyper;         /* hyper tmp variable */
7264     osi_hyper_t bufferOffset;
7265     afs_uint32 bufIndex;                /* index in buffer where our data is */
7266     int doWriteBack = 0;
7267     osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
7268     DWORD filter = 0;
7269     cm_req_t req;
7270     int needSyncOpDone = 0;
7271
7272     osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
7273               fidp->fid, offsetp->LowPart, count);
7274
7275     *writtenp = 0;
7276
7277     lock_ObtainMutex(&fidp->mx);
7278     /* make sure we have a writable FD */
7279     if (!(fidp->flags & SMB_FID_OPENWRITE)) {
7280         osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
7281                   fidp->fid, fidp->flags);
7282         lock_ReleaseMutex(&fidp->mx);
7283         code = CM_ERROR_BADFDOP;
7284         goto done2;
7285     }
7286
7287     smb_InitReq(&req);
7288
7289     scp = fidp->scp;
7290     cm_HoldSCache(scp);
7291     lock_ReleaseMutex(&fidp->mx);
7292
7293     lock_ObtainWrite(&scp->rw);
7294     /* start by looking up the file's end */
7295     code = cm_SyncOp(scp, NULL, userp, &req, 0,
7296                       CM_SCACHESYNC_NEEDCALLBACK
7297                       | CM_SCACHESYNC_SETSTATUS
7298                       | CM_SCACHESYNC_GETSTATUS);
7299     if (code)
7300         goto done;
7301
7302     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
7303
7304     /* now we have the entry locked, look up the length */
7305     fileLength = scp->length;
7306     minLength = fileLength;
7307     if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7308         minLength = scp->serverLength;
7309
7310     /* adjust file length if we extend past EOF */
7311     thyper.LowPart = count;
7312     thyper.HighPart = 0;
7313     thyper = LargeIntegerAdd(offset, thyper);   /* where write should end */
7314     if (LargeIntegerGreaterThan(thyper, fileLength)) {
7315         /* we'd write past EOF, so extend the file */
7316         scp->mask |= CM_SCACHEMASK_LENGTH;
7317         scp->length = thyper;
7318         filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
7319     } else
7320         filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
7321
7322     /* now, if the new position (thyper) and the old (offset) are in
7323      * different storeback windows, remember to store back the previous
7324      * storeback window when we're done with the write.
7325      *
7326      * the purpose of this logic is to slow down the CIFS client
7327      * in order to avoid the client disconnecting during the CLOSE
7328      * operation if there are too many dirty buffers left to write
7329      * than can be accomplished during 45 seconds.  This used to be
7330      * based upon cm_chunkSize but we desire cm_chunkSize to be large
7331      * so that we can read larger amounts of data at a time.
7332      */
7333     if (smb_AsyncStore == 1 &&
7334          (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
7335          (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
7336         /* they're different */
7337         doWriteBack = 1;
7338         writeBackOffset.HighPart = offset.HighPart;
7339         writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
7340     }
7341
7342     *writtenp = count;
7343
7344     /* now, copy the data one buffer at a time, until we've filled the
7345      * request packet */
7346     while (count != 0) {
7347
7348         /* handle over quota or out of space */
7349         if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
7350             *writtenp = written;
7351             code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
7352             break;
7353         }
7354
7355         /* otherwise, load up a buffer of data */
7356         thyper.HighPart = offset.HighPart;
7357         thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
7358         if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
7359             /* wrong buffer */
7360             if (bufferp) {
7361                 if (needSyncOpDone) {
7362                     cm_SyncOpDone(scp, bufferp,
7363                                   CM_SCACHESYNC_NEEDCALLBACK
7364                                   | CM_SCACHESYNC_WRITE
7365                                   | CM_SCACHESYNC_BUFLOCKED);
7366                     needSyncOpDone = 0;
7367                 }
7368                 lock_ReleaseMutex(&bufferp->mx);
7369                 buf_Release(bufferp);
7370                 bufferp = NULL;
7371             }
7372             lock_ReleaseWrite(&scp->rw);
7373
7374             code = buf_Get(scp, &thyper, &req, &bufferp);
7375
7376             lock_ObtainMutex(&bufferp->mx);
7377             lock_ObtainWrite(&scp->rw);
7378             if (code) goto done;
7379
7380             bufferOffset = thyper;
7381
7382             /* now get the data in the cache */
7383             while (code == 0) {
7384                 if (!needSyncOpDone) {
7385                     code = cm_SyncOp(scp, bufferp, userp, &req, 0,
7386                                      CM_SCACHESYNC_NEEDCALLBACK
7387                                      | CM_SCACHESYNC_WRITE
7388                                      | CM_SCACHESYNC_BUFLOCKED);
7389                     if (code)
7390                         goto done;
7391
7392                     needSyncOpDone = 1;
7393                 }
7394
7395                 /* If we're overwriting the entire buffer, or
7396                  * if we're writing at or past EOF, mark the
7397                  * buffer as current so we don't call
7398                  * cm_GetBuffer.  This skips the fetch from the
7399                  * server in those cases where we're going to
7400                  * obliterate all the data in the buffer anyway,
7401                  * or in those cases where there is no useful
7402                  * data at the server to start with.
7403                  *
7404                  * Use minLength instead of scp->length, since
7405                  * the latter has already been updated by this
7406                  * call.
7407                  *
7408                  * The scp lock has been dropped multiple times
7409                  * so the minLength must be refreshed before it
7410                  * is used.
7411                  */
7412
7413                 minLength = scp->length;
7414                 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
7415                     minLength = scp->serverLength;
7416
7417                 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
7418                      || LargeIntegerEqualTo(offset, bufferp->offset)
7419                      && (count >= cm_data.buf_blockSize
7420                           || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
7421                                                                                ConvertLongToLargeInteger(count)),
7422                                                                minLength))) {
7423                     if (count < cm_data.buf_blockSize
7424                          && bufferp->dataVersion == CM_BUF_VERSION_BAD)
7425                         memset(bufferp->datap, 0,
7426                                 cm_data.buf_blockSize);
7427                     bufferp->dataVersion = scp->dataVersion;
7428                 }
7429
7430                 if (cm_HaveBuffer(scp, bufferp, 1)) break;
7431
7432                 /* otherwise, load the buffer and try again */
7433                 cm_SyncOpDone(scp, bufferp,
7434                               CM_SCACHESYNC_NEEDCALLBACK
7435                               | CM_SCACHESYNC_WRITE
7436                               | CM_SCACHESYNC_BUFLOCKED);
7437                 needSyncOpDone = 0;
7438
7439                 lock_ReleaseMutex(&bufferp->mx);
7440                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
7441                                      &req);
7442                 lock_ReleaseWrite(&scp->rw);
7443                 lock_ObtainMutex(&bufferp->mx);
7444                 lock_ObtainWrite(&scp->rw);
7445             }
7446             if (code)
7447                 goto done;
7448         }       /* if (wrong buffer) ... */
7449
7450         /* now we have the right buffer loaded.  Copy out the
7451          * data from here to the user's buffer.
7452          */
7453         bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
7454
7455         /* and figure out how many bytes we want from this buffer */
7456         nbytes = cm_data.buf_blockSize - bufIndex;      /* what remains in buffer */
7457         if (nbytes > count)
7458             nbytes = count;     /* don't go past end of request */
7459
7460         /* now copy the data */
7461         memcpy(bufferp->datap + bufIndex, op, nbytes);
7462         buf_SetDirty(bufferp, bufIndex, nbytes, userp);
7463
7464         /* adjust counters, pointers, etc. */
7465         op += nbytes;
7466         count -= nbytes;
7467         written += nbytes;
7468         offset = LargeIntegerAdd(offset, ConvertLongToLargeInteger(nbytes));
7469     } /* while count != 0 */
7470
7471   done:
7472     if (bufferp && needSyncOpDone) {
7473         cm_SyncOpDone(scp, bufferp,
7474                       CM_SCACHESYNC_NEEDCALLBACK
7475                       | CM_SCACHESYNC_WRITE
7476                       | CM_SCACHESYNC_BUFLOCKED);
7477     }
7478
7479     lock_ReleaseWrite(&scp->rw);
7480
7481     if (bufferp) {
7482         lock_ReleaseMutex(&bufferp->mx);
7483         buf_Release(bufferp);
7484     }
7485
7486     lock_ObtainMutex(&fidp->mx);
7487     if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
7488          && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7489     {
7490         lock_ReleaseMutex(&fidp->mx);
7491         smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
7492                           fidp->NTopen_dscp, fidp->NTopen_pathp,
7493                           NULL, TRUE);
7494     } else {
7495         lock_ReleaseMutex(&fidp->mx);
7496     }
7497
7498     if (code == 0) {
7499         if (smb_AsyncStore > 0) {
7500             if (doWriteBack) {
7501                 long code2;
7502
7503                 lock_ObtainWrite(&scp->rw);
7504                 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
7505                           fidp->fid);
7506                 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
7507                 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
7508                           fidp->fid, code2);
7509                 lock_ReleaseWrite(&scp->rw);
7510                 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
7511                                     writeBackOffset.HighPart,
7512                                     smb_AsyncStoreSize, 0, userp);
7513                 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
7514             }
7515         } else {
7516             cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
7517         }
7518     }
7519
7520     cm_ReleaseSCache(scp);
7521
7522   done2:
7523     osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
7524               fidp->fid, code, *writtenp);
7525     return code;
7526 }
7527
7528 /* SMB_COM_WRITE */
7529 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7530 {
7531     unsigned short fd;
7532     unsigned short count;
7533     osi_hyper_t offset;
7534     unsigned short hint;
7535     long written = 0, total_written = 0;
7536     unsigned pid;
7537     smb_fid_t *fidp;
7538     smb_t* smbp = (smb_t*) inp;
7539     long code = 0;
7540     cm_user_t *userp;
7541         cm_scache_t *scp;
7542     cm_attr_t truncAttr;        /* attribute struct used for truncating file */
7543     char *op;
7544     int inDataBlockCount;
7545
7546     fd = smb_GetSMBParm(inp, 0);
7547     count = smb_GetSMBParm(inp, 1);
7548     offset.HighPart = 0;        /* too bad */
7549     offset.LowPart = smb_GetSMBParmLong(inp, 2);
7550     hint = smb_GetSMBParm(inp, 4);
7551
7552     op = smb_GetSMBData(inp, NULL);
7553     op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
7554
7555     osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
7556              fd, offset.LowPart, count);
7557
7558     fd = smb_ChainFID(fd, inp);
7559     fidp = smb_FindFID(vcp, fd, 0);
7560     if (!fidp) {
7561         osi_Log2(smb_logp, "smb_ReceiveCoreWrite Unknown SMB Fid vcp 0x%p fid %d",
7562                  vcp, fd);
7563         return CM_ERROR_BADFD;
7564     }
7565
7566     lock_ObtainMutex(&fidp->mx);
7567     if (fidp->flags & SMB_FID_IOCTL) {
7568         lock_ReleaseMutex(&fidp->mx);
7569         code = smb_IoctlWrite(fidp, vcp, inp, outp);
7570         smb_ReleaseFID(fidp);
7571         osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
7572         return code;
7573     }
7574
7575     if (fidp->flags & SMB_FID_RPC) {
7576         lock_ReleaseMutex(&fidp->mx);
7577         code = smb_RPCWrite(fidp, vcp, inp, outp);
7578         smb_ReleaseFID(fidp);
7579         osi_Log1(smb_logp, "smb_ReceiveCoreWrite RPC code 0x%x", code);
7580         return code;
7581     }
7582
7583     if (!fidp->scp) {
7584         lock_ReleaseMutex(&fidp->mx);
7585         smb_ReleaseFID(fidp);
7586         return CM_ERROR_BADFD;
7587     }
7588
7589     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7590         lock_ReleaseMutex(&fidp->mx);
7591         smb_CloseFID(vcp, fidp, NULL, 0);
7592         smb_ReleaseFID(fidp);
7593         return CM_ERROR_NOSUCHFILE;
7594     }
7595
7596     scp = fidp->scp;
7597     cm_HoldSCache(scp);
7598     lock_ReleaseMutex(&fidp->mx);
7599     userp = smb_GetUserFromVCP(vcp, inp);
7600
7601     {
7602         cm_key_t key;
7603         LARGE_INTEGER LOffset;
7604         LARGE_INTEGER LLength;
7605
7606         pid = smbp->pid;
7607         key = cm_GenerateKey(vcp->vcID, pid, fd);
7608
7609         LOffset.HighPart = offset.HighPart;
7610         LOffset.LowPart = offset.LowPart;
7611         LLength.HighPart = 0;
7612         LLength.LowPart = count;
7613
7614         lock_ObtainWrite(&scp->rw);
7615         code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7616         lock_ReleaseWrite(&scp->rw);
7617
7618         if (code) {
7619             osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
7620             goto done;
7621         }
7622     }
7623
7624     /* special case: 0 bytes transferred means truncate to this position */
7625     if (count == 0) {
7626         cm_req_t req;
7627
7628         osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
7629
7630         smb_InitReq(&req);
7631
7632         truncAttr.mask = CM_ATTRMASK_LENGTH;
7633         truncAttr.length.LowPart = offset.LowPart;
7634         truncAttr.length.HighPart = 0;
7635         lock_ObtainMutex(&fidp->mx);
7636         code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
7637         fidp->flags |= SMB_FID_LENGTHSETDONE;
7638         lock_ReleaseMutex(&fidp->mx);
7639         smb_SetSMBParm(outp, 0, 0 /* count */);
7640         smb_SetSMBDataLength(outp, 0);
7641         goto done;
7642     }
7643
7644     /*
7645      * Work around bug in NT client
7646      *
7647      * When copying a file, the NT client should first copy the data,
7648      * then copy the last write time.  But sometimes the NT client does
7649      * these in the wrong order, so the data copies would inadvertently
7650      * cause the last write time to be overwritten.  We try to detect this,
7651      * and don't set client mod time if we think that would go against the
7652      * intention.
7653      */
7654     lock_ObtainMutex(&fidp->mx);
7655     if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
7656         lock_ObtainWrite(&fidp->scp->rw);
7657         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7658         fidp->scp->clientModTime = time(NULL);
7659         lock_ReleaseWrite(&fidp->scp->rw);
7660     }
7661     lock_ReleaseMutex(&fidp->mx);
7662
7663     code = 0;
7664     while ( code == 0 && count > 0 ) {
7665         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7666         if (code == 0 && written == 0)
7667             code = CM_ERROR_PARTIALWRITE;
7668
7669         offset = LargeIntegerAdd(offset,
7670                                  ConvertLongToLargeInteger(written));
7671         count -= (unsigned short)written;
7672         total_written += written;
7673         written = 0;
7674     }
7675
7676     osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
7677              total_written, code);
7678
7679     /* set the packet data length to 3 bytes for the data block header,
7680      * plus the size of the data.
7681      */
7682     smb_SetSMBParm(outp, 0, total_written);
7683     smb_SetSMBParmLong(outp, 1, offset.LowPart);
7684     smb_SetSMBParm(outp, 3, hint);
7685     smb_SetSMBDataLength(outp, 0);
7686
7687   done:
7688     smb_ReleaseFID(fidp);
7689     cm_ReleaseUser(userp);
7690         cm_ReleaseSCache(scp);
7691
7692     return code;
7693 }
7694
7695 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7696                           NCB *ncbp, raw_write_cont_t *rwcp)
7697 {
7698     unsigned short fd;
7699     smb_fid_t *fidp;
7700     cm_user_t *userp;
7701     char *rawBuf;
7702     long written = 0;
7703     long code = 0;
7704
7705     fd = smb_GetSMBParm(inp, 0);
7706     fidp = smb_FindFID(vcp, fd, 0);
7707
7708     lock_ObtainMutex(&fidp->mx);
7709     if (!fidp->scp) {
7710         lock_ReleaseMutex(&fidp->mx);
7711         smb_ReleaseFID(fidp);
7712         return;
7713     }
7714
7715     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7716         lock_ReleaseMutex(&fidp->mx);
7717         smb_CloseFID(vcp, fidp, NULL, 0);
7718         smb_ReleaseFID(fidp);
7719         return;
7720     }
7721     lock_ReleaseMutex(&fidp->mx);
7722
7723     osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7724              rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7725
7726     userp = smb_GetUserFromVCP(vcp, inp);
7727
7728     rawBuf = rwcp->buf;
7729     code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7730                                                  &written);
7731     if (rwcp->writeMode & 0x1) {        /* synchronous */
7732         smb_t *op;
7733
7734         smb_FormatResponsePacket(vcp, inp, outp);
7735         op = (smb_t *) outp;
7736         op->com = 0x20;         /* SMB_COM_WRITE_COMPLETE */
7737         smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7738         smb_SetSMBDataLength(outp,  0);
7739         smb_SendPacket(vcp, outp);
7740         smb_FreePacket(outp);
7741     }
7742     else {                              /* asynchronous */
7743         lock_ObtainMutex(&fidp->mx);
7744         fidp->raw_writers--;
7745         if (fidp->raw_writers == 0)
7746             thrd_SetEvent(fidp->raw_write_event);
7747         lock_ReleaseMutex(&fidp->mx);
7748     }
7749
7750     /* Give back raw buffer */
7751     lock_ObtainMutex(&smb_RawBufLock);
7752     *((char **)rawBuf) = smb_RawBufs;
7753     smb_RawBufs = rawBuf;
7754     lock_ReleaseMutex(&smb_RawBufLock);
7755
7756     smb_ReleaseFID(fidp);
7757     cm_ReleaseUser(userp);
7758 }
7759
7760 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7761 {
7762     return 0;
7763 }
7764
7765 /* SMB_COM_WRITE_RAW */
7766 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7767 {
7768     osi_hyper_t offset;
7769     long count, written = 0, total_written = 0;
7770     long totalCount;
7771     unsigned short fd;
7772     smb_fid_t *fidp;
7773     smb_t *smbp = (smb_t*) inp;
7774     long code = 0;
7775     cm_user_t *userp;
7776         cm_scache_t *scp;
7777     char *op;
7778     unsigned short writeMode;
7779     char *rawBuf;
7780     fd = smb_GetSMBParm(inp, 0);
7781     totalCount = smb_GetSMBParm(inp, 1);
7782     count = smb_GetSMBParm(inp, 10);
7783     writeMode = smb_GetSMBParm(inp, 7);
7784
7785     op = (char *) inp->data;
7786     op += smb_GetSMBParm(inp, 11);
7787
7788     offset.HighPart = 0;
7789     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7790
7791     if (*inp->wctp == 14) {
7792         /* we received a 64-bit file offset */
7793         offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7794
7795         if (LargeIntegerLessThanZero(offset)) {
7796             osi_Log2(smb_logp,
7797                      "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7798                      offset.HighPart, offset.LowPart);
7799             return CM_ERROR_BADSMB;
7800         }
7801     } else {
7802         offset.HighPart = 0;    /* 32-bit file offset */
7803     }
7804
7805     osi_Log4(smb_logp,
7806              "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7807              fd, offset.HighPart, offset.LowPart, count);
7808     osi_Log1(smb_logp,
7809              "               WriteRaw WriteMode 0x%x",
7810              writeMode);
7811
7812     fd = smb_ChainFID(fd, inp);
7813     fidp = smb_FindFID(vcp, fd, 0);
7814     if (!fidp) {
7815         osi_Log2(smb_logp, "smb_ReceiveCoreWriteRaw Unknown SMB Fid vcp 0x%p fid %d",
7816                  vcp, fd);
7817         return CM_ERROR_BADFD;
7818     }
7819     lock_ObtainMutex(&fidp->mx);
7820     if (!fidp->scp) {
7821         lock_ReleaseMutex(&fidp->mx);
7822         smb_ReleaseFID(fidp);
7823         return CM_ERROR_BADFD;
7824     }
7825
7826     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
7827         lock_ReleaseMutex(&fidp->mx);
7828         smb_CloseFID(vcp, fidp, NULL, 0);
7829         smb_ReleaseFID(fidp);
7830         return CM_ERROR_NOSUCHFILE;
7831     }
7832
7833     scp = fidp->scp;
7834     cm_HoldSCache(scp);
7835     lock_ReleaseMutex(&fidp->mx);
7836
7837     {
7838         unsigned pid;
7839         cm_key_t key;
7840         LARGE_INTEGER LOffset;
7841         LARGE_INTEGER LLength;
7842
7843         pid = smbp->pid;
7844         key = cm_GenerateKey(vcp->vcID, pid, fd);
7845
7846         LOffset.HighPart = offset.HighPart;
7847         LOffset.LowPart = offset.LowPart;
7848         LLength.HighPart = 0;
7849         LLength.LowPart = count;
7850
7851         lock_ObtainWrite(&scp->rw);
7852         code = cm_LockCheckWrite(scp, LOffset, LLength, key);
7853         lock_ReleaseWrite(&scp->rw);
7854
7855         if (code) {
7856             cm_ReleaseSCache(scp);
7857             smb_ReleaseFID(fidp);
7858             return code;
7859         }
7860     }
7861
7862     userp = smb_GetUserFromVCP(vcp, inp);
7863
7864     /*
7865      * Work around bug in NT client
7866      *
7867      * When copying a file, the NT client should first copy the data,
7868      * then copy the last write time.  But sometimes the NT client does
7869      * these in the wrong order, so the data copies would inadvertently
7870      * cause the last write time to be overwritten.  We try to detect this,
7871      * and don't set client mod time if we think that would go against the
7872      * intention.
7873      */
7874     lock_ObtainMutex(&fidp->mx);
7875     if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7876         lock_ObtainWrite(&fidp->scp->rw);
7877         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7878         fidp->scp->clientModTime = time(NULL);
7879         lock_ReleaseWrite(&fidp->scp->rw);
7880     }
7881     lock_ReleaseMutex(&fidp->mx);
7882
7883     code = 0;
7884     while ( code == 0 && count > 0 ) {
7885         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7886         if (code == 0 && written == 0)
7887             code = CM_ERROR_PARTIALWRITE;
7888
7889         offset = LargeIntegerAdd(offset,
7890                                  ConvertLongToLargeInteger(written));
7891
7892         count -= written;
7893         total_written += written;
7894         written = 0;
7895     }
7896
7897     /* Get a raw buffer */
7898     if (code == 0) {
7899         rawBuf = NULL;
7900         lock_ObtainMutex(&smb_RawBufLock);
7901         if (smb_RawBufs) {
7902             /* Get a raw buf, from head of list */
7903             rawBuf = smb_RawBufs;
7904             smb_RawBufs = *(char **)smb_RawBufs;
7905         }
7906         else
7907             code = CM_ERROR_USESTD;
7908
7909         lock_ReleaseMutex(&smb_RawBufLock);
7910     }
7911
7912     /* Don't allow a premature Close */
7913     if (code == 0 && (writeMode & 1) == 0) {
7914         lock_ObtainMutex(&fidp->mx);
7915         fidp->raw_writers++;
7916         thrd_ResetEvent(fidp->raw_write_event);
7917         lock_ReleaseMutex(&fidp->mx);
7918     }
7919
7920     smb_ReleaseFID(fidp);
7921     cm_ReleaseUser(userp);
7922     cm_ReleaseSCache(scp);
7923
7924     if (code) {
7925         smb_SetSMBParm(outp, 0, total_written);
7926         smb_SetSMBDataLength(outp, 0);
7927         ((smb_t *)outp)->com = 0x20;    /* SMB_COM_WRITE_COMPLETE */
7928         rwcp->code = code;
7929         return code;
7930     }
7931
7932     offset = LargeIntegerAdd(offset,
7933                              ConvertLongToLargeInteger(count));
7934
7935     rwcp->code = 0;
7936     rwcp->buf = rawBuf;
7937     rwcp->offset.HighPart = offset.HighPart;
7938     rwcp->offset.LowPart = offset.LowPart;
7939     rwcp->count = totalCount - count;
7940     rwcp->writeMode = writeMode;
7941     rwcp->alreadyWritten = total_written;
7942
7943     /* set the packet data length to 3 bytes for the data block header,
7944      * plus the size of the data.
7945      */
7946     smb_SetSMBParm(outp, 0, 0xffff);
7947     smb_SetSMBDataLength(outp, 0);
7948
7949     return 0;
7950 }
7951
7952 /* SMB_COM_READ */
7953 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7954 {
7955     osi_hyper_t offset;
7956     long count, finalCount;
7957     unsigned short fd;
7958     unsigned pid;
7959     smb_fid_t *fidp;
7960     smb_t *smbp = (smb_t*) inp;
7961     long code = 0;
7962     cm_user_t *userp;
7963     cm_scache_t *scp;
7964     char *op;
7965
7966     fd = smb_GetSMBParm(inp, 0);
7967     count = smb_GetSMBParm(inp, 1);
7968     offset.HighPart = 0;        /* too bad */
7969     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7970
7971     osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7972              fd, offset.LowPart, count);
7973
7974     fd = smb_ChainFID(fd, inp);
7975     fidp = smb_FindFID(vcp, fd, 0);
7976     if (!fidp) {
7977         osi_Log2(smb_logp, "smb_ReceiveCoreRead Unknown SMB Fid vcp 0x%p fid %d",
7978                  vcp, fd);
7979         return CM_ERROR_BADFD;
7980     }
7981     lock_ObtainMutex(&fidp->mx);
7982     if (fidp->flags & SMB_FID_IOCTL) {
7983         lock_ReleaseMutex(&fidp->mx);
7984         code = smb_IoctlRead(fidp, vcp, inp, outp);
7985         smb_ReleaseFID(fidp);
7986         return code;
7987     }
7988
7989     if (fidp->flags & SMB_FID_RPC) {
7990         lock_ReleaseMutex(&fidp->mx);
7991         code = smb_RPCRead(fidp, vcp, inp, outp);
7992         smb_ReleaseFID(fidp);
7993         return code;
7994     }
7995
7996     if (!fidp->scp) {
7997         lock_ReleaseMutex(&fidp->mx);
7998         smb_ReleaseFID(fidp);
7999         return CM_ERROR_BADFD;
8000     }
8001
8002     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8003         lock_ReleaseMutex(&fidp->mx);
8004         smb_CloseFID(vcp, fidp, NULL, 0);
8005         smb_ReleaseFID(fidp);
8006         return CM_ERROR_NOSUCHFILE;
8007     }
8008
8009     scp = fidp->scp;
8010     cm_HoldSCache(scp);
8011     lock_ReleaseMutex(&fidp->mx);
8012
8013     {
8014         LARGE_INTEGER LOffset, LLength;
8015         cm_key_t key;
8016
8017         pid = smbp->pid;
8018         key = cm_GenerateKey(vcp->vcID, pid, fd);
8019
8020         LOffset.HighPart = 0;
8021         LOffset.LowPart = offset.LowPart;
8022         LLength.HighPart = 0;
8023         LLength.LowPart = count;
8024
8025         lock_ObtainWrite(&scp->rw);
8026         code = cm_LockCheckRead(scp, LOffset, LLength, key);
8027         lock_ReleaseWrite(&scp->rw);
8028     }
8029     if (code) {
8030         cm_ReleaseSCache(scp);
8031         smb_ReleaseFID(fidp);
8032         return code;
8033     }
8034
8035     userp = smb_GetUserFromVCP(vcp, inp);
8036
8037     /* remember this for final results */
8038     smb_SetSMBParm(outp, 0, count);
8039     smb_SetSMBParm(outp, 1, 0);
8040     smb_SetSMBParm(outp, 2, 0);
8041     smb_SetSMBParm(outp, 3, 0);
8042     smb_SetSMBParm(outp, 4, 0);
8043
8044     /* set the packet data length to 3 bytes for the data block header,
8045      * plus the size of the data.
8046      */
8047     smb_SetSMBDataLength(outp, count+3);
8048
8049     /* get op ptr after putting in the parms, since otherwise we don't
8050      * know where the data really is.
8051      */
8052     op = smb_GetSMBData(outp, NULL);
8053
8054     /* now emit the data block header: 1 byte of type and 2 bytes of length */
8055     *op++ = 1;  /* data block marker */
8056     *op++ = (unsigned char) (count & 0xff);
8057     *op++ = (unsigned char) ((count >> 8) & 0xff);
8058
8059     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
8060
8061     /* fix some things up */
8062     smb_SetSMBParm(outp, 0, finalCount);
8063     smb_SetSMBDataLength(outp, finalCount+3);
8064
8065     smb_ReleaseFID(fidp);
8066
8067     cm_ReleaseUser(userp);
8068     cm_ReleaseSCache(scp);
8069     return code;
8070 }
8071
8072 /* SMB_COM_CREATE_DIRECTORY */
8073 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8074 {
8075     clientchar_t *pathp;
8076     long code = 0;
8077     cm_space_t *spacep;
8078     unsigned char *tp;
8079     cm_user_t *userp;
8080     cm_scache_t *dscp;                  /* dir we're dealing with */
8081     cm_scache_t *scp;                   /* file we're creating */
8082     cm_attr_t setAttr;
8083     int initialModeBits;
8084     clientchar_t *lastNamep;
8085     int caseFold;
8086     clientchar_t *tidPathp;
8087     cm_req_t req;
8088
8089     smb_InitReq(&req);
8090
8091     scp = NULL;
8092
8093     /* compute initial mode bits based on read-only flag in attributes */
8094     initialModeBits = 0777;
8095
8096     tp = smb_GetSMBData(inp, NULL);
8097     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8098     if (!pathp)
8099         return CM_ERROR_BADSMB;
8100
8101     spacep = inp->spacep;
8102     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8103
8104     if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
8105         return CM_ERROR_EXISTS;
8106
8107     userp = smb_GetUserFromVCP(vcp, inp);
8108
8109     caseFold = CM_FLAG_CASEFOLD;
8110
8111     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8112     if (code) {
8113         cm_ReleaseUser(userp);
8114         return CM_ERROR_NOSUCHPATH;
8115     }
8116
8117     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata,
8118                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
8119                     userp, tidPathp, &req, &dscp);
8120
8121     if (code) {
8122         cm_ReleaseUser(userp);
8123         return code;
8124     }
8125
8126 #ifdef DFS_SUPPORT
8127     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8128         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8129         cm_ReleaseSCache(dscp);
8130         cm_ReleaseUser(userp);
8131         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8132             return CM_ERROR_PATH_NOT_COVERED;
8133         else
8134             return CM_ERROR_NOSUCHPATH;
8135     }
8136 #endif /* DFS_SUPPORT */
8137
8138     /* otherwise, scp points to the parent directory.  Do a lookup, and
8139      * fail if we find it.  Otherwise, we do the create.
8140      */
8141     if (!lastNamep)
8142         lastNamep = pathp;
8143     else
8144         lastNamep++;
8145     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8146     if (scp) cm_ReleaseSCache(scp);
8147     if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8148         if (code == 0) code = CM_ERROR_EXISTS;
8149         cm_ReleaseSCache(dscp);
8150         cm_ReleaseUser(userp);
8151         return code;
8152     }
8153
8154     setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8155     setAttr.clientModTime = time(NULL);
8156     smb_SetInitialModeBitsForDir(0, &setAttr);
8157
8158     code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
8159     if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
8160         smb_NotifyChange(FILE_ACTION_ADDED,
8161                          FILE_NOTIFY_CHANGE_DIR_NAME,
8162                          dscp, lastNamep, NULL, TRUE);
8163
8164     /* we don't need this any longer */
8165     cm_ReleaseSCache(dscp);
8166
8167     if (code) {
8168         /* something went wrong creating or truncating the file */
8169         cm_ReleaseUser(userp);
8170         return code;
8171     }
8172
8173     /* otherwise we succeeded */
8174     smb_SetSMBDataLength(outp, 0);
8175     cm_ReleaseUser(userp);
8176
8177     return 0;
8178 }
8179
8180 BOOL smb_IsLegalFilename(clientchar_t *filename)
8181 {
8182     /*
8183      *  Find the longest substring of filename that does not contain
8184      *  any of the chars in illegalChars.  If that substring is less
8185      *  than the length of the whole string, then one or more of the
8186      *  illegal chars is in filename.
8187      */
8188     if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
8189         return FALSE;
8190
8191     return TRUE;
8192 }
8193
8194 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
8195 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8196 {
8197     clientchar_t *pathp;
8198     long code = 0;
8199     cm_space_t *spacep;
8200     unsigned char *tp;
8201     int excl;
8202     cm_user_t *userp;
8203     cm_scache_t *dscp;                  /* dir we're dealing with */
8204     cm_scache_t *scp;                   /* file we're creating */
8205     cm_attr_t setAttr;
8206     smb_fid_t *fidp;
8207     int attributes;
8208     clientchar_t *lastNamep;
8209     int caseFold;
8210     afs_uint32 dosTime;
8211     clientchar_t *tidPathp;
8212     cm_req_t req;
8213     int created = 0;                    /* the file was new */
8214
8215     smb_InitReq(&req);
8216
8217     scp = NULL;
8218     excl = (inp->inCom == 0x03)? 0 : 1;
8219
8220     attributes = smb_GetSMBParm(inp, 0);
8221     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
8222
8223     tp = smb_GetSMBData(inp, NULL);
8224     pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
8225     if (!pathp)
8226         return CM_ERROR_BADSMB;
8227
8228     spacep = inp->spacep;
8229     /* smb_StripLastComponent will strip "::$DATA" if present */
8230     smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
8231
8232     if (!cm_IsValidClientString(pathp)) {
8233 #ifdef DEBUG
8234         clientchar_t * hexp;
8235
8236         hexp = cm_GetRawCharsAlloc(pathp, -1);
8237         osi_Log1(smb_logp, "CoreCreate rejecting invalid name. [%S]",
8238                  osi_LogSaveClientString(smb_logp, hexp));
8239         if (hexp)
8240             free(hexp);
8241 #else
8242         osi_Log0(smb_logp, "CoreCreate rejecting invalid name");
8243 #endif
8244         return CM_ERROR_BADNTFILENAME;
8245     }
8246
8247     userp = smb_GetUserFromVCP(vcp, inp);
8248
8249     caseFold = CM_FLAG_CASEFOLD;
8250
8251     code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
8252     if (code) {
8253         cm_ReleaseUser(userp);
8254         return CM_ERROR_NOSUCHPATH;
8255     }
8256     code = cm_NameI(cm_RootSCachep(userp, &req), spacep->wdata, caseFold | CM_FLAG_FOLLOW,
8257                     userp, tidPathp, &req, &dscp);
8258
8259     if (code) {
8260         cm_ReleaseUser(userp);
8261         return code;
8262     }
8263
8264 #ifdef DFS_SUPPORT
8265     if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
8266         int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
8267         cm_ReleaseSCache(dscp);
8268         cm_ReleaseUser(userp);
8269         if ( WANTS_DFS_PATHNAMES(inp) || pnc )
8270             return CM_ERROR_PATH_NOT_COVERED;
8271         else
8272             return CM_ERROR_NOSUCHPATH;
8273     }
8274 #endif /* DFS_SUPPORT */
8275
8276     /* otherwise, scp points to the parent directory.  Do a lookup, and
8277      * truncate the file if we find it, otherwise we create the file.
8278      */
8279     if (!lastNamep)
8280         lastNamep = pathp;
8281     else
8282         lastNamep++;
8283
8284     if (!smb_IsLegalFilename(lastNamep))
8285         return CM_ERROR_BADNTFILENAME;
8286
8287     osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
8288 #ifdef DEBUG_VERBOSE
8289     {
8290         char *hexp;
8291         hexp = osi_HexifyString( lastNamep );
8292         DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
8293         free(hexp);
8294     }
8295 #endif
8296
8297     code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
8298     if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
8299         cm_ReleaseSCache(dscp);
8300         cm_ReleaseUser(userp);
8301         return code;
8302     }
8303
8304     /* if we get here, if code is 0, the file exists and is represented by
8305      * scp.  Otherwise, we have to create it.
8306      */
8307     if (code == 0) {
8308         if (excl) {
8309             /* oops, file shouldn't be there */
8310             cm_ReleaseSCache(dscp);
8311             cm_ReleaseSCache(scp);
8312             cm_ReleaseUser(userp);
8313             return CM_ERROR_EXISTS;
8314         }
8315
8316         setAttr.mask = CM_ATTRMASK_LENGTH;
8317         setAttr.length.LowPart = 0;
8318         setAttr.length.HighPart = 0;
8319         code = cm_SetAttr(scp, &setAttr, userp, &req);
8320     }
8321     else {
8322         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
8323         smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
8324         smb_SetInitialModeBitsForFile(attributes, &setAttr);
8325
8326         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
8327                          &req);
8328         if (code == 0) {
8329             created = 1;
8330             if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
8331                 smb_NotifyChange(FILE_ACTION_ADDED,
8332                                  FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
8333                                  dscp, lastNamep, NULL, TRUE);
8334         } else if (!excl && code == CM_ERROR_EXISTS) {
8335             /* not an exclusive create, and someone else tried
8336              * creating it already, then we open it anyway.  We
8337              * don't bother retrying after this, since if this next
8338              * fails, that means that the file was deleted after
8339              * we started this call.
8340              */
8341             code = cm_Lookup(dscp, lastNamep, caseFold, userp,
8342                              &req, &scp);
8343             if (code == 0) {
8344                 setAttr.mask = CM_ATTRMASK_LENGTH;
8345                 setAttr.length.LowPart = 0;
8346                 setAttr.length.HighPart = 0;
8347                 code = cm_SetAttr(scp, &setAttr, userp, &req);
8348             }
8349         }
8350     }
8351
8352     /* we don't need this any longer */
8353     cm_ReleaseSCache(dscp);
8354
8355     if (code) {
8356         /* something went wrong creating or truncating the file */
8357         if (scp) cm_ReleaseSCache(scp);
8358         cm_ReleaseUser(userp);
8359         return code;
8360     }
8361
8362     /* make sure we only open files */
8363     if (scp->fileType != CM_SCACHETYPE_FILE) {
8364         cm_ReleaseSCache(scp);
8365         cm_ReleaseUser(userp);
8366         return CM_ERROR_ISDIR;
8367     }
8368
8369     /* now all we have to do is open the file itself */
8370     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
8371     osi_assertx(fidp, "null smb_fid_t");
8372
8373     cm_HoldUser(userp);
8374
8375     lock_ObtainMutex(&fidp->mx);
8376     /* always create it open for read/write */
8377     fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
8378
8379     /* remember that the file was newly created */
8380     if (created)
8381         fidp->flags |= SMB_FID_CREATED;
8382
8383     osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
8384
8385     /* save a pointer to the vnode */
8386     fidp->scp = scp;
8387     lock_ObtainWrite(&scp->rw);
8388     scp->flags |= CM_SCACHEFLAG_SMB_FID;
8389     lock_ReleaseWrite(&scp->rw);
8390
8391     /* and the user */
8392     fidp->userp = userp;
8393     lock_ReleaseMutex(&fidp->mx);
8394
8395     smb_SetSMBParm(outp, 0, fidp->fid);
8396     smb_SetSMBDataLength(outp, 0);
8397
8398     cm_Open(scp, 0, userp);
8399
8400     smb_ReleaseFID(fidp);
8401     cm_ReleaseUser(userp);
8402     /* leave scp held since we put it in fidp->scp */
8403     return 0;
8404 }
8405
8406 /* SMB_COM_SEEK */
8407 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
8408 {
8409     long code = 0;
8410     osi_hyper_t new_offset;
8411     long offset;
8412     int whence;
8413     unsigned short fd;
8414     smb_fid_t *fidp;
8415     cm_scache_t *scp;
8416     cm_user_t *userp;
8417     cm_req_t req;
8418
8419     smb_InitReq(&req);
8420
8421     fd = smb_GetSMBParm(inp, 0);
8422     whence = smb_GetSMBParm(inp, 1);
8423     offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
8424
8425     /* try to find the file descriptor */
8426     fd = smb_ChainFID(fd, inp);
8427     fidp = smb_FindFID(vcp, fd, 0);
8428     if (!fidp) {
8429         osi_Log2(smb_logp, "smb_ReceiveCoreSeek Unknown SMB Fid vcp 0x%p fid %d",
8430                  vcp, fd);
8431         return CM_ERROR_BADFD;
8432     }
8433     lock_ObtainMutex(&fidp->mx);
8434     if (!fidp->scp || (fidp->flags & SMB_FID_IOCTL)) {
8435         lock_ReleaseMutex(&fidp->mx);
8436         smb_ReleaseFID(fidp);
8437         return CM_ERROR_BADFD;
8438     }
8439
8440     if (fidp->scp->flags & CM_SCACHEFLAG_DELETED) {
8441         lock_ReleaseMutex(&fidp->mx);
8442         smb_CloseFID(vcp, fidp, NULL, 0);
8443         smb_ReleaseFID(fidp);
8444         return CM_ERROR_NOSUCHFILE;
8445     }
8446
8447     lock_ReleaseMutex(&fidp->mx);
8448
8449     userp = smb_GetUserFromVCP(vcp, inp);
8450
8451     lock_ObtainMutex(&fidp->mx);
8452     scp = fidp->scp;
8453     cm_HoldSCache(scp);
8454     lock_ReleaseMutex(&fidp->mx);
8455     lock_ObtainWrite(&scp->rw);
8456     code = cm_SyncOp(scp, NULL, userp, &req, 0,
8457                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8458     if (code == 0) {
8459         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
8460         if (whence == 1) {
8461             /* offset from current offset */
8462             new_offset = LargeIntegerAdd(fidp->offset,
8463                                          ConvertLongToLargeInteger(offset));
8464         }
8465         else if (whence == 2) {
8466             /* offset from current EOF */
8467             new_offset = LargeIntegerAdd(scp->length,
8468                                          ConvertLongToLargeInteger(offset));
8469         } else {
8470             new_offset = ConvertLongToLargeInteger(offset);
8471         }
8472
8473         fidp->offset = new_offset;
8474         smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
8475         smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
8476         smb_SetSMBDataLength(outp, 0);
8477     }
8478     lock_ReleaseWrite(&scp->rw);
8479     smb_ReleaseFID(fidp);
8480     cm_ReleaseSCache(scp);
8481     cm_ReleaseUser(userp);
8482     return code;
8483 }
8484
8485 /* dispatch all of the requests received in a packet.  Due to chaining, this may
8486  * be more than one request.
8487  */
8488 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
8489                         NCB *ncbp, raw_write_cont_t *rwcp)
8490 {
8491     smb_dispatch_t *dp;
8492     smb_t *smbp;
8493     unsigned long code = 0;
8494     unsigned char *outWctp;
8495     int nparms;                 /* # of bytes of parameters */
8496     char tbuffer[200];
8497     int nbytes;                 /* bytes of data, excluding count */
8498     int temp;
8499     unsigned char *tp;
8500     unsigned short errCode;
8501     unsigned long NTStatus;
8502     int noSend;
8503     unsigned char errClass;
8504     unsigned int oldGen;
8505     DWORD oldTime, newTime;
8506
8507     /* get easy pointer to the data */
8508     smbp = (smb_t *) inp->data;
8509
8510     if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
8511         /* setup the basic parms for the initial request in the packet */
8512         inp->inCom = smbp->com;
8513         inp->wctp = &smbp->wct;
8514         inp->inCount = 0;
8515         inp->ncb_length = ncbp->ncb_length;
8516     }
8517     noSend = 0;
8518
8519     /* Sanity check */
8520     if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
8521         /* log it and discard it */
8522         LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
8523                  __FILE__, __LINE__, ncbp->ncb_length);
8524         osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
8525         return;
8526     }
8527
8528     /* We are an ongoing op */
8529     thrd_Increment(&ongoingOps);
8530
8531     /* set up response packet for receiving output */
8532     if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
8533         smb_FormatResponsePacket(vcp, inp, outp);
8534     outWctp = outp->wctp;
8535
8536     /* Remember session generation number and time */
8537     oldGen = sessionGen;
8538     oldTime = GetTickCount();
8539
8540     while (inp->inCom != 0xff) {
8541         dp = &smb_dispatchTable[inp->inCom];
8542
8543         if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
8544             outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
8545             code = outp->resumeCode;
8546             goto resume;
8547         }
8548
8549         /* process each request in the packet; inCom, wctp and inCount
8550          * are already set up.
8551          */
8552         osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
8553                   ncbp->ncb_lsn);
8554
8555         /* now do the dispatch */
8556         /* start by formatting the response record a little, as a default */
8557         if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
8558             outWctp[0] = 2;
8559             outWctp[1] = 0xff;  /* no operation */
8560             outWctp[2] = 0;             /* padding */
8561             outWctp[3] = 0;
8562             outWctp[4] = 0;
8563         }
8564         else {
8565             /* not a chained request, this is a more reasonable default */
8566             outWctp[0] = 0;     /* wct of zero */
8567             outWctp[1] = 0;     /* and bcc (word) of zero */
8568             outWctp[2] = 0;
8569         }
8570
8571         /* once set, stays set.  Doesn't matter, since we never chain
8572          * "no response" calls.
8573          */
8574         if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
8575             noSend = 1;
8576
8577         if (dp->procp) {
8578             /* we have a recognized operation */
8579             char * opName = myCrt_Dispatch(inp->inCom);
8580             smb_t *smbp;
8581
8582             smbp = (smb_t *) inp;
8583
8584             osi_Log5(smb_logp,"Dispatch %s mid 0x%x vcp 0x%p lana %d lsn %d",
8585                       opName, smbp->mid, vcp, vcp->lana, vcp->lsn);
8586             if (inp->inCom == 0x1d) {
8587                 /* Raw Write */
8588                 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
8589             } else {
8590                 code = (*(dp->procp)) (vcp, inp, outp);
8591             }
8592             osi_Log5(smb_logp,"Dispatch return code 0x%x mid 0x%x vcp 0x%p lana %d lsn %d",
8593                       code, smbp->mid, vcp, vcp->lana, vcp->lsn);
8594
8595             newTime = GetTickCount();
8596             osi_Log3(smb_logp, "Dispatch %s mid 0x%x duration %d ms",
8597                      opName, smbp->mid, newTime - oldTime);
8598
8599 #ifdef LOG_PACKET
8600             if ( code == CM_ERROR_BADSMB ||
8601                  code == CM_ERROR_BADOP )
8602                 smb_LogPacket(inp);
8603 #endif /* LOG_PACKET */
8604
8605             /* ReceiveV3Tran2A handles its own logging */
8606             if (inp->inCom != 0x32 && newTime - oldTime > 45000) {
8607                 smb_user_t *uidp;
8608                 smb_fid_t *fidp;
8609                 clientchar_t *treepath = NULL;  /* do not free */
8610                 clientchar_t *pathname = NULL;
8611                 cm_fid_t afid = {0,0,0,0,0};
8612
8613                 uidp = smb_FindUID(vcp, smbp->uid, 0);
8614                 smb_LookupTIDPath(vcp, smbp->tid, &treepath);
8615                 fidp = smb_FindFID(vcp, inp->fid, 0);
8616
8617                 if (fidp) {
8618                     lock_ObtainMutex(&fidp->mx);
8619                     if (fidp->NTopen_pathp)
8620                         pathname = fidp->NTopen_pathp;
8621                     if (fidp->scp)
8622                         afid = fidp->scp->fid;
8623                 } else {
8624                     if (inp->stringsp->wdata)
8625                         pathname = inp->stringsp->wdata;
8626                 }
8627
8628                 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)",
8629                           opName, newTime - oldTime,
8630                           smbp->uid, uidp ? uidp->unp->name : NULL,
8631                           smbp->pid, smbp->mid, smbp->tid,
8632                           treepath,
8633                           pathname,
8634                           afid.cell, afid.volume, afid.vnode, afid.unique);
8635
8636                 if (fidp)
8637                     lock_ReleaseMutex(&fidp->mx);
8638
8639                 if (uidp)
8640                     smb_ReleaseUID(uidp);
8641                 if (fidp)
8642                     smb_ReleaseFID(fidp);
8643             }
8644
8645             if (oldGen != sessionGen) {
8646                 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
8647                          newTime - oldTime, ncbp->ncb_length);
8648                 osi_Log3(smb_logp, "Request %s straddled session startup, "
8649                           "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
8650             }
8651
8652             FreeSMBStrings(inp);
8653         } else {
8654             /* bad opcode, fail the request, after displaying it */
8655             osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
8656 #ifdef LOG_PACKET
8657             smb_LogPacket(inp);
8658 #endif  /* LOG_PACKET */
8659
8660             if (showErrors) {
8661                 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
8662                 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
8663                                       MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
8664                 if (code == IDCANCEL)
8665                     showErrors = 0;
8666             }
8667             code = CM_ERROR_BADOP;
8668         }
8669
8670         /* catastrophic failure:  log as much as possible */
8671         if (code == CM_ERROR_BADSMB) {
8672             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
8673                      ncbp->ncb_length);
8674 #ifdef LOG_PACKET
8675             smb_LogPacket(inp);
8676 #endif /* LOG_PACKET */
8677             osi_Log1(smb_logp, "Invalid SMB message, length %d",
8678                      ncbp->ncb_length);
8679
8680             code = CM_ERROR_INVAL;
8681         }
8682
8683         if (outp->flags & SMB_PACKETFLAG_NOSEND) {
8684             thrd_Decrement(&ongoingOps);
8685             return;
8686         }
8687
8688       resume:
8689         /* now, if we failed, turn the current response into an empty
8690          * one, and fill in the response packet's error code.
8691          */
8692         if (code) {
8693             if (vcp->flags & SMB_VCFLAG_STATUS32) {
8694                 smb_MapNTError(code, &NTStatus);
8695                 outWctp = outp->wctp;
8696                 smbp = (smb_t *) &outp->data;
8697                 if (code != CM_ERROR_PARTIALWRITE
8698                      && code != CM_ERROR_BUFFERTOOSMALL
8699                      && code != CM_ERROR_GSSCONTINUE) {
8700                     /* nuke wct and bcc.  For a partial
8701                      * write or an in-process authentication handshake,
8702                      * assume they're OK.
8703                      */
8704                     *outWctp++ = 0;
8705                     *outWctp++ = 0;
8706                     *outWctp++ = 0;
8707                 }
8708                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8709                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8710                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8711                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8712                 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8713                 break;
8714             }
8715             else {
8716                 smb_MapCoreError(code, vcp, &errCode, &errClass);
8717                 outWctp = outp->wctp;
8718                 smbp = (smb_t *) &outp->data;
8719                 if (code != CM_ERROR_PARTIALWRITE) {
8720                     /* nuke wct and bcc.  For a partial
8721                      * write, assume they're OK.
8722                      */
8723                     *outWctp++ = 0;
8724                     *outWctp++ = 0;
8725                     *outWctp++ = 0;
8726                 }
8727                 smbp->errLow = (unsigned char) (errCode & 0xff);
8728                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8729                 smbp->rcls = errClass;
8730                 break;
8731             }
8732         }       /* error occurred */
8733
8734         /* if we're here, we've finished one request.  Look to see if
8735          * this is a chained opcode.  If it is, setup things to process
8736          * the chained request, and setup the output buffer to hold the
8737          * chained response.  Start by finding the next input record.
8738          */
8739         if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
8740             break;              /* not a chained req */
8741         tp = inp->wctp;         /* points to start of last request */
8742         /* in a chained request, the first two
8743          * parm fields are required, and are
8744          * AndXCommand/AndXReserved and
8745          * AndXOffset. */
8746         if (tp[0] < 2) break;
8747         if (tp[1] == 0xff) break;       /* no more chained opcodes */
8748         inp->inCom = tp[1];
8749         inp->wctp = inp->data + tp[3] + (tp[4] << 8);
8750         inp->inCount++;
8751
8752         /* and now append the next output request to the end of this
8753          * last request.  Begin by finding out where the last response
8754          * ends, since that's where we'll put our new response.
8755          */
8756         outWctp = outp->wctp;           /* ptr to out parameters */
8757         osi_assert (outWctp[0] >= 2);   /* need this for all chained requests */
8758         nparms = outWctp[0] << 1;
8759         tp = outWctp + nparms + 1;      /* now points to bcc field */
8760         nbytes = tp[0] + (tp[1] << 8);  /* # of data bytes */
8761         tp += 2 /* for the count itself */ + nbytes;
8762         /* tp now points to the new output record; go back and patch the
8763          * second parameter (off2) to point to the new record.
8764          */
8765         temp = (unsigned int)(tp - outp->data);
8766         outWctp[3] = (unsigned char) (temp & 0xff);
8767         outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
8768         outWctp[2] = 0; /* padding */
8769         outWctp[1] = inp->inCom;        /* next opcode */
8770
8771         /* finally, setup for the next iteration */
8772         outp->wctp = tp;
8773         outWctp = tp;
8774     }   /* while loop over all requests in the packet */
8775
8776     /* now send the output packet, and return */
8777     if (!noSend)
8778         smb_SendPacket(vcp, outp);
8779     thrd_Decrement(&ongoingOps);
8780
8781     return;
8782 }
8783
8784 /* Wait for Netbios() calls to return, and make the results available to server
8785  * threads.  Note that server threads can't wait on the NCBevents array
8786  * themselves, because NCB events are manual-reset, and the servers would race
8787  * each other to reset them.
8788  */
8789 void smb_ClientWaiter(void *parmp)
8790 {
8791     DWORD code;
8792     int   idx;
8793
8794     while (smbShutdownFlag == 0) {
8795         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
8796                                                  FALSE, INFINITE);
8797         if (code == WAIT_OBJECT_0)
8798             continue;
8799
8800         /* error checking */
8801         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8802         {
8803             int abandonIdx = code - WAIT_ABANDONED_0;
8804             osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8805         }
8806
8807         if (code == WAIT_IO_COMPLETION)
8808         {
8809             osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8810             continue;
8811         }
8812
8813         if (code == WAIT_TIMEOUT)
8814         {
8815             osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8816         }
8817
8818         if (code == WAIT_FAILED)
8819         {
8820             osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8821         }
8822
8823         idx = code - WAIT_OBJECT_0;
8824
8825         /* check idx range! */
8826         if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8827         {
8828             /* this is fatal - log as much as possible */
8829             osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8830             osi_assertx(0, "invalid index");
8831         }
8832
8833         thrd_ResetEvent(NCBevents[idx]);
8834         thrd_SetEvent(NCBreturns[0][idx]);
8835     }
8836 }
8837
8838 /*
8839  * Try to have one NCBRECV request waiting for every live session.  Not more
8840  * than one, because if there is more than one, it's hard to handle Write Raw.
8841  */
8842 void smb_ServerWaiter(void *parmp)
8843 {
8844     DWORD code;
8845     int idx_session, idx_NCB;
8846     NCB *ncbp;
8847
8848     while (smbShutdownFlag == 0) {
8849         /* Get a session */
8850         code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8851                                                  FALSE, INFINITE);
8852         if (code == WAIT_OBJECT_0)
8853             continue;
8854
8855         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8856         {
8857             int abandonIdx = code - WAIT_ABANDONED_0;
8858             osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8859         }
8860
8861         if (code == WAIT_IO_COMPLETION)
8862         {
8863             osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8864             continue;
8865         }
8866
8867         if (code == WAIT_TIMEOUT)
8868         {
8869             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8870         }
8871
8872         if (code == WAIT_FAILED)
8873         {
8874             osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8875         }
8876
8877         idx_session = code - WAIT_OBJECT_0;
8878
8879         /* check idx range! */
8880         if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8881         {
8882             /* this is fatal - log as much as possible */
8883             osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8884             osi_assertx(0, "invalid index");
8885         }
8886
8887                 /* Get an NCB */
8888       NCBretry:
8889         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8890                                                  FALSE, INFINITE);
8891         if (code == WAIT_OBJECT_0) {
8892             if (smbShutdownFlag == 1)
8893                 break;
8894             else
8895                 goto NCBretry;
8896         }
8897
8898         /* error checking */
8899         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8900         {
8901             int abandonIdx = code - WAIT_ABANDONED_0;
8902             osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8903         }
8904
8905         if (code == WAIT_IO_COMPLETION)
8906         {
8907             osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8908             continue;
8909         }
8910
8911         if (code == WAIT_TIMEOUT)
8912         {
8913             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8914         }
8915
8916         if (code == WAIT_FAILED)
8917         {
8918             osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8919         }
8920
8921         idx_NCB = code - WAIT_OBJECT_0;
8922
8923         /* check idx range! */
8924         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8925         {
8926             /* this is fatal - log as much as possible */
8927             osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8928             osi_assertx(0, "invalid index");
8929         }
8930
8931         /* Link them together */
8932         NCBsessions[idx_NCB] = idx_session;
8933
8934         /* Fire it up */
8935         ncbp = NCBs[idx_NCB];
8936         ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8937         ncbp->ncb_command = NCBRECV | ASYNCH;
8938         ncbp->ncb_lana_num = lanas[idx_session];
8939         ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8940         ncbp->ncb_event = NCBevents[idx_NCB];
8941         ncbp->ncb_length = SMB_PACKETSIZE;
8942         Netbios(ncbp);
8943     }
8944 }
8945
8946 typedef struct _monitored_task {
8947     osi_queue_t q;
8948     INT_PTR     task_id;
8949     LARGE_INTEGER start_time;
8950     BOOL        started;
8951     BOOL        trace_timer_hit;
8952     BOOL        dump_timer_hit;
8953 } monitored_task;
8954
8955 typedef struct osi_queueHT {
8956     osi_queue_t * headp;
8957     osi_queue_t * tailp;
8958 } osi_queueHT_t;
8959
8960 static osi_queue_t *smb_monitored_tasks = NULL;
8961 static osi_queue_t *smb_free_monitored_tasks = NULL;
8962
8963 static osi_mutex_t _monitor_mx;
8964
8965 static HANDLE h_monitored_task_queue    = NULL;
8966 static HANDLE h_monitored_task_shutdown = NULL;
8967
8968 static time_t smb_last_dump_time = 0;
8969
8970 DWORD  smb_monitorReqs = 0;
8971
8972 /* FILETIME comparison fuzz */
8973 #define MONITOR_FUZZ_TIMEOUT    (1 * 10000000i64)
8974
8975 /* Trace timeout is at 60 seconds */
8976 #define MONITOR_TRACE_TIMEOUT   (60 * 10000000i64)
8977
8978 /* Dump timeout is at 120 seconds */
8979 #define MONITOR_DUMP_TIMEOUT    (120 * 10000000i64)
8980
8981 /* Time before another dump is performed in seconds*/
8982 #define MONITOR_DUMP_RESET_TIMEOUT  (600)
8983
8984 static void smb_PurgeOldTaskMonitors(osi_queueHT_t * taskmq)
8985 {
8986     FILETIME now;
8987     LARGE_INTEGER earliest;
8988     monitored_task * t;
8989
8990     GetSystemTimeAsFileTime(&now);
8991     earliest.LowPart = now.dwLowDateTime;
8992     earliest.HighPart = now.dwHighDateTime;
8993     earliest.QuadPart -= MONITOR_FUZZ_TIMEOUT + MONITOR_DUMP_TIMEOUT;
8994
8995     while ((t = (monitored_task *) taskmq->headp) != NULL &&
8996
8997            (t->start_time.QuadPart < earliest.QuadPart ||
8998
8999             t->dump_timer_hit)) {
9000
9001         osi_QRemoveHT(&taskmq->headp,
9002                       &taskmq->tailp,
9003                       &t->q);
9004
9005         lock_ObtainMutex(&_monitor_mx);
9006         osi_QAdd(&smb_free_monitored_tasks, &t->q);
9007         lock_ReleaseMutex(&_monitor_mx);
9008     }
9009
9010 #ifdef INVARIANT_CHECK
9011     {
9012         LARGE_INTEGER last;
9013
9014         last.QuadPart = 0;
9015
9016         for (t = (monitored_task *) taskmq->headp;
9017              t;
9018              t = (monitored_task *) osi_QNext(&t->q)) {
9019             osi_assert(last.QuadPart <= t->start_time.QuadPart);
9020             last.QuadPart = t->start_time.QuadPart;
9021         }
9022     }
9023 #endif
9024 }
9025
9026 static void smb_SlurpNewTaskMonitors(osi_queueHT_t * taskmq)
9027 {
9028     monitored_task * task;
9029     monitored_task * tasks;
9030
9031     lock_ObtainMutex(&_monitor_mx);
9032     tasks = (monitored_task *) smb_monitored_tasks;
9033     smb_monitored_tasks = NULL;
9034     lock_ReleaseMutex(&_monitor_mx);
9035
9036     while (tasks) {
9037
9038         task = tasks;
9039         osi_QRemove((osi_queue_t **) &tasks, &task->q);
9040
9041         if (task->started) {
9042
9043             osi_queue_t q;
9044             osi_queue_t *p;
9045
9046             q.nextp = NULL;
9047             q.prevp = taskmq->tailp;
9048
9049             /* Insertion sort by start_time.  Earliest request is
9050                first.  Since we are likely to receive new requests
9051                later, we start inserting from the back. */
9052             for (p = &q;
9053                  osi_QPrev(p) &&
9054                      ((monitored_task *) osi_QPrev(p))->start_time.QuadPart > task->start_time.QuadPart;
9055                  p = osi_QPrev(p));
9056
9057             if (p == &q)
9058                 osi_QAddT(&taskmq->headp, &taskmq->tailp, &task->q);
9059             else if (p->prevp == NULL)
9060                 osi_QAddH(&taskmq->headp, &taskmq->tailp, &task->q);
9061             else {
9062                 osi_queue_t *o = p->prevp;
9063
9064                 osi_assert(o->nextp == p);
9065
9066                 task->q.nextp = p;
9067                 task->q.prevp = o;
9068                 p->prevp = &task->q;
9069                 o->nextp = &task->q;
9070             }
9071
9072         } else {
9073             /* Some task ending */
9074
9075             osi_queue_t * p;
9076
9077             for (p = taskmq->headp;
9078                  p != NULL;
9079                  p = osi_QNext(p)) {
9080
9081                 monitored_task * mt = (monitored_task *) p;
9082
9083                 if (mt->task_id == task->task_id) {
9084
9085                     osi_QRemoveHT(&taskmq->headp,
9086                                   &taskmq->tailp, p);
9087
9088                     lock_ObtainMutex(&_monitor_mx);
9089                     osi_QAdd(&smb_free_monitored_tasks, p);
9090                     lock_ReleaseMutex(&_monitor_mx);
9091
9092                     break;
9093                 }
9094             }
9095
9096             lock_ObtainMutex(&_monitor_mx);
9097             osi_QAdd(&smb_free_monitored_tasks, &task->q);
9098             lock_ReleaseMutex(&_monitor_mx);
9099         }
9100     }
9101
9102 #ifdef INVARIANT_CHECK
9103     {
9104         LARGE_INTEGER last;
9105         monitored_task * t;
9106
9107         last.QuadPart = 0;
9108
9109         for (t = (monitored_task *) taskmq->headp;
9110              t;
9111              t = (monitored_task *) osi_QNext(&t->q)) {
9112             osi_assert(last.QuadPart <= t->start_time.QuadPart);
9113             last.QuadPart = t->start_time.QuadPart;
9114         }
9115     }
9116 #endif
9117 }
9118
9119 static void smb_HandleTaskMonitorEvent(monitored_task * task)
9120 {
9121     if (!task->trace_timer_hit) {
9122
9123         task->trace_timer_hit = TRUE;
9124
9125         osi_LogEnable(afsd_logp);
9126         rx_DebugOnOff(TRUE);
9127
9128     } else if (!task->dump_timer_hit) {
9129         time_t now;
9130
9131         time(&now);
9132
9133         if (smb_last_dump_time + MONITOR_DUMP_RESET_TIMEOUT < now) {
9134             task->dump_timer_hit = TRUE;
9135             smb_last_dump_time = now;
9136
9137             GenerateMiniDump(NULL);
9138         }
9139     }
9140 }
9141
9142 /**
9143  * Server request monitoring
9144  *
9145  * The server monitor runs in a separate thread and monitors server
9146  * requests for potential timeouts.  It examines notifcations queued
9147  * by smb_NotifyRequestEvent() and waits for potential timeout events:
9148  *
9149  * - After MONITOR_TRACE_TIMEOUT threshold elapses, the monitor
9150  *   enables trace logging.
9151  *
9152  * - After MONITOR_DUMP_TIMEOUT threshold elapses, the monitor writes
9153  *   out a dump file that will hopefully contain enough evidence to
9154  *   figure out why the timeout event occurred.
9155  *
9156  */
9157 void smb_ServerMonitor(VOID * parmp)
9158 {
9159     osi_queueHT_t in_progress = { NULL, NULL };
9160     HANDLE h_timer = NULL;
9161
9162     HANDLE h_all[3];
9163
9164     h_monitored_task_queue = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitor");
9165     h_monitored_task_shutdown = CreateEvent(NULL, FALSE, FALSE, "Local\\OpenAFSTaskMonitorShutdown");
9166     h_timer = CreateWaitableTimer(NULL, FALSE, "Local\\OpenAFSTaskMonitorTimer");
9167
9168     lock_InitializeMutex(&_monitor_mx, "Request monitor lock", LOCK_HIERARCHY_SMB_MONITOR);
9169
9170     h_all[0] = h_monitored_task_queue;
9171     h_all[1] = h_timer;
9172     h_all[2] = h_monitored_task_shutdown;
9173
9174     while(1) {
9175         DWORD rv;
9176
9177         rv = WaitForMultipleObjects(3, h_all, FALSE, INFINITE);
9178
9179         if (rv == WAIT_OBJECT_0) {
9180
9181             smb_SlurpNewTaskMonitors(&in_progress);
9182
9183         } else if (rv == WAIT_OBJECT_0 + 1) {
9184
9185             smb_HandleTaskMonitorEvent((monitored_task *) in_progress.headp);
9186
9187         } else {
9188
9189             break;
9190
9191         }
9192
9193         /* refresh timers */
9194         {
9195             monitored_task * t;
9196
9197             smb_PurgeOldTaskMonitors(&in_progress);
9198             t = (monitored_task *) in_progress.headp;
9199
9200             if (t && !t->trace_timer_hit) {
9201                 LARGE_INTEGER due;
9202
9203                 due = t->start_time;
9204                 due.QuadPart += MONITOR_TRACE_TIMEOUT;
9205
9206                 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9207             } else if (t && !t->dump_timer_hit) {
9208
9209                 LARGE_INTEGER due;
9210
9211                 due = t->start_time;
9212                 due.QuadPart += MONITOR_DUMP_TIMEOUT;
9213
9214                 SetWaitableTimer(h_timer, &due, 0, NULL, NULL, FALSE);
9215             } else {
9216                 CancelWaitableTimer(h_timer);
9217
9218                 /* CancelWaitableTimer() doesn't reset the timer if it
9219                    was already signalled. */
9220                 WaitForSingleObject(h_timer, 0);
9221             }
9222         }
9223     }
9224
9225     {
9226         HANDLE h;
9227
9228         h = h_monitored_task_queue;
9229         h_monitored_task_queue = NULL;
9230         CloseHandle(h);
9231
9232         h = h_monitored_task_shutdown;
9233         h_monitored_task_shutdown = NULL;
9234         CloseHandle(h);
9235
9236         CloseHandle(h_timer);
9237
9238         lock_FinalizeMutex(&_monitor_mx);
9239     }
9240
9241     {
9242         monitored_task * task;
9243
9244         while (in_progress.headp) {
9245             task = (monitored_task *) in_progress.headp;
9246             osi_QRemoveHT(&in_progress.headp, &in_progress.tailp, &task->q);
9247             free(task);
9248         }
9249
9250         for (task = (monitored_task  *) smb_free_monitored_tasks;
9251              task; task = (monitored_task *) smb_free_monitored_tasks) {
9252             osi_QRemove(&smb_free_monitored_tasks, &task->q);
9253             free(task);
9254         }
9255
9256         for (task = (monitored_task *) smb_monitored_tasks;
9257              task; task = (monitored_task *) smb_monitored_tasks) {
9258             osi_QRemove(&smb_monitored_tasks, &task->q);
9259             free(task);
9260         }
9261     }
9262 }
9263
9264 void smb_NotifyRequestEvent(INT_PTR task_id, BOOL started)
9265 {
9266     monitored_task * task;
9267
9268     lock_ObtainMutex(&_monitor_mx);
9269     task = (monitored_task *) smb_free_monitored_tasks;
9270     if (task)
9271         osi_QRemove(&smb_free_monitored_tasks, &task->q);
9272     lock_ReleaseMutex(&_monitor_mx);
9273
9274     if (task == NULL)
9275         task = malloc(sizeof(monitored_task));
9276     memset(task, 0, sizeof(*task));
9277
9278     task->task_id = task_id;
9279     task->started = started;
9280
9281     {
9282         FILETIME now;
9283
9284         GetSystemTimeAsFileTime(&now);
9285         task->start_time.HighPart = now.dwHighDateTime;
9286         task->start_time.LowPart = now.dwLowDateTime;
9287     }
9288
9289     lock_ObtainMutex(&_monitor_mx);
9290     osi_QAdd(&smb_monitored_tasks, &task->q);
9291     lock_ReleaseMutex(&_monitor_mx);
9292
9293     SetEvent(h_monitored_task_queue);
9294 }
9295
9296 void smb_ShutdownMonitor()
9297 {
9298     SetEvent(h_monitored_task_shutdown);
9299 }
9300
9301 /*
9302  * The top level loop for handling SMB request messages.  Each server thread
9303  * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
9304  * NCB and buffer for the incoming request are loaned to us.
9305  *
9306  * Write Raw trickery starts here.  When we get a Write Raw, we are supposed
9307  * to immediately send a request for the rest of the data.  This must come
9308  * before any other traffic for that session, so we delay setting the session
9309  * event until that data has come in.
9310  */
9311 void smb_Server(VOID *parmp)
9312 {
9313     INT_PTR myIdx = (INT_PTR) parmp;
9314     NCB *ncbp;
9315     NCB *outncbp;
9316     smb_packet_t *bufp;
9317     smb_packet_t *outbufp;
9318     DWORD code, rcode;
9319     int idx_NCB, idx_session;
9320     UCHAR rc;
9321     smb_vc_t *vcp = NULL;
9322     smb_t *smbp;
9323
9324     rx_StartClientThread();
9325
9326     outncbp = smb_GetNCB();
9327     outbufp = smb_GetPacket();
9328     outbufp->ncbp = outncbp;
9329
9330     while (1) {
9331         if (vcp) {
9332             smb_ReleaseVC(vcp);
9333             vcp = NULL;
9334         }
9335
9336         cm_ResetServerPriority();
9337
9338         code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
9339                                                  FALSE, INFINITE);
9340
9341         /* terminate silently if shutdown flag is set */
9342         if (code == WAIT_OBJECT_0) {
9343             if (smbShutdownFlag == 1) {
9344                 thrd_SetEvent(smb_ServerShutdown[myIdx]);
9345                 break;
9346             } else
9347                 continue;
9348         }
9349
9350         /* error checking */
9351         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
9352         {
9353             int abandonIdx = code - WAIT_ABANDONED_0;
9354             osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
9355         }
9356
9357         if (code == WAIT_IO_COMPLETION)
9358         {
9359             osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
9360             continue;
9361         }
9362
9363         if (code == WAIT_TIMEOUT)
9364         {
9365             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
9366         }
9367
9368         if (code == WAIT_FAILED)
9369         {
9370             osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
9371         }
9372
9373         idx_NCB = code - WAIT_OBJECT_0;
9374
9375         /* check idx range! */
9376         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
9377         {
9378             /* this is fatal - log as much as possible */
9379             osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
9380             osi_assertx(0, "invalid index");
9381         }
9382
9383         ncbp = NCBs[idx_NCB];
9384         idx_session = NCBsessions[idx_NCB];
9385         rc = ncbp->ncb_retcode;
9386
9387         if (rc != NRC_PENDING && rc != NRC_GOODRET)
9388             osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
9389
9390         switch (rc) {
9391         case NRC_GOODRET:
9392             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9393             break;
9394
9395         case NRC_PENDING:
9396             /* Can this happen? Or is it just my UNIX paranoia? */
9397             osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
9398             continue;
9399
9400         case NRC_SNUMOUT:
9401         case NRC_SABORT:
9402             LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
9403             /* fallthrough */
9404         case NRC_SCLOSED:
9405             /* Client closed session */
9406             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9407             if (vcp) {
9408                 lock_ObtainMutex(&vcp->mx);
9409                 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9410                     osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9411                              vcp, vcp->usersp);
9412                     vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9413                     lock_ReleaseMutex(&vcp->mx);
9414                     lock_ObtainWrite(&smb_globalLock);
9415                     dead_sessions[vcp->session] = TRUE;
9416                     lock_ReleaseWrite(&smb_globalLock);
9417                 } else {
9418                     lock_ReleaseMutex(&vcp->mx);
9419                 }
9420                 smb_CleanupDeadVC(vcp);
9421                 smb_ReleaseVC(vcp);
9422                 vcp = NULL;
9423             }
9424             goto doneWithNCB;
9425
9426         case NRC_INCOMP:
9427             /* Treat as transient error */
9428             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
9429                      ncbp->ncb_length);
9430             osi_Log1(smb_logp,
9431                      "dispatch smb recv failed, message incomplete, ncb_length %d",
9432                      ncbp->ncb_length);
9433             osi_Log1(smb_logp,
9434                      "SMB message incomplete, "
9435                      "length %d", ncbp->ncb_length);
9436
9437             /*
9438              * We used to discard the packet.
9439              * Instead, try handling it normally.
9440              *
9441              continue;
9442              */
9443             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9444             break;
9445
9446         default:
9447             /* A weird error code.  Log it, sleep, and continue. */
9448             vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
9449             if (vcp) {
9450                 lock_ObtainMutex(&vcp->mx);
9451                 if (vcp->errorCount++ > 3) {
9452                     osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
9453                     if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9454                         osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9455                                  vcp, vcp->usersp);
9456                         vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9457                         lock_ReleaseMutex(&vcp->mx);
9458                         lock_ObtainWrite(&smb_globalLock);
9459                         dead_sessions[vcp->session] = TRUE;
9460                         lock_ReleaseWrite(&smb_globalLock);
9461                     } else {
9462                         lock_ReleaseMutex(&vcp->mx);
9463                     }
9464                     smb_CleanupDeadVC(vcp);
9465                     smb_ReleaseVC(vcp);
9466                     vcp = NULL;
9467                     goto doneWithNCB;
9468                 }
9469                 else {
9470                     lock_ReleaseMutex(&vcp->mx);
9471                     smb_ReleaseVC(vcp);
9472                     vcp = NULL;
9473                     Sleep(10);
9474                     thrd_SetEvent(SessionEvents[idx_session]);
9475                 }
9476             }
9477             continue;
9478         }
9479
9480         /* Success, so now dispatch on all the data in the packet */
9481
9482         smb_concurrentCalls++;
9483         if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
9484             smb_maxObsConcurrentCalls = smb_concurrentCalls;
9485
9486         /*
9487          * If at this point vcp is NULL (implies that packet was invalid)
9488          * then we are in big trouble. This means either :
9489          *   a) we have the wrong NCB.
9490          *   b) Netbios screwed up the call.
9491          *   c) The VC was already marked dead before we were able to
9492          *      process the call
9493          * Obviously this implies that
9494          *   ( LSNs[idx_session] != ncbp->ncb_lsn ||
9495          *   lanas[idx_session] != ncbp->ncb_lana_num )
9496          * Either way, we can't do anything with this packet.
9497          * Log, sleep and resume.
9498          */
9499         if (!vcp) {
9500             LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
9501                      LSNs[idx_session],
9502                      lanas[idx_session],
9503                      ncbp->ncb_lsn,
9504                      ncbp->ncb_lana_num);
9505
9506             /* Also log in the trace log. */
9507             osi_Log4(smb_logp, "Server: VCP does not exist!"
9508                       "LSNs[idx_session]=[%d],"
9509                       "lanas[idx_session]=[%d],"
9510                       "ncbp->ncb_lsn=[%d],"
9511                       "ncbp->ncb_lana_num=[%d]",
9512                       LSNs[idx_session],
9513                       lanas[idx_session],
9514                       ncbp->ncb_lsn,
9515                       ncbp->ncb_lana_num);
9516
9517             /* thrd_Sleep(1000); Don't bother sleeping */
9518             thrd_SetEvent(SessionEvents[idx_session]);
9519             smb_concurrentCalls--;
9520             continue;
9521         }
9522
9523         cm_SetRequestStartTime();
9524         if (smb_monitorReqs) {
9525             smb_NotifyRequestEvent(GetCurrentThreadId(), TRUE);
9526         }
9527
9528         vcp->errorCount = 0;
9529         bufp = (struct smb_packet *) ncbp->ncb_buffer;
9530         smbp = (smb_t *)bufp->data;
9531         outbufp->flags = 0;
9532
9533 #ifndef NOTRACE
9534         __try
9535         {
9536 #endif
9537             if (smbp->com == 0x1d) {
9538                 /* Special handling for Write Raw */
9539                 raw_write_cont_t rwc;
9540
9541                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
9542                 if (rwc.code == 0) {
9543                     EVENT_HANDLE rwevent;
9544                     char eventName[MAX_PATH];
9545
9546                     snprintf(eventName, MAX_PATH, "smb_Server() rwevent %d", myIdx);
9547                     rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9548                     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9549                         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9550
9551                     ncbp->ncb_command = NCBRECV | ASYNCH;
9552                     ncbp->ncb_lsn = (unsigned char) vcp->lsn;
9553                     ncbp->ncb_lana_num = vcp->lana;
9554                     ncbp->ncb_buffer = rwc.buf;
9555                     ncbp->ncb_length = 65535;
9556                     ncbp->ncb_event = rwevent;
9557                     Netbios(ncbp);
9558                     rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
9559                     thrd_CloseHandle(rwevent);
9560                 }
9561                 thrd_SetEvent(SessionEvents[idx_session]);
9562                 if (rwc.code == 0)
9563                     smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
9564             }
9565             else if (smbp->com == 0xa0) {
9566                 /*
9567                  * Serialize the handling for NT Transact
9568                  * (defect 11626)
9569                  */
9570                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9571                 thrd_SetEvent(SessionEvents[idx_session]);
9572             } else {
9573                 thrd_SetEvent(SessionEvents[idx_session]);
9574                 /* TODO: what else needs to be serialized? */
9575                 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
9576             }
9577 #ifndef NOTRACE
9578         }
9579         __except( smb_ServerExceptionFilter() ) {
9580         }
9581 #endif
9582
9583         if (smb_monitorReqs) {
9584             smb_NotifyRequestEvent(GetCurrentThreadId(), FALSE);
9585         }
9586         smb_concurrentCalls--;
9587
9588       doneWithNCB:
9589         thrd_SetEvent(NCBavails[idx_NCB]);
9590     }
9591     if (vcp)
9592         smb_ReleaseVC(vcp);
9593     if (outbufp)
9594         smb_FreePacket(outbufp);
9595     if (outncbp)
9596         smb_FreeNCB(outncbp);
9597 }
9598
9599 /*
9600  * Exception filter for the server threads.  If an exception occurs in the
9601  * dispatch routines, which is where exceptions are most common, then do a
9602  * force trace and give control to upstream exception handlers. Useful for
9603  * debugging.
9604  */
9605 DWORD smb_ServerExceptionFilter(void) {
9606     /* While this is not the best time to do a trace, if it succeeds, then
9607      * we have a trace (assuming tracing was enabled). Otherwise, this should
9608      * throw a second exception.
9609      */
9610     LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
9611     afsd_ForceTrace(TRUE);
9612     buf_ForceTrace(TRUE);
9613     return EXCEPTION_CONTINUE_SEARCH;
9614 }
9615
9616 /*
9617  * Create a new NCB and associated events, packet buffer, and "space" buffer.
9618  * If the number of server threads is M, and the number of live sessions is
9619  * N, then the number of NCB's in use at any time either waiting for, or
9620  * holding, received messages is M + N, so that is how many NCB's get created.
9621  */
9622 void InitNCBslot(int idx)
9623 {
9624     struct smb_packet *bufp;
9625     EVENT_HANDLE retHandle;
9626     afs_uint32 i;
9627     char eventName[MAX_PATH];
9628
9629     osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
9630
9631     NCBs[idx] = smb_GetNCB();
9632     sprintf(eventName,"NCBavails[%d]", idx);
9633     NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9634     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9635         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9636     sprintf(eventName,"NCBevents[%d]", idx);
9637     NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
9638     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9639         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9640     sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
9641     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9642     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9643         osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9644     for (i=0; i<smb_NumServerThreads; i++)
9645         NCBreturns[i][idx] = retHandle;
9646     bufp = smb_GetPacket();
9647     bufp->spacep = cm_GetSpace();
9648     bufs[idx] = bufp;
9649 }
9650
9651 /* listen for new connections */
9652 void smb_Listener(void *parmp)
9653 {
9654     NCB *ncbp;
9655     long code = 0;
9656     long len;
9657     long i;
9658     afs_uint32  session, thread;
9659     smb_vc_t *vcp = NULL;
9660     int flags = 0;
9661     char rname[NCBNAMSZ+1];
9662     char cname[MAX_COMPUTERNAME_LENGTH+1];
9663     int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
9664     INT_PTR lana = (INT_PTR) parmp;
9665     char eventName[MAX_PATH];
9666     int bridgeCount = 0;
9667     int nowildCount = 0;
9668
9669     sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
9670     ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9671     if ( GetLastError() == ERROR_ALREADY_EXISTS )
9672         thrd_ResetEvent(ListenerShutdown[lana]);
9673
9674     ncbp = smb_GetNCB();
9675
9676     /* retrieve computer name */
9677     GetComputerName(cname, &cnamelen);
9678     _strupr(cname);
9679
9680     while (smb_ListenerState == SMB_LISTENER_STARTED) {
9681         memset(ncbp, 0, sizeof(NCB));
9682         flags = 0;
9683
9684         ncbp->ncb_command = NCBLISTEN;
9685         ncbp->ncb_rto = 0;      /* No receive timeout */
9686         ncbp->ncb_sto = 0;      /* No send timeout */
9687
9688         /* pad out with spaces instead of null termination */
9689         len = (long)strlen(smb_localNamep);
9690         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9691         for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9692
9693         strcpy(ncbp->ncb_callname, "*");
9694         for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
9695
9696         ncbp->ncb_lana_num = (UCHAR)lana;
9697
9698         code = Netbios(ncbp);
9699
9700         if (code == NRC_NAMERR) {
9701           /* An smb shutdown or Vista resume must have taken place */
9702           osi_Log1(smb_logp,
9703                    "NCBLISTEN lana=%d failed with NRC_NAMERR.",
9704                    ncbp->ncb_lana_num);
9705           afsi_log("NCBLISTEN lana=%d failed with NRC_NAMERR.", ncbp->ncb_lana_num);
9706
9707             if (lock_TryMutex(&smb_StartedLock)) {
9708                 lana_list.lana[i] = LANA_INVALID;
9709                 lock_ReleaseMutex(&smb_StartedLock);
9710             }
9711             break;
9712         } else if (code ==  NRC_BRIDGE || code != 0) {
9713             int lanaRemaining = 0;
9714
9715             if (code == NRC_BRIDGE) {
9716                 if (++bridgeCount <= 5) {
9717                     afsi_log("NCBLISTEN lana=%d failed with NRC_BRIDGE, retrying ...", ncbp->ncb_lana_num);
9718                     continue;
9719                 }
9720             } else if (code == NRC_NOWILD) {
9721                 if (++nowildCount <= 5) {
9722                     afsi_log("NCBLISTEN lana=%d failed with NRC_NOWILD, retrying ...", ncbp->ncb_lana_num);
9723
9724                     if (bridgeCount > 0) {
9725                         memset(ncbp, 0, sizeof(*ncbp));
9726                         ncbp->ncb_command = NCBADDNAME;
9727                         ncbp->ncb_lana_num = (UCHAR)lana;
9728                         /* pad out with spaces instead of null termination */
9729                         len = (long)strlen(smb_localNamep);
9730                         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
9731                         for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
9732                         code = Netbios(ncbp);
9733                     }
9734                     continue;
9735                 }
9736             }
9737
9738             while (!lock_TryMutex(&smb_StartedLock)) {
9739                 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9740                     goto exit_thread;
9741                 Sleep(50);
9742             }
9743
9744             osi_Log2(smb_logp,
9745                       "NCBLISTEN lana=%d failed with %s.  Listener thread exiting.",
9746                       ncbp->ncb_lana_num, ncb_error_string(code));
9747             afsi_log("NCBLISTEN lana=%d failed with %s.  Listener thread exiting.",
9748                      ncbp->ncb_lana_num, ncb_error_string(code));
9749
9750             for (i = 0; i < lana_list.length; i++) {
9751                 if (lana_list.lana[i] == lana) {
9752                     smb_StopListener(ncbp, lana_list.lana[i], FALSE);
9753                     lana_list.lana[i] = LANA_INVALID;
9754                 }
9755                 if (lana_list.lana[i] != LANA_INVALID)
9756                     lanaRemaining++;
9757             }
9758
9759             if (lanaRemaining == 0) {
9760                 cm_VolStatus_Network_Stopped(cm_NetbiosName
9761 #ifdef _WIN64
9762                                              ,cm_NetbiosName
9763 #endif
9764                                               );
9765                 smb_ListenerState = SMB_LISTENER_STOPPED;
9766                 smb_LANadapter = LANA_INVALID;
9767                 lana_list.length = 0;
9768             }
9769             lock_ReleaseMutex(&smb_StartedLock);
9770             break;
9771         }
9772 #if 0
9773         else if (code != 0) {
9774             char tbuffer[AFSPATHMAX];
9775
9776             /* terminate silently if shutdown flag is set */
9777             while (!lock_TryMutex(&smb_StartedLock)) {
9778                 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
9779                     goto exit_thread;
9780                 Sleep(50);
9781             }
9782
9783             osi_Log3(smb_logp,
9784                      "NCBLISTEN lana=%d failed with code %d [%s]",
9785                      ncbp->ncb_lana_num, code, ncb_error_string(code));
9786             osi_Log0(smb_logp,
9787                      "Client exiting due to network failure. Please restart client.\n");
9788
9789             sprintf(tbuffer,
9790                      "Client exiting due to network failure.  Please restart client.\n"
9791                      "NCBLISTEN lana=%d failed with code %d [%s]",
9792                      ncbp->ncb_lana_num, code, ncb_error_string(code));
9793             if (showErrors)
9794                 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
9795                                       MB_OK|MB_SERVICE_NOTIFICATION);
9796             osi_panic(tbuffer, __FILE__, __LINE__);
9797
9798             lock_ReleaseMutex(&smb_StartedLock);
9799             break;
9800         }
9801 #endif /* 0 */
9802
9803         /* a successful packet received.  clear bridge error count */
9804         bridgeCount = 0;
9805         nowildCount = 0;
9806
9807         /* check for remote conns */
9808         /* first get remote name and insert null terminator */
9809         memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
9810         for (i=NCBNAMSZ; i>0; i--) {
9811             if (rname[i-1] != ' ' && rname[i-1] != 0) {
9812                 rname[i] = 0;
9813                 break;
9814             }
9815         }
9816
9817         /* compare with local name */
9818         if (!isGateway)
9819             if (strncmp(rname, cname, NCBNAMSZ) != 0)
9820                 flags |= SMB_VCFLAG_REMOTECONN;
9821
9822         /* lock */
9823         lock_ObtainMutex(&smb_ListenerLock);
9824
9825         osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
9826         osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
9827
9828         /* now ncbp->ncb_lsn is the connection ID */
9829         vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
9830         if (vcp->session == 0) {
9831             /* New generation */
9832             osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
9833             sessionGen++;
9834
9835             /* Log session startup */
9836 #ifdef NOTSERVICE
9837             fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9838                     ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9839 #endif /* NOTSERVICE */
9840             osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9841                      ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9842
9843             if (reportSessionStartups) {
9844                 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9845             }
9846
9847             lock_ObtainMutex(&vcp->mx);
9848             cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
9849             vcp->flags |= flags;
9850             lock_ReleaseMutex(&vcp->mx);
9851
9852             /* Allocate slot in session arrays */
9853             /* Re-use dead session if possible, otherwise add one more */
9854             /* But don't look at session[0], it is reserved */
9855             lock_ObtainWrite(&smb_globalLock);
9856             for (session = 1; session < numSessions; session++) {
9857                 if (dead_sessions[session]) {
9858                     osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
9859                     dead_sessions[session] = FALSE;
9860                     break;
9861                 }
9862             }
9863             lock_ReleaseWrite(&smb_globalLock);
9864         } else {
9865             /* We are re-using an existing VC because the lsn and lana
9866              * were re-used */
9867             session = vcp->session;
9868
9869             osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
9870
9871             /* Log session startup */
9872 #ifdef NOTSERVICE
9873             fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
9874                     ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
9875 #endif /* NOTSERVICE */
9876             osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
9877                      ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
9878
9879             if (reportSessionStartups) {
9880                 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
9881             }
9882         }
9883
9884         if (session >= SESSION_MAX - 1  || numNCBs >= NCB_MAX - 1) {
9885             unsigned long code = CM_ERROR_ALLBUSY;
9886             smb_packet_t * outp = smb_GetPacket();
9887             unsigned char *outWctp;
9888             smb_t *smbp;
9889
9890             smb_FormatResponsePacket(vcp, NULL, outp);
9891             outp->ncbp = ncbp;
9892
9893             if (vcp->flags & SMB_VCFLAG_STATUS32) {
9894                 unsigned long NTStatus;
9895                 smb_MapNTError(code, &NTStatus);
9896                 outWctp = outp->wctp;
9897                 smbp = (smb_t *) &outp->data;
9898                 *outWctp++ = 0;
9899                 *outWctp++ = 0;
9900                 *outWctp++ = 0;
9901                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
9902                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
9903                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
9904                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
9905                 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
9906             } else {
9907                 unsigned short errCode;
9908                 unsigned char errClass;
9909                 smb_MapCoreError(code, vcp, &errCode, &errClass);
9910                 outWctp = outp->wctp;
9911                 smbp = (smb_t *) &outp->data;
9912                 *outWctp++ = 0;
9913                 *outWctp++ = 0;
9914                 *outWctp++ = 0;
9915                 smbp->errLow = (unsigned char) (errCode & 0xff);
9916                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
9917                 smbp->rcls = errClass;
9918             }
9919
9920             smb_SendPacket(vcp, outp);
9921             smb_FreePacket(outp);
9922
9923             lock_ObtainMutex(&vcp->mx);
9924             if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
9925                 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
9926                           vcp, vcp->usersp);
9927                 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
9928                 lock_ReleaseMutex(&vcp->mx);
9929                 lock_ObtainWrite(&smb_globalLock);
9930                 dead_sessions[vcp->session] = TRUE;
9931                 lock_ReleaseWrite(&smb_globalLock);
9932                 smb_CleanupDeadVC(vcp);
9933             } else {
9934                 lock_ReleaseMutex(&vcp->mx);
9935             }
9936         } else {
9937             /* assert that we do not exceed the maximum number of sessions or NCBs.
9938              * we should probably want to wait for a session to be freed in case
9939              * we run out.
9940              */
9941             osi_assertx(session < SESSION_MAX - 1, "invalid session");
9942             osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs");   /* if we pass this test we can allocate one more */
9943
9944             lock_ObtainMutex(&vcp->mx);
9945             vcp->session   = session;
9946             lock_ReleaseMutex(&vcp->mx);
9947             lock_ObtainWrite(&smb_globalLock);
9948             LSNs[session]  = ncbp->ncb_lsn;
9949             lanas[session] = ncbp->ncb_lana_num;
9950             lock_ReleaseWrite(&smb_globalLock);
9951
9952             if (session == numSessions) {
9953                 /* Add new NCB for new session */
9954                 char eventName[MAX_PATH];
9955
9956                 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
9957
9958                 InitNCBslot(numNCBs);
9959                 lock_ObtainWrite(&smb_globalLock);
9960                 numNCBs++;
9961                 lock_ReleaseWrite(&smb_globalLock);
9962                 thrd_SetEvent(NCBavails[0]);
9963                 thrd_SetEvent(NCBevents[0]);
9964                 for (thread = 0; thread < smb_NumServerThreads; thread++)
9965                     thrd_SetEvent(NCBreturns[thread][0]);
9966                 /* Also add new session event */
9967                 sprintf(eventName, "SessionEvents[%d]", session);
9968                 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
9969                 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9970                     osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
9971                 lock_ObtainWrite(&smb_globalLock);
9972                 numSessions++;
9973                 lock_ReleaseWrite(&smb_globalLock);
9974                 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
9975                 thrd_SetEvent(SessionEvents[0]);
9976             } else {
9977                 thrd_SetEvent(SessionEvents[session]);
9978             }
9979         }
9980         smb_ReleaseVC(vcp);
9981
9982         /* unlock */
9983         lock_ReleaseMutex(&smb_ListenerLock);
9984     }   /* dispatch while loop */
9985
9986 exit_thread:
9987     smb_FreeNCB(ncbp);
9988     thrd_SetEvent(ListenerShutdown[lana]);
9989     return;
9990 }
9991
9992 static void
9993 configureBackConnectionHostNames(void)
9994 {
9995     /* On Windows XP SP2, Windows 2003 SP1, and all future Windows operating systems
9996      * there is a restriction on the use of SMB authentication on loopback connections.
9997      * There are two work arounds available:
9998      *
9999      *   (1) We can disable the check for matching host names.  This does not
10000      *   require a reboot:
10001      *   [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
10002      *     "DisableLoopbackCheck"=dword:00000001
10003      *
10004      *   (2) We can add the AFS SMB/CIFS service name to an approved list.  This
10005      *   does require a reboot:
10006      *   [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0]
10007      *     "BackConnectionHostNames"=multi-sz
10008      *
10009      * The algorithm will be:
10010      *   (1) Check to see if cm_NetbiosName exists in the BackConnectionHostNames list
10011      *   (2a) If not, add it to the list.  (This will not take effect until the next reboot.)
10012      *   (2b1)    and check to see if DisableLoopbackCheck is set.
10013      *   (2b2)    If not set, set the DisableLoopbackCheck value to 0x1
10014      *   (2b3)                and create HKLM\SOFTWARE\OpenAFS\Client  UnsetDisableLoopbackCheck
10015      *   (2c) else If cm_NetbiosName exists in the BackConnectionHostNames list,
10016      *             check for the UnsetDisableLoopbackCheck value.
10017      *             If set, set the DisableLoopbackCheck flag to 0x0
10018      *             and delete the UnsetDisableLoopbackCheck value
10019      *
10020      * Starting in Longhorn Beta 1, an entry in the BackConnectionHostNames value will
10021      * force Windows to use the loopback authentication mechanism for the specified
10022      * services.
10023      *
10024      * Do not permit the "DisableLoopbackCheck" value to be removed within the same
10025      * service session that set it.
10026      */
10027     HKEY hkLsa;
10028     HKEY hkMSV10;
10029     HKEY hkClient;
10030     DWORD dwType;
10031     DWORD dwSize, dwAllocSize;
10032     DWORD dwValue;
10033     PBYTE pHostNames = NULL, pName = NULL;
10034     BOOL  bNameFound = FALSE;
10035     static BOOL bLoopbackCheckDisabled = FALSE;
10036
10037     /* BackConnectionHostNames and DisableLoopbackCheck */
10038     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10039                        "SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0",
10040                        0,
10041                        KEY_READ|KEY_WRITE,
10042                        &hkMSV10) == ERROR_SUCCESS )
10043     {
10044         if ((RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0,
10045                              &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10046             (dwType == REG_MULTI_SZ))
10047         {
10048             dwAllocSize += 1 /* in case the source string is not nul terminated */
10049                 + (DWORD)strlen(cm_NetbiosName) + 2;
10050             pHostNames = malloc(dwAllocSize);
10051             dwSize = dwAllocSize;
10052             if (RegQueryValueEx( hkMSV10, "BackConnectionHostNames", 0, &dwType,
10053                                  pHostNames, &dwSize) == ERROR_SUCCESS)
10054             {
10055                 for (pName = pHostNames;
10056                      (pName - pHostNames < (int) dwSize) && *pName ;
10057                      pName += strlen(pName) + 1)
10058                 {
10059                     if ( !stricmp(pName, cm_NetbiosName) ) {
10060                         bNameFound = TRUE;
10061                         break;
10062                     }
10063                 }
10064             }
10065         }
10066
10067         if ( !bNameFound ) {
10068             size_t size = strlen(cm_NetbiosName) + 2;
10069             if ( !pHostNames ) {
10070                 pHostNames = malloc(size);
10071                 pName = pHostNames;
10072             }
10073             StringCbCopyA(pName, size, cm_NetbiosName);
10074             pName += size - 1;
10075             *pName = '\0';  /* add a second nul terminator */
10076
10077             dwType = REG_MULTI_SZ;
10078             dwSize = (DWORD)(pName - pHostNames + 1);
10079             RegSetValueEx( hkMSV10, "BackConnectionHostNames", 0, dwType, pHostNames, dwSize);
10080
10081             if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10082                                "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10083                                0,
10084                                KEY_READ|KEY_WRITE,
10085                                &hkLsa) == ERROR_SUCCESS )
10086             {
10087                 dwSize = sizeof(DWORD);
10088                 if ( RegQueryValueEx( hkLsa, "DisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) != ERROR_SUCCESS ||
10089                      dwValue == 0 ) {
10090                     dwType = REG_DWORD;
10091                     dwSize = sizeof(DWORD);
10092                     dwValue = 1;
10093                     RegSetValueEx( hkLsa, "DisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10094
10095                     if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10096                                         AFSREG_CLT_OPENAFS_SUBKEY,
10097                                         0,
10098                                         NULL,
10099                                         REG_OPTION_NON_VOLATILE,
10100                                         KEY_READ|KEY_WRITE,
10101                                         NULL,
10102                                         &hkClient,
10103                                         NULL) == ERROR_SUCCESS) {
10104
10105                         dwType = REG_DWORD;
10106                         dwSize = sizeof(DWORD);
10107                         dwValue = 1;
10108                         RegSetValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, dwType, (LPBYTE)&dwValue, dwSize);
10109                         bLoopbackCheckDisabled = TRUE;
10110                         RegCloseKey(hkClient);
10111                     }
10112                     RegCloseKey(hkLsa);
10113                 }
10114             }
10115         } else if (!bLoopbackCheckDisabled) {
10116             if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
10117                                 AFSREG_CLT_OPENAFS_SUBKEY,
10118                                 0,
10119                                 NULL,
10120                                 REG_OPTION_NON_VOLATILE,
10121                                 KEY_READ|KEY_WRITE,
10122                                 NULL,
10123                                 &hkClient,
10124                                 NULL) == ERROR_SUCCESS) {
10125
10126                 dwSize = sizeof(DWORD);
10127                 if ( RegQueryValueEx( hkClient, "RemoveDisableLoopbackCheck", 0, &dwType, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS &&
10128                      dwValue == 1 ) {
10129                     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10130                                        "SYSTEM\\CurrentControlSet\\Control\\Lsa",
10131                                        0,
10132                                        KEY_READ|KEY_WRITE,
10133                                        &hkLsa) == ERROR_SUCCESS )
10134                     {
10135                         RegDeleteValue(hkLsa, "DisableLoopbackCheck");
10136                         RegCloseKey(hkLsa);
10137                     }
10138                 }
10139                 RegDeleteValue(hkClient, "RemoveDisableLoopbackCheck");
10140                 RegCloseKey(hkClient);
10141             }
10142         }
10143
10144         if (pHostNames) {
10145             free(pHostNames);
10146             pHostNames = NULL;
10147         }
10148
10149         RegCloseKey(hkMSV10);
10150     }
10151 }
10152
10153
10154 static void
10155 configureExtendedSMBSessionTimeouts(void)
10156 {
10157     /*
10158      * In a Hot Fix to Windows 2003 SP2, the smb redirector was given the following
10159      * new functionality:
10160      *
10161      *  [HKLM\SYSTEM\CurrentControlSet\Services\LanManWorkstation\Parameters]
10162      *   "ReconnectableServers"            REG_MULTI_SZ
10163      *   "ExtendedSessTimeout"             REG_DWORD  (seconds)
10164      *   "ServersWithExtendedSessTimeout"  REG_MULTI_SZ
10165      *
10166      * These values can be used to prevent the smb redirector from timing out
10167      * smb connection to the afs smb server prematurely.
10168      */
10169     HKEY hkLanMan;
10170     DWORD dwType;
10171     DWORD dwSize, dwAllocSize;
10172     DWORD dwValue;
10173     PBYTE pHostNames = NULL, pName = NULL;
10174     BOOL  bNameFound = FALSE;
10175
10176     if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
10177                        "SYSTEM\\CurrentControlSet\\Services\\LanManWorkstation\\Parameters",
10178                        0,
10179                        KEY_READ|KEY_WRITE,
10180                        &hkLanMan) == ERROR_SUCCESS )
10181     {
10182         if ((RegQueryValueEx( hkLanMan, "ReconnectableServers", 0,
10183                              &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10184             (dwType == REG_MULTI_SZ))
10185         {
10186             dwAllocSize += 1 /* in case the source string is not nul terminated */
10187                 + (DWORD)strlen(cm_NetbiosName) + 2;
10188             pHostNames = malloc(dwAllocSize);
10189             dwSize = dwAllocSize;
10190             if (RegQueryValueEx( hkLanMan, "ReconnectableServers", 0, &dwType,
10191                                  pHostNames, &dwSize) == ERROR_SUCCESS)
10192             {
10193                 for (pName = pHostNames;
10194                      (pName - pHostNames < (int) dwSize) && *pName ;
10195                      pName += strlen(pName) + 1)
10196                 {
10197                     if ( !stricmp(pName, cm_NetbiosName) ) {
10198                         bNameFound = TRUE;
10199                         break;
10200                     }
10201                 }
10202             }
10203         }
10204
10205         if ( !bNameFound ) {
10206             size_t size = strlen(cm_NetbiosName) + 2;
10207             if ( !pHostNames ) {
10208                 pHostNames = malloc(size);
10209                 pName = pHostNames;
10210             }
10211             StringCbCopyA(pName, size, cm_NetbiosName);
10212             pName += size - 1;
10213             *pName = '\0';  /* add a second nul terminator */
10214
10215             dwType = REG_MULTI_SZ;
10216             dwSize = (DWORD)(pName - pHostNames + 1);
10217             RegSetValueEx( hkLanMan, "ReconnectableServers", 0, dwType, pHostNames, dwSize);
10218         }
10219
10220         if (pHostNames) {
10221             free(pHostNames);
10222             pHostNames = NULL;
10223         }
10224
10225         if ((RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0,
10226                              &dwType, NULL, &dwAllocSize) == ERROR_SUCCESS) &&
10227             (dwType == REG_MULTI_SZ))
10228         {
10229             dwAllocSize += 1 /* in case the source string is not nul terminated */
10230                 + (DWORD)strlen(cm_NetbiosName) + 2;
10231             pHostNames = malloc(dwAllocSize);
10232             dwSize = dwAllocSize;
10233             if (RegQueryValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, &dwType,
10234                                  pHostNames, &dwSize) == ERROR_SUCCESS)
10235             {
10236                 for (pName = pHostNames;
10237                      (pName - pHostNames < (int) dwSize) && *pName ;
10238                      pName += strlen(pName) + 1)
10239                 {
10240                     if ( !stricmp(pName, cm_NetbiosName) ) {
10241                         bNameFound = TRUE;
10242                         break;
10243                     }
10244                 }
10245             }
10246         }
10247
10248         if ( !bNameFound ) {
10249             size_t size = strlen(cm_NetbiosName) + 2;
10250             if ( !pHostNames ) {
10251                 pHostNames = malloc(size);
10252                 pName = pHostNames;
10253             }
10254             StringCbCopyA(pName, size, cm_NetbiosName);
10255             pName += size - 1;
10256             *pName = '\0';  /* add a second nul terminator */
10257
10258             dwType = REG_MULTI_SZ;
10259             dwSize = (DWORD)(pName - pHostNames + 1);
10260             RegSetValueEx( hkLanMan, "ServersWithExtendedSessTimeout", 0, dwType, pHostNames, dwSize);
10261         }
10262
10263         if (pHostNames) {
10264             free(pHostNames);
10265             pHostNames = NULL;
10266         }
10267
10268         if ((RegQueryValueEx( hkLanMan, "ExtendedSessTimeout", 0,
10269                               &dwType, (LPBYTE)&dwValue, &dwAllocSize) != ERROR_SUCCESS) ||
10270              (dwType != REG_DWORD))
10271         {
10272             dwType = REG_DWORD;
10273             dwSize = sizeof(dwValue);
10274             dwValue = 300;      /* 5 minutes */
10275             RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
10276         }
10277         RegCloseKey(hkLanMan);
10278     }
10279 }
10280
10281 static void
10282 smb_LanAdapterChangeThread(void *param)
10283 {
10284     /*
10285      * Give the IPAddrDaemon thread a chance
10286      * to block before we trigger.
10287      */
10288     Sleep(30000);
10289     smb_LanAdapterChange(0);
10290 }
10291
10292 void smb_SetLanAdapterChangeDetected(void)
10293 {
10294     int lpid;
10295     thread_t phandle;
10296
10297     lock_ObtainMutex(&smb_StartedLock);
10298
10299     if (!powerStateSuspended) {
10300         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
10301                               NULL, 0, &lpid, "smb_LanAdapterChange");
10302         if (phandle == NULL) {
10303             DWORD gle;
10304             char msg[128];
10305
10306             gle = GetLastError();
10307             StringCchPrintf( msg, sizeof(msg)/sizeof(msg[0]),
10308                              "smb_LanAdapterChangeThread thread creation failure - gle 0x%x",
10309                              gle);
10310             osi_assertx(TRUE, msg);
10311         }
10312         thrd_CloseHandle(phandle);
10313     }
10314
10315     smb_LanAdapterChangeDetected = 1;
10316     lock_ReleaseMutex(&smb_StartedLock);
10317 }
10318
10319 void smb_LanAdapterChange(int locked) {
10320     lana_number_t lanaNum;
10321     BOOL          bGateway;
10322     char          NetbiosName[MAX_NB_NAME_LENGTH] = "";
10323     int           change = 0;
10324     LANA_ENUM     temp_list;
10325     long          code;
10326     int           i;
10327
10328
10329     afsi_log("smb_LanAdapterChange");
10330
10331     if (!locked)
10332         lock_ObtainMutex(&smb_StartedLock);
10333
10334     smb_LanAdapterChangeDetected = 0;
10335
10336     if (!powerStateSuspended &&
10337         SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
10338                                           LANA_NETBIOS_NAME_FULL | LANA_NETBIOS_NO_RESET)) &&
10339         lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
10340         if ( isGateway != bGateway ) {
10341             afsi_log("Lan Adapter Change detected (%d != %d): gateway %d != %d",
10342                       smb_LANadapter, lanaNum, isGateway, bGateway);
10343             change = 1;
10344         } else if (strcmp(cm_NetbiosName, NetbiosName) ) {
10345             afsi_log("Lan Adapter Change detected (%d != %d): name %s != %s",
10346                       smb_LANadapter, lanaNum, cm_NetbiosName, NetbiosName);
10347             change = 1;
10348         } else {
10349             NCB *ncbp = smb_GetNCB();
10350             ncbp->ncb_command = NCBENUM;
10351             ncbp->ncb_buffer = (PUCHAR)&temp_list;
10352             ncbp->ncb_length = sizeof(temp_list);
10353             code = Netbios(ncbp);
10354             if (code == 0) {
10355                 if (temp_list.length != lana_list.length) {
10356                     afsi_log("Lan Adapter Change detected (%d != %d): lan list length changed %d != %d",
10357                               smb_LANadapter, lanaNum, temp_list.length, lana_list.length);
10358                     change = 1;
10359                 } else {
10360                     for (i=0; i<lana_list.length; i++) {
10361                         if ( temp_list.lana[i] != lana_list.lana[i] ) {
10362                             afsi_log("Lan Adapter Change detected (%d != %d): lana[%d] %d != %d",
10363                                       smb_LANadapter, lanaNum, i, temp_list.lana[i], lana_list.lana[i]);
10364                             change = 1;
10365                             break;
10366                         }
10367                     }
10368                 }
10369             }
10370             smb_FreeNCB(ncbp);
10371         }
10372     }
10373
10374     if (change) {
10375         smb_StopListeners(1);
10376         smb_RestartListeners(1);
10377     }
10378     if (!locked)
10379         lock_ReleaseMutex(&smb_StartedLock);
10380 }
10381
10382 /* initialize Netbios */
10383 int smb_NetbiosInit(int locked)
10384 {
10385     NCB *ncbp;
10386     int i, lana, code, l;
10387     char s[100];
10388     int delname_tried=0;
10389     int len;
10390     int lana_found = 0;
10391     lana_number_t lanaNum;
10392
10393     if (!smb_Enabled)
10394         return 0;
10395
10396     if (!locked)
10397         lock_ObtainMutex(&smb_StartedLock);
10398
10399     if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
10400          smb_ListenerState != SMB_LISTENER_STOPPED) {
10401
10402         if (!locked)
10403             lock_ReleaseMutex(&smb_StartedLock);
10404         return 0;
10405     }
10406     /* setup the NCB system */
10407     ncbp = smb_GetNCB();
10408
10409     /*
10410      * Call lanahelper to get Netbios name, lan adapter number and gateway flag
10411      * This will reset all of the network adapter's netbios state.
10412      */
10413     if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
10414         smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
10415
10416         if (smb_LANadapter != LANA_INVALID)
10417             afsi_log("LAN adapter number %d", smb_LANadapter);
10418         else
10419             afsi_log("LAN adapter number not determined");
10420
10421         if (isGateway)
10422             afsi_log("Set for gateway service");
10423
10424         afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
10425     } else {
10426         /* something went horribly wrong.  We can't proceed without a netbios name */
10427         char buf[128];
10428         StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
10429         osi_panic(buf, __FILE__, __LINE__);
10430     }
10431
10432     /* remember the name */
10433     len = (int)strlen(cm_NetbiosName);
10434     if (smb_localNamep)
10435         free(smb_localNamep);
10436     smb_localNamep = malloc(len+1);
10437     strcpy(smb_localNamep, cm_NetbiosName);
10438     afsi_log("smb_localNamep is >%s<", smb_localNamep);
10439
10440     /* Also copy the value to the client character encoded string */
10441     cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
10442
10443     if (smb_LANadapter == LANA_INVALID) {
10444         ncbp->ncb_command = NCBENUM;
10445         ncbp->ncb_buffer = (PUCHAR)&lana_list;
10446         ncbp->ncb_length = sizeof(lana_list);
10447         code = Netbios(ncbp);
10448         if (code != 0) {
10449             afsi_log("Netbios NCBENUM error code %d", code);
10450             osi_panic(s, __FILE__, __LINE__);
10451         }
10452     }
10453     else {
10454         lana_list.length = 1;
10455         lana_list.lana[0] = smb_LANadapter;
10456     }
10457
10458     for (i = 0; i < lana_list.length; i++) {
10459         /* reset the adaptor: in Win32, this is required for every process, and
10460          * acts as an init call, not as a real hardware reset.
10461          */
10462         ncbp->ncb_command = NCBRESET;
10463         ncbp->ncb_callname[0] = 100;
10464         ncbp->ncb_callname[2] = 100;
10465         ncbp->ncb_lana_num = lana_list.lana[i];
10466         code = Netbios(ncbp);
10467         if (code == 0)
10468             code = ncbp->ncb_retcode;
10469         if (code != 0) {
10470             afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
10471             lana_list.lana[i] = LANA_INVALID;  /* invalid lana */
10472         } else {
10473             afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
10474         }
10475     }
10476
10477     /* and declare our name so we can receive connections */
10478     memset(ncbp, 0, sizeof(*ncbp));
10479     len=lstrlen(smb_localNamep);
10480     memset(smb_sharename,' ',NCBNAMSZ);
10481     memcpy(smb_sharename,smb_localNamep,len);
10482     afsi_log("lana_list.length %d", lana_list.length);
10483
10484     /* Keep the name so we can unregister it later */
10485     for (l = 0; l < lana_list.length; l++) {
10486         lana = lana_list.lana[l];
10487
10488         ncbp->ncb_command = NCBADDNAME;
10489         ncbp->ncb_lana_num = lana;
10490         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10491         code = Netbios(ncbp);
10492
10493         afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
10494                  lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10495         {
10496             char name[NCBNAMSZ+1];
10497             name[NCBNAMSZ]=0;
10498             memcpy(name,ncbp->ncb_name,NCBNAMSZ);
10499             afsi_log("Netbios NCBADDNAME added new name >%s<",name);
10500         }
10501
10502         if (code == 0)
10503             code = ncbp->ncb_retcode;
10504
10505         if (code == 0) {
10506             afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
10507         }
10508         else {
10509             afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10510             if (code == NRC_BRIDGE) {    /* invalid LANA num */
10511                 lana_list.lana[l] = LANA_INVALID;
10512                 continue;
10513             }
10514             else if (code == NRC_DUPNAME) {
10515                 afsi_log("Name already exists; try to delete it");
10516                 memset(ncbp, 0, sizeof(*ncbp));
10517                 ncbp->ncb_command = NCBDELNAME;
10518                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10519                 ncbp->ncb_lana_num = lana;
10520                 code = Netbios(ncbp);
10521                 if (code == 0)
10522                     code = ncbp->ncb_retcode;
10523                 else {
10524                     afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
10525                 }
10526                 if (code != 0 || delname_tried) {
10527                     lana_list.lana[l] = LANA_INVALID;
10528                 }
10529                 else if (code == 0) {
10530                     if (!delname_tried) {
10531                         lana--;
10532                         delname_tried = 1;
10533                         continue;
10534                     }
10535                 }
10536             }
10537             else {
10538                 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
10539                 lana_list.lana[l] = LANA_INVALID;  /* invalid lana */
10540             }
10541         }
10542         if (code == 0) {
10543             smb_LANadapter = lana;
10544             lana_found = 1;   /* at least one worked */
10545         }
10546     }
10547
10548     osi_assertx(lana_list.length >= 0, "empty lana list");
10549     if (!lana_found) {
10550         afsi_log("No valid LANA numbers found!");
10551         lana_list.length = 0;
10552         smb_LANadapter = LANA_INVALID;
10553         smb_ListenerState = SMB_LISTENER_STOPPED;
10554         cm_VolStatus_Network_Stopped(cm_NetbiosName
10555 #ifdef _WIN64
10556                                       ,cm_NetbiosName
10557 #endif
10558                                       );
10559     }
10560
10561     /* we're done with the NCB now */
10562     smb_FreeNCB(ncbp);
10563
10564     afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
10565     if (lana_list.length > 0)
10566         osi_assert(smb_LANadapter != LANA_INVALID);
10567
10568     if (!locked)
10569         lock_ReleaseMutex(&smb_StartedLock);
10570
10571     return (lana_list.length > 0 ? 1 : 0);
10572 }
10573
10574 void smb_StartListeners(int locked)
10575 {
10576     int i;
10577     int lpid;
10578     thread_t phandle;
10579
10580     if (!smb_Enabled)
10581         return;
10582
10583     if (!locked)
10584         lock_ObtainMutex(&smb_StartedLock);
10585
10586     if (smb_ListenerState == SMB_LISTENER_STARTED) {
10587         if (!locked)
10588             lock_ReleaseMutex(&smb_StartedLock);
10589         return;
10590     }
10591
10592     afsi_log("smb_StartListeners");
10593     /* Ensure the AFS Netbios Name is registered to allow loopback access */
10594     configureBackConnectionHostNames();
10595
10596     /* Configure Extended SMB Session Timeouts */
10597     if (msftSMBRedirectorSupportsExtendedTimeouts()) {
10598         afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
10599         configureExtendedSMBSessionTimeouts();
10600     }
10601
10602     smb_ListenerState = SMB_LISTENER_STARTED;
10603     cm_VolStatus_Network_Started(cm_NetbiosName
10604 #ifdef _WIN64
10605                                   , cm_NetbiosName
10606 #endif
10607                                   );
10608
10609     for (i = 0; i < lana_list.length; i++) {
10610         if (lana_list.lana[i] == LANA_INVALID)
10611             continue;
10612         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
10613                                (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
10614         osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
10615         thrd_CloseHandle(phandle);
10616     }
10617     if (!locked)
10618         lock_ReleaseMutex(&smb_StartedLock);
10619 }
10620
10621 void smb_RestartListeners(int locked)
10622 {
10623     if (!smb_Enabled)
10624         return;
10625
10626     if (!locked)
10627         lock_ObtainMutex(&smb_StartedLock);
10628
10629     if (powerStateSuspended)
10630         afsi_log("smb_RestartListeners called while suspended");
10631
10632     if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
10633         if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10634             if (smb_NetbiosInit(1))
10635                 smb_StartListeners(1);
10636         } else if (smb_LanAdapterChangeDetected) {
10637             smb_LanAdapterChange(1);
10638         }
10639     }
10640     if (!locked)
10641         lock_ReleaseMutex(&smb_StartedLock);
10642 }
10643
10644 void smb_StopListener(NCB *ncbp, int lana, int wait)
10645 {
10646     long code;
10647
10648     memset(ncbp, 0, sizeof(*ncbp));
10649     ncbp->ncb_command = NCBDELNAME;
10650     ncbp->ncb_lana_num = lana;
10651     memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
10652     code = Netbios(ncbp);
10653
10654     afsi_log("StopListener: Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
10655               lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
10656
10657     /* and then reset the LANA; this will cause the listener threads to exit */
10658     ncbp->ncb_command = NCBRESET;
10659     ncbp->ncb_callname[0] = 100;
10660     ncbp->ncb_callname[2] = 100;
10661     ncbp->ncb_lana_num = lana;
10662     code = Netbios(ncbp);
10663     if (code == 0)
10664         code = ncbp->ncb_retcode;
10665     if (code != 0) {
10666         afsi_log("StopListener: Netbios NCBRESET lana %d error code %d", lana, code);
10667     } else {
10668         afsi_log("StopListener: Netbios NCBRESET lana %d succeeded", lana);
10669     }
10670
10671     if (wait)
10672         thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
10673 }
10674
10675 void smb_StopListeners(int locked)
10676 {
10677     NCB *ncbp;
10678     int lana, l;
10679
10680     if (!smb_Enabled)
10681         return;
10682
10683     if (!locked)
10684         lock_ObtainMutex(&smb_StartedLock);
10685
10686     if (smb_ListenerState == SMB_LISTENER_STOPPED) {
10687         if (!locked)
10688             lock_ReleaseMutex(&smb_StartedLock);
10689         return;
10690     }
10691
10692     afsi_log("smb_StopListeners");
10693     smb_ListenerState = SMB_LISTENER_STOPPED;
10694     cm_VolStatus_Network_Stopped(cm_NetbiosName
10695 #ifdef _WIN64
10696                                   , cm_NetbiosName
10697 #endif
10698                                   );
10699
10700     ncbp = smb_GetNCB();
10701
10702     /* Unregister the SMB name */
10703     for (l = 0; l < lana_list.length; l++) {
10704         lana = lana_list.lana[l];
10705
10706         if (lana != LANA_INVALID) {
10707             smb_StopListener(ncbp, lana, TRUE);
10708
10709             /* mark the adapter invalid */
10710             lana_list.lana[l] = LANA_INVALID;  /* invalid lana */
10711         }
10712     }
10713
10714     /* force a re-evaluation of the network adapters */
10715     lana_list.length = 0;
10716     smb_LANadapter = LANA_INVALID;
10717     smb_FreeNCB(ncbp);
10718     if (!locked)
10719         lock_ReleaseMutex(&smb_StartedLock);
10720 }
10721
10722 void smb_Init(osi_log_t *logp, int useV3,
10723               int nThreads
10724               , void *aMBfunc
10725   )
10726
10727 {
10728     thread_t phandle;
10729     int lpid;
10730     UINT_PTR i;
10731     struct tm myTime;
10732     EVENT_HANDLE retHandle;
10733     char eventName[MAX_PATH];
10734     int startListeners = 0;
10735
10736     if (!smb_Enabled)
10737         return;
10738
10739     smb_MBfunc = aMBfunc;
10740
10741     smb_useV3 = useV3;
10742
10743     /* Initialize smb_localZero */
10744     myTime.tm_isdst = -1;               /* compute whether on DST or not */
10745     myTime.tm_year = 70;
10746     myTime.tm_mon = 0;
10747     myTime.tm_mday = 1;
10748     myTime.tm_hour = 0;
10749     myTime.tm_min = 0;
10750     myTime.tm_sec = 0;
10751     smb_localZero = mktime(&myTime);
10752
10753 #ifdef AFS_FREELANCE_CLIENT
10754     /* Make sure the root.afs volume has the correct time */
10755     cm_noteLocalMountPointChange(FALSE);
10756 #endif
10757
10758     /* initialize the remote debugging log */
10759     smb_logp = logp;
10760
10761     /* and the global lock */
10762     lock_InitializeRWLock(&smb_globalLock, "smb global lock", LOCK_HIERARCHY_SMB_GLOBAL);
10763     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock", LOCK_HIERARCHY_SMB_RCT_GLOBAL);
10764
10765     /* Raw I/O data structures */
10766     lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock", LOCK_HIERARCHY_SMB_RAWBUF);
10767
10768     lock_InitializeMutex(&smb_ListenerLock, "smb listener lock", LOCK_HIERARCHY_SMB_LISTENER);
10769     lock_InitializeMutex(&smb_StartedLock, "smb started lock", LOCK_HIERARCHY_SMB_STARTED);
10770
10771     /* 4 Raw I/O buffers */
10772     smb_RawBufs = calloc(65536,1);
10773     *((char **)smb_RawBufs) = NULL;
10774     for (i=0; i<3; i++) {
10775         char *rawBuf = calloc(65536,1);
10776         *((char **)rawBuf) = smb_RawBufs;
10777         smb_RawBufs = rawBuf;
10778     }
10779
10780     /* global free lists */
10781     smb_ncbFreeListp = NULL;
10782     smb_packetFreeListp = NULL;
10783
10784     lock_ObtainMutex(&smb_StartedLock);
10785     startListeners = smb_NetbiosInit(1);
10786
10787     /* Initialize listener and server structures */
10788     numVCs = 0;
10789     memset(dead_sessions, 0, sizeof(dead_sessions));
10790     sprintf(eventName, "SessionEvents[0]");
10791     SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10792     if ( GetLastError() == ERROR_ALREADY_EXISTS )
10793         afsi_log("Event Object Already Exists: %s", eventName);
10794     numSessions = 1;
10795     smb_NumServerThreads = nThreads;
10796     sprintf(eventName, "NCBavails[0]");
10797     NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10798     if ( GetLastError() == ERROR_ALREADY_EXISTS )
10799         afsi_log("Event Object Already Exists: %s", eventName);
10800     sprintf(eventName, "NCBevents[0]");
10801     NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10802     if ( GetLastError() == ERROR_ALREADY_EXISTS )
10803         afsi_log("Event Object Already Exists: %s", eventName);
10804     NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
10805     sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
10806     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10807     if ( GetLastError() == ERROR_ALREADY_EXISTS )
10808         afsi_log("Event Object Already Exists: %s", eventName);
10809     for (i = 0; i < smb_NumServerThreads; i++) {
10810         NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
10811         NCBreturns[i][0] = retHandle;
10812     }
10813
10814     smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
10815     for (i = 0; i < smb_NumServerThreads; i++) {
10816         sprintf(eventName, "smb_ServerShutdown[%d]", i);
10817         smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
10818         if ( GetLastError() == ERROR_ALREADY_EXISTS )
10819             afsi_log("Event Object Already Exists: %s", eventName);
10820         InitNCBslot((int)(i+1));
10821     }
10822     numNCBs = smb_NumServerThreads + 1;
10823
10824     /* Initialize dispatch table */
10825     memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
10826     /* Prepare the table for unknown operations */
10827     for(i=0; i<= SMB_NOPCODES; i++) {
10828         smb_dispatchTable[i].procp = smb_SendCoreBadOp;
10829     }
10830     /* Fill in the ones we do know */
10831     smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
10832     smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
10833     smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
10834     smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
10835     smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
10836     smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
10837     smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
10838     smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
10839     smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
10840     smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
10841     smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
10842     smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
10843     smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
10844     smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
10845     smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
10846     smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
10847     smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
10848     smb_dispatchTable[0x11].procp = smb_SendCoreBadOp;  /* process exit */
10849     smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
10850     smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
10851     /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
10852     smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10853     smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
10854     smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
10855     smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
10856     smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
10857     smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
10858     smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
10859     smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10860     smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
10861     smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10862     smb_dispatchTable[0x29].procp = smb_SendCoreBadOp;  /* copy file */
10863     smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
10864     /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
10865     smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10866     smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
10867     smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
10868     smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
10869     smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
10870     smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
10871     smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
10872     smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A;        /* both are same */
10873     smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10874     smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
10875     smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10876     smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
10877     smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
10878     smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
10879     smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
10880     smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
10881     smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
10882     smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
10883     smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
10884     smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
10885     smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
10886     smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
10887     smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
10888     smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
10889     smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
10890     smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
10891     smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
10892     smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
10893     smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
10894     smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
10895     smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
10896     smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
10897     smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
10898     smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;  /* Open Print File */
10899     smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;  /* Write Print File */
10900     smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;  /* Close Print File */
10901     smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;  /* Get Print Queue */
10902     smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp;  /* Read Bulk */
10903     smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp;  /* Write Bulk */
10904     smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp;  /* Write Bulk Data */
10905
10906     /* setup tran 2 dispatch table */
10907     smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
10908     smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir;        /* FindFirst */
10909     smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir;        /* FindNext */
10910     smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
10911     smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
10912     smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
10913     smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
10914     smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
10915     smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
10916     smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
10917     smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
10918     smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
10919     smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
10920     smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
10921     smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
10922     smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
10923     smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
10924     smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
10925
10926     /* setup the rap dispatch table */
10927     memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
10928     smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
10929     smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
10930     smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
10931     smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
10932
10933     smb3_Init();
10934
10935     /* if we are doing SMB authentication we have register outselves as a logon process */
10936     if (smb_authType != SMB_AUTH_NONE) {
10937         NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
10938         LSA_STRING afsProcessName;
10939         LSA_OPERATIONAL_MODE dummy; /*junk*/
10940
10941         afsProcessName.Buffer = "OpenAFSClientDaemon";
10942         afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
10943         afsProcessName.MaximumLength = afsProcessName.Length + 1;
10944
10945         nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
10946
10947         if (nts == STATUS_SUCCESS) {
10948             LSA_STRING packageName;
10949             /* we are registered. Find out the security package id */
10950             packageName.Buffer = MSV1_0_PACKAGE_NAME;
10951             packageName.Length = (USHORT)strlen(packageName.Buffer);
10952             packageName.MaximumLength = packageName.Length + 1;
10953             nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
10954             if (nts == STATUS_SUCCESS) {
10955                 /* BEGIN
10956                  * This code forces Windows to authenticate against the Logon Cache
10957                  * first instead of attempting to authenticate against the Domain
10958                  * Controller.  When the Windows logon cache is enabled this improves
10959                  * performance by removing the network access and works around a bug
10960                  * seen at sites which are using a MIT Kerberos principal to login
10961                  * to machines joined to a non-root domain in a multi-domain forest.
10962                  * MsV1_0SetProcessOption was added in Windows XP.
10963                  */
10964                 PVOID pResponse = NULL;
10965                 ULONG cbResponse = 0;
10966                 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
10967
10968                 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
10969                 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
10970                 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
10971                 OptionsRequest.DisableOptions = FALSE;
10972
10973                 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
10974                                                     smb_lsaSecPackage,
10975                                                     &OptionsRequest,
10976                                                     sizeof(OptionsRequest),
10977                                                     &pResponse,
10978                                                     &cbResponse,
10979                                                     &ntsEx
10980                                                     );
10981
10982                 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
10983                     osi_Log2(smb_logp, "MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
10984                              nts, ntsEx);
10985
10986                     afsi_log("MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x", nts, ntsEx);
10987                 } else {
10988                     osi_Log0(smb_logp, "MsV1_0SetProcessOption success");
10989                     afsi_log("MsV1_0SetProcessOption success");
10990                 }
10991                 /* END - code from Larry */
10992
10993                 smb_lsaLogonOrigin.Buffer = "OpenAFS";
10994                 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
10995                 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
10996             } else {
10997                 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
10998
10999                 /* something went wrong. We report the error and revert back to no authentication
11000                 because we can't perform any auth requests without a successful lsa handle
11001                 or sec package id. */
11002                 afsi_log("Reverting to NO SMB AUTH");
11003                 smb_authType = SMB_AUTH_NONE;
11004             }
11005         } else {
11006             afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
11007
11008             /* something went wrong. We report the error and revert back to no authentication
11009             because we can't perform any auth requests without a successful lsa handle
11010             or sec package id. */
11011             afsi_log("Reverting to NO SMB AUTH");
11012             smb_authType = SMB_AUTH_NONE;
11013         }
11014
11015 #ifdef COMMENT
11016         /* Don't fallback to SMB_AUTH_NTLM.  Apparently, allowing SPNEGO to be used each
11017          * time prevents the failure of authentication when logged into Windows with an
11018          * external Kerberos principal mapped to a local account.
11019          */
11020         else if ( smb_authType == SMB_AUTH_EXTENDED) {
11021             /* Test to see if there is anything to negotiate.  If SPNEGO is not going to be used
11022              * then the only option is NTLMSSP anyway; so just fallback.
11023              */
11024             void * secBlob;
11025             int secBlobLength;
11026
11027             smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
11028             if (secBlobLength == 0) {
11029                 smb_authType = SMB_AUTH_NTLM;
11030                 afsi_log("Reverting to SMB AUTH NTLM");
11031             } else
11032                 free(secBlob);
11033         }
11034 #endif
11035     }
11036
11037     {
11038         DWORD bufsize;
11039         /* Now get ourselves a domain name. */
11040         /* For now we are using the local computer name as the domain name.
11041          * It is actually the domain for local logins, and we are acting as
11042          * a local SMB server.
11043          */
11044         bufsize = lengthof(smb_ServerDomainName) - 1;
11045         GetComputerNameW(smb_ServerDomainName, &bufsize);
11046         smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
11047         afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
11048     }
11049
11050     /* Start listeners, waiters, servers, and daemons */
11051     if (startListeners)
11052         smb_StartListeners(1);
11053
11054     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
11055                           NULL, 0, &lpid, "smb_ClientWaiter");
11056     osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
11057     thrd_CloseHandle(phandle);
11058
11059     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
11060                           NULL, 0, &lpid, "smb_ServerWaiter");
11061     osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
11062     thrd_CloseHandle(phandle);
11063
11064     for (i=0; i<smb_NumServerThreads; i++) {
11065         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
11066                               (void *) i, 0, &lpid, "smb_Server");
11067         osi_assertx(phandle != NULL, "smb_Server thread creation failure");
11068         thrd_CloseHandle(phandle);
11069     }
11070
11071     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
11072                           NULL, 0, &lpid, "smb_Daemon");
11073     osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
11074     thrd_CloseHandle(phandle);
11075
11076     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
11077                           NULL, 0, &lpid, "smb_WaitingLocksDaemon");
11078     osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
11079     thrd_CloseHandle(phandle);
11080
11081     if (smb_monitorReqs) {
11082         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerMonitor,
11083                               NULL, 0, &lpid, "smb_ServerMonitor");
11084         osi_assertx(phandle != NULL, "smb_ServerMonitor thread creation failure");
11085         thrd_CloseHandle(phandle);
11086     }
11087
11088     lock_ReleaseMutex(&smb_StartedLock);
11089     return;
11090 }
11091
11092 void smb_Shutdown(void)
11093 {
11094     NCB *ncbp;
11095     long code = 0;
11096     afs_uint32 i;
11097     smb_vc_t *vcp;
11098
11099     if (!smb_Enabled)
11100         return;
11101
11102     /*fprintf(stderr, "Entering smb_Shutdown\n");*/
11103
11104     /* setup the NCB system */
11105     ncbp = smb_GetNCB();
11106
11107     /* Block new sessions by setting shutdown flag */
11108     smbShutdownFlag = 1;
11109
11110     /* Hang up all sessions */
11111     memset(ncbp, 0, sizeof(NCB));
11112     for (i = 1; i < numSessions; i++)
11113     {
11114         if (dead_sessions[i])
11115             continue;
11116
11117         /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11118         ncbp->ncb_command = NCBHANGUP;
11119         ncbp->ncb_lana_num = lanas[i];  /*smb_LANadapter;*/
11120         ncbp->ncb_lsn = (UCHAR)LSNs[i];
11121         code = Netbios(ncbp);
11122         /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
11123         if (code == 0) code = ncbp->ncb_retcode;
11124         if (code != 0) {
11125             osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
11126             fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
11127         }
11128     }
11129
11130     /* Trigger the shutdown of all SMB threads */
11131     for (i = 0; i < smb_NumServerThreads; i++)
11132         thrd_SetEvent(NCBreturns[i][0]);
11133
11134     thrd_SetEvent(NCBevents[0]);
11135     thrd_SetEvent(SessionEvents[0]);
11136     thrd_SetEvent(NCBavails[0]);
11137
11138     for (i = 0;i < smb_NumServerThreads; i++) {
11139         DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
11140         if (code == WAIT_OBJECT_0) {
11141             continue;
11142         } else {
11143             afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
11144             thrd_SetEvent(NCBreturns[i--][0]);
11145         }
11146     }
11147
11148     /* Delete Netbios name */
11149     memset(ncbp, 0, sizeof(NCB));
11150     for (i = 0; i < lana_list.length; i++) {
11151         if (lana_list.lana[i] == LANA_INVALID) continue;
11152         ncbp->ncb_command = NCBDELNAME;
11153         ncbp->ncb_lana_num = lana_list.lana[i];
11154         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
11155         code = Netbios(ncbp);
11156         if (code == 0)
11157             code = ncbp->ncb_retcode;
11158         if (code != 0) {
11159             fprintf(stderr, "Shutdown: Netbios NCBDELNAME lana %d error code %d",
11160                      ncbp->ncb_lana_num, code);
11161         }
11162         fflush(stderr);
11163     }
11164
11165     /* Release the reference counts held by the VCs */
11166     lock_ObtainWrite(&smb_rctLock);
11167     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11168     {
11169         smb_fid_t *fidp;
11170         smb_tid_t *tidp;
11171
11172         if (vcp->magic != SMB_VC_MAGIC)
11173             osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
11174                        __FILE__, __LINE__);
11175
11176         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11177         {
11178             if (fidp->scp != NULL) {
11179                 cm_scache_t * scp;
11180
11181                 lock_ReleaseWrite(&smb_rctLock);
11182                 lock_ObtainMutex(&fidp->mx);
11183                 if (fidp->scp != NULL) {
11184                     scp = fidp->scp;
11185                     fidp->scp = NULL;
11186                     lock_ObtainWrite(&scp->rw);
11187                     scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
11188                     lock_ReleaseWrite(&scp->rw);
11189                     osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
11190                     cm_ReleaseSCache(scp);
11191                 }
11192                 lock_ReleaseMutex(&fidp->mx);
11193                 lock_ObtainWrite(&smb_rctLock);
11194             }
11195         }
11196
11197         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11198             if (tidp->vcp)
11199                 smb_ReleaseVCNoLock(tidp->vcp);
11200             if (tidp->userp) {
11201                 cm_user_t *userp = tidp->userp;
11202                 tidp->userp = NULL;
11203                 cm_ReleaseUser(userp);
11204             }
11205         }
11206     }
11207     lock_ReleaseWrite(&smb_rctLock);
11208     smb_FreeNCB(ncbp);
11209
11210     if (smb_monitorReqs) {
11211         smb_ShutdownMonitor();
11212     }
11213 }
11214
11215 /* Get the UNC \\<servername>\<sharename> prefix. */
11216 char *smb_GetSharename()
11217 {
11218     char *name;
11219     size_t len;
11220
11221     /* Make sure we have been properly initialized. */
11222     if (smb_localNamep == NULL)
11223         return NULL;
11224
11225     /* Allocate space for \\<servername>\<sharename>, plus the
11226      * terminator.
11227      */
11228     len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
11229     name = malloc(len);
11230     snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
11231     return name;
11232 }
11233
11234
11235 #ifdef LOG_PACKET
11236 void smb_LogPacket(smb_packet_t *packet)
11237 {
11238     BYTE *vp, *cp;
11239     smb_t * smbp;
11240     unsigned length, paramlen, datalen, i, j;
11241     char buf[81];
11242     char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
11243
11244     if (!packet) return;
11245
11246     osi_Log0(smb_logp, "*** SMB packet dump ***");
11247
11248     smbp = (smb_t *) packet->data;
11249     vp = (BYTE *) packet->data;
11250
11251     paramlen = smbp->wct * 2;
11252     datalen = *((WORD *) (smbp->vdata + paramlen));
11253     length = sizeof(*smbp) + paramlen + 1 + datalen;
11254
11255     for (i=0;i < length; i+=16)
11256     {
11257         memset( buf, ' ', 80 );
11258         buf[80] = 0;
11259
11260         itoa( i, buf, 16 );
11261
11262         buf[strlen(buf)] = ' ';
11263
11264         cp = (BYTE*) buf + 7;
11265
11266         for (j=0;j < 16 && (i+j)<length; j++)
11267         {
11268             *(cp++) = hex[vp[i+j] >> 4];
11269             *(cp++) = hex[vp[i+j] & 0xf];
11270             *(cp++) = ' ';
11271
11272             if (j==7)
11273             {
11274                 *(cp++) = '-';
11275                 *(cp++) = ' ';
11276             }
11277         }
11278
11279         for (j=0;j < 16 && (i+j)<length;j++)
11280         {
11281             *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
11282             if (j==7)
11283             {
11284                 *(cp++) = ' ';
11285                 *(cp++) = '-';
11286                 *(cp++) = ' ';
11287             }
11288         }
11289
11290         *cp = 0;
11291
11292         osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
11293     }
11294
11295     osi_Log0(smb_logp, "*** End SMB packet dump ***");
11296 }
11297 #endif /* LOG_PACKET */
11298
11299
11300 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
11301 {
11302     int zilch;
11303     char output[4196];
11304
11305     smb_vc_t *vcp;
11306     smb_username_t *unp;
11307     smb_waitingLockRequest_t *wlrp;
11308
11309     if (lock)
11310         lock_ObtainRead(&smb_rctLock);
11311
11312     sprintf(output, "begin dumping smb_username_t\r\n");
11313     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11314     for (unp = usernamesp; unp; unp=unp->nextp)
11315     {
11316         cm_ucell_t *ucellp;
11317
11318         sprintf(output, "%s -- smb_unp=0x%p, refCount=%d, cm_userp=0x%p, flags=0x%x, logoff=%u, name=%S, machine=%S\r\n",
11319                 cookie, unp, unp->refCount, unp->userp, unp->flags, unp->last_logoff_t,
11320                 unp->name ? unp->name : _C("NULL"),
11321                 unp->machine ? unp->machine : _C("NULL"));
11322         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11323
11324         sprintf(output, "  begin dumping cm_ucell_t\r\n");
11325         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11326
11327         for ( ucellp = unp->userp->cellInfop; ucellp; ucellp = ucellp->nextp ) {
11328             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",
11329                      cookie, ucellp, ucellp->cellp, ucellp->flags, ucellp->ticketLen, ucellp->kvno,
11330                      ucellp->expirationTime, ucellp->gen,
11331                      ucellp->userName,
11332                      ucellp->cellp->name);
11333             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11334         }
11335
11336         sprintf(output, "  done dumping cm_ucell_t\r\n");
11337         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11338
11339     }
11340     sprintf(output, "done dumping smb_username_t\r\n");
11341     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11342
11343
11344     if (!smb_Enabled)
11345         goto done;
11346
11347     sprintf(output, "begin dumping smb_waitingLockRequest_t\r\n");
11348     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11349
11350     for ( wlrp = smb_allWaitingLocks; wlrp; wlrp = (smb_waitingLockRequest_t *) osi_QNext(&wlrp->q)) {
11351         smb_waitingLock_t *lockp;
11352
11353         sprintf(output, "%s wlrp=0x%p vcp=0x%p, scp=0x%p, type=0x%x, start_t=0x%I64u msTimeout=0x%x\r\n",
11354                  cookie, wlrp, wlrp->vcp, wlrp->scp, wlrp->lockType, wlrp->start_t, wlrp->msTimeout);
11355         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11356
11357         sprintf(output, "  begin dumping smb_waitingLock_t\r\n");
11358         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11359         for (lockp = wlrp->locks; lockp; lockp = (smb_waitingLock_t *) osi_QNext(&lockp->q)) {
11360             sprintf(output, "  %s -- waitlockp=0x%p lockp=0x%p key=0x%I64x offset=0x%I64x length=0x%I64x state=0x%x\r\n",
11361                     cookie, lockp, lockp->lockp, lockp->key, lockp->LOffset.QuadPart, lockp->LLength.QuadPart, lockp->state);
11362             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11363         }
11364         sprintf(output, "  done dumping smb_waitingLock_t\r\n");
11365         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11366     }
11367
11368     sprintf(output, "done dumping smb_waitingLockRequest_t\r\n");
11369     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11370
11371     sprintf(output, "begin dumping smb_vc_t\r\n");
11372     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11373
11374     for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
11375     {
11376         smb_fid_t *fidp;
11377         smb_tid_t *tidp;
11378         smb_user_t *userp;
11379
11380         sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11381                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11382         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11383
11384         sprintf(output, "  begin dumping smb_user_t\r\n");
11385         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11386         for (userp = vcp->usersp; userp; userp = userp->nextp) {
11387             sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11388                     cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11389             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11390         }
11391         sprintf(output, "  done dumping smb_user_t\r\n");
11392         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11393
11394         sprintf(output, "  begin dumping smb_tid_t\r\n");
11395         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11396         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11397             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",
11398                     cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11399                     tidp->pathname ? tidp->pathname : _C("NULL"));
11400             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11401         }
11402         sprintf(output, "  done dumping smb_tid_t\r\n");
11403         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11404
11405         sprintf(output, "  begin dumping smb_fid_t\r\n");
11406         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11407
11408         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11409         {
11410             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",
11411                     cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11412                     fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11413                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11414             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11415         }
11416
11417         sprintf(output, "  done dumping smb_fid_t\r\n");
11418         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11419     }
11420
11421     sprintf(output, "done dumping smb_vc_t\r\n");
11422     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11423
11424     sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
11425     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11426
11427     for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
11428     {
11429         smb_fid_t *fidp;
11430         smb_tid_t *tidp;
11431         smb_user_t *userp;
11432
11433         sprintf(output, "%s vcp=0x%p, refCount=%d, flags=0x%x, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
11434                 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
11435         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11436
11437         sprintf(output, "  begin dumping smb_user_t\r\n");
11438         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11439         for (userp = vcp->usersp; userp; userp = userp->nextp) {
11440             sprintf(output, "  %s -- smb_userp=0x%p, refCount=%d, uid=%d, vcp=0x%p, unp=0x%p, flags=0x%x, delOk=%d\r\n",
11441                     cookie, userp, userp->refCount, userp->userID, userp->vcp, userp->unp, userp->flags, userp->deleteOk);
11442             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11443         }
11444         sprintf(output, "  done dumping smb_user_t\r\n");
11445         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11446
11447         sprintf(output, "  begin dumping smb_tid_t\r\n");
11448         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11449         for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
11450             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",
11451                     cookie, tidp, tidp->refCount, tidp->tid, tidp->vcp, tidp->userp, tidp->flags, tidp->deleteOk,
11452                     tidp->pathname ? tidp->pathname : _C("NULL"));
11453             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11454         }
11455         sprintf(output, "  done dumping smb_tid_t\r\n");
11456         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11457
11458         sprintf(output, "  begin dumping smb_fid_t\r\n");
11459         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11460
11461         for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
11462         {
11463             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",
11464                     cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->userp, fidp->ioctlp, fidp->flags, fidp->deleteOk,
11465                     fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
11466                     fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
11467             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11468         }
11469
11470         sprintf(output, "  done dumping smb_fid_t\r\n");
11471         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11472     }
11473
11474     sprintf(output, "done dumping DEAD smb_vc_t\r\n");
11475     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
11476
11477   done:
11478     if (lock)
11479         lock_ReleaseRead(&smb_rctLock);
11480     return 0;
11481 }
11482
11483 long smb_IsNetworkStarted(void)
11484 {
11485     long rc;
11486
11487     if (!smb_Enabled)
11488         return 0;
11489
11490     lock_ObtainWrite(&smb_globalLock);
11491     rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
11492     lock_ReleaseWrite(&smb_globalLock);
11493     return rc;
11494 }