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