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