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