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