2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afs/param.h>
15 #pragma warning(disable: 4005)
28 #include <rx/rx_prototypes.h>
29 #include <WINNT\afsreg.h>
32 #include "lanahelper.h"
34 /* These characters are illegal in Windows filenames */
35 static char *illegalChars = "\\/:*?\"<>|";
37 static int smbShutdownFlag = 0;
38 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
40 int smb_LogoffTokenTransfer;
41 time_t smb_LogoffTransferTimeout;
43 int smb_StoreAnsiFilenames = 0;
45 DWORD last_msg_time = 0;
49 unsigned int sessionGen = 0;
51 extern void afsi_log(char *pattern, ...);
52 extern HANDLE afsi_file;
53 extern int powerStateSuspended;
55 osi_hyper_t hzero = {0, 0};
56 osi_hyper_t hones = {0xFFFFFFFF, -1};
59 osi_rwlock_t smb_globalLock;
60 osi_rwlock_t smb_rctLock;
61 osi_mutex_t smb_ListenerLock;
64 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
66 BOOL isGateway = FALSE;
69 long smb_maxObsConcurrentCalls=0;
70 long smb_concurrentCalls=0;
72 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
74 smb_packet_t *smb_packetFreeListp;
75 smb_ncb_t *smb_ncbFreeListp;
77 int smb_NumServerThreads;
79 int numNCBs, numSessions, numVCs;
81 int smb_maxVCPerServer;
82 int smb_maxMpxRequests;
84 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
86 ULONG smb_lsaSecPackage;
87 LSA_STRING smb_lsaLogonOrigin;
89 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
90 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
91 EVENT_HANDLE **NCBreturns;
92 EVENT_HANDLE **NCBShutdown;
93 EVENT_HANDLE *smb_ServerShutdown;
94 DWORD NCBsessions[NCB_MAX];
96 struct smb_packet *bufs[NCB_MAX];
98 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
99 EVENT_HANDLE SessionEvents[SESSION_MAX];
100 unsigned short LSNs[SESSION_MAX];
101 int lanas[SESSION_MAX];
102 BOOL dead_sessions[SESSION_MAX];
106 osi_mutex_t smb_RawBufLock;
109 #define SMB_MASKFLAG_TILDE 1
110 #define SMB_MASKFLAG_CASEFOLD 2
112 #define RAWTIMEOUT INFINITE
115 typedef struct raw_write_cont {
124 /* dir search stuff */
125 long smb_dirSearchCounter = 1;
126 smb_dirSearch_t *smb_firstDirSearchp;
127 smb_dirSearch_t *smb_lastDirSearchp;
129 /* hide dot files? */
130 int smb_hideDotFiles;
132 /* global state about V3 protocols */
133 int smb_useV3; /* try to negotiate V3 */
135 static showErrors = 0;
136 /* MessageBox or something like it */
137 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
140 * Time in Unix format of midnight, 1/1/1970 local time.
141 * When added to dosUTime, gives Unix (AFS) time.
143 time_t smb_localZero = 0;
145 #define USE_NUMERIC_TIME_CONV 1
147 #ifndef USE_NUMERIC_TIME_CONV
148 /* Time difference for converting to kludge-GMT */
149 afs_uint32 smb_NowTZ;
150 #endif /* USE_NUMERIC_TIME_CONV */
152 char *smb_localNamep = NULL;
154 smb_vc_t *smb_allVCsp;
155 smb_vc_t *smb_deadVCsp;
157 smb_username_t *usernamesp = NULL;
159 smb_waitingLockRequest_t *smb_allWaitingLocks;
161 DWORD smb_TlsRequestSlot = -1;
164 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
165 NCB *ncbp, raw_write_cont_t *rwcp);
166 int smb_NetbiosInit(void);
169 void smb_LogPacket(smb_packet_t *packet);
170 #endif /* LOG_PACKET */
172 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
173 int smb_ServerDomainNameLength = 0;
174 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
175 int smb_ServerOSLength = sizeof(smb_ServerOS);
176 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
177 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
179 /* Faux server GUID. This is never checked. */
180 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
182 void smb_ResetServerPriority()
184 void * p = TlsGetValue(smb_TlsRequestSlot);
187 TlsSetValue(smb_TlsRequestSlot, NULL);
188 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
192 void smb_SetRequestStartTime()
194 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
196 tp = malloc(sizeof(time_t));
200 if (!TlsSetValue(smb_TlsRequestSlot, tp))
205 void smb_UpdateServerPriority()
207 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
210 time_t now = osi_Time();
212 /* Give one priority boost for each 15 seconds */
213 SetThreadPriority(GetCurrentThread(), (now - *tp) / 15);
218 const char * ncb_error_string(int code)
222 case 0x01: s = "llegal buffer length"; break;
223 case 0x03: s = "illegal command"; break;
224 case 0x05: s = "command timed out"; break;
225 case 0x06: s = "message incomplete, issue another command"; break;
226 case 0x07: s = "illegal buffer address"; break;
227 case 0x08: s = "session number out of range"; break;
228 case 0x09: s = "no resource available"; break;
229 case 0x0a: s = "session closed"; break;
230 case 0x0b: s = "command cancelled"; break;
231 case 0x0d: s = "duplicate name"; break;
232 case 0x0e: s = "name table full"; break;
233 case 0x0f: s = "no deletions, name has active sessions"; break;
234 case 0x11: s = "local session table full"; break;
235 case 0x12: s = "remote session table full"; break;
236 case 0x13: s = "illegal name number"; break;
237 case 0x14: s = "no callname"; break;
238 case 0x15: s = "cannot put * in NCB_NAME"; break;
239 case 0x16: s = "name in use on remote adapter"; break;
240 case 0x17: s = "name deleted"; break;
241 case 0x18: s = "session ended abnormally"; break;
242 case 0x19: s = "name conflict detected"; break;
243 case 0x21: s = "interface busy, IRET before retrying"; break;
244 case 0x22: s = "too many commands outstanding, retry later";break;
245 case 0x23: s = "ncb_lana_num field invalid"; break;
246 case 0x24: s = "command completed while cancel occurring "; break;
247 case 0x26: s = "command not valid to cancel"; break;
248 case 0x30: s = "name defined by anther local process"; break;
249 case 0x34: s = "environment undefined. RESET required"; break;
250 case 0x35: s = "required OS resources exhausted"; break;
251 case 0x36: s = "max number of applications exceeded"; break;
252 case 0x37: s = "no saps available for netbios"; break;
253 case 0x38: s = "requested resources are not available"; break;
254 case 0x39: s = "invalid ncb address or length > segment"; break;
255 case 0x3B: s = "invalid NCB DDID"; break;
256 case 0x3C: s = "lock of user area failed"; break;
257 case 0x3f: s = "NETBIOS not loaded"; break;
258 case 0x40: s = "system error"; break;
259 default: s = "unknown error";
265 char * myCrt_Dispatch(int i)
270 return "(00)ReceiveCoreMakeDir";
272 return "(01)ReceiveCoreRemoveDir";
274 return "(02)ReceiveCoreOpen";
276 return "(03)ReceiveCoreCreate";
278 return "(04)ReceiveCoreClose";
280 return "(05)ReceiveCoreFlush";
282 return "(06)ReceiveCoreUnlink";
284 return "(07)ReceiveCoreRename";
286 return "(08)ReceiveCoreGetFileAttributes";
288 return "(09)ReceiveCoreSetFileAttributes";
290 return "(0a)ReceiveCoreRead";
292 return "(0b)ReceiveCoreWrite";
294 return "(0c)ReceiveCoreLockRecord";
296 return "(0d)ReceiveCoreUnlockRecord";
298 return "(0e)SendCoreBadOp";
300 return "(0f)ReceiveCoreCreate";
302 return "(10)ReceiveCoreCheckPath";
304 return "(11)SendCoreBadOp";
306 return "(12)ReceiveCoreSeek";
308 return "(1a)ReceiveCoreReadRaw";
310 return "(1d)ReceiveCoreWriteRawDummy";
312 return "(22)ReceiveV3SetAttributes";
314 return "(23)ReceiveV3GetAttributes";
316 return "(24)ReceiveV3LockingX";
318 return "(25)ReceiveV3Trans";
320 return "(26)ReceiveV3Trans[aux]";
322 return "(29)SendCoreBadOp";
324 return "(2b)ReceiveCoreEcho";
326 return "(2d)ReceiveV3OpenX";
328 return "(2e)ReceiveV3ReadX";
330 return "(2f)ReceiveV3WriteX";
332 return "(32)ReceiveV3Tran2A";
334 return "(33)ReceiveV3Tran2A[aux]";
336 return "(34)ReceiveV3FindClose";
338 return "(35)ReceiveV3FindNotifyClose";
340 return "(70)ReceiveCoreTreeConnect";
342 return "(71)ReceiveCoreTreeDisconnect";
344 return "(72)ReceiveNegotiate";
346 return "(73)ReceiveV3SessionSetupX";
348 return "(74)ReceiveV3UserLogoffX";
350 return "(75)ReceiveV3TreeConnectX";
352 return "(80)ReceiveCoreGetDiskAttributes";
354 return "(81)ReceiveCoreSearchDir";
358 return "(83)FindUnique";
360 return "(84)FindClose";
362 return "(A0)ReceiveNTTransact";
364 return "(A2)ReceiveNTCreateX";
366 return "(A4)ReceiveNTCancel";
368 return "(A5)ReceiveNTRename";
370 return "(C0)OpenPrintFile";
372 return "(C1)WritePrintFile";
374 return "(C2)ClosePrintFile";
376 return "(C3)GetPrintQueue";
378 return "(D8)ReadBulk";
380 return "(D9)WriteBulk";
382 return "(DA)WriteBulkData";
384 return "unknown SMB op";
388 char * myCrt_2Dispatch(int i)
393 return "unknown SMB op-2";
395 return "S(00)CreateFile_ReceiveTran2Open";
397 return "S(01)FindFirst_ReceiveTran2SearchDir";
399 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
401 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
403 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
405 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
407 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
409 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
411 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
413 return "S(09)_ReceiveTran2FSCTL";
415 return "S(0a)_ReceiveTran2IOCTL";
417 return "S(0b)_ReceiveTran2FindNotifyFirst";
419 return "S(0c)_ReceiveTran2FindNotifyNext";
421 return "S(0d)_ReceiveTran2CreateDirectory";
423 return "S(0e)_ReceiveTran2SessionSetup";
425 return "S(0f)_QueryFileSystemInformationFid";
427 return "S(10)_ReceiveTran2GetDfsReferral";
429 return "S(11)_ReceiveTran2ReportDfsInconsistency";
433 char * myCrt_RapDispatch(int i)
438 return "unknown RAP OP";
440 return "RAP(0)NetShareEnum";
442 return "RAP(1)NetShareGetInfo";
444 return "RAP(13)NetServerGetInfo";
446 return "RAP(63)NetWkStaGetInfo";
450 /* scache must be locked */
451 unsigned int smb_Attributes(cm_scache_t *scp)
455 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
456 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
457 scp->fileType == CM_SCACHETYPE_INVALID)
459 attrs = SMB_ATTR_DIRECTORY;
460 #ifdef SPECIAL_FOLDERS
461 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
462 #endif /* SPECIAL_FOLDERS */
463 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
464 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
469 * We used to mark a file RO if it was in an RO volume, but that
470 * turns out to be impolitic in NT. See defect 10007.
473 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
474 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
476 if ((scp->unixModeBits & 0222) == 0)
477 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
483 /* Check if the named file/dir is a dotfile/dotdir */
484 /* String pointed to by lastComp can have leading slashes, but otherwise should have
485 no other patch components */
486 unsigned int smb_IsDotFile(char *lastComp) {
489 /* skip over slashes */
490 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
495 /* nulls, curdir and parent dir doesn't count */
501 if(*(s+1) == '.' && !*(s + 2))
508 static int ExtractBits(WORD bits, short start, short len)
515 num = bits << (16 - end);
516 num = num >> ((16 - end) + start);
521 void ShowUnixTime(char *FuncName, time_t unixTime)
526 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
528 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
529 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
531 int day, month, year, sec, min, hour;
534 day = ExtractBits(wDate, 0, 5);
535 month = ExtractBits(wDate, 5, 4);
536 year = ExtractBits(wDate, 9, 7) + 1980;
538 sec = ExtractBits(wTime, 0, 5);
539 min = ExtractBits(wTime, 5, 6);
540 hour = ExtractBits(wTime, 11, 5);
542 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
543 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
547 /* Determine if we are observing daylight savings time */
548 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
550 TIME_ZONE_INFORMATION timeZoneInformation;
551 SYSTEMTIME utc, local, localDST;
553 /* Get the time zone info. NT uses this to calc if we are in DST. */
554 GetTimeZoneInformation(&timeZoneInformation);
556 /* Return the daylight bias */
557 *pDstBias = timeZoneInformation.DaylightBias;
559 /* Return the bias */
560 *pBias = timeZoneInformation.Bias;
562 /* Now determine if DST is being observed */
564 /* Get the UTC (GMT) time */
567 /* Convert UTC time to local time using the time zone info. If we are
568 observing DST, the calculated local time will include this.
570 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
572 /* Set the daylight bias to 0. The daylight bias is the amount of change
573 * in time that we use for daylight savings time. By setting this to 0
574 * we cause there to be no change in time during daylight savings time.
576 timeZoneInformation.DaylightBias = 0;
578 /* Convert the utc time to local time again, but this time without any
579 adjustment for daylight savings time.
581 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
583 /* If the two times are different, then it means that the localDST that
584 we calculated includes the daylight bias, and therefore we are
585 observing daylight savings time.
587 *pDST = localDST.wHour != local.wHour;
591 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
593 BOOL dst; /* Will be TRUE if observing DST */
594 LONG dstBias; /* Offset from local time if observing DST */
595 LONG bias; /* Offset from GMT for local time */
598 * This function will adjust the last write time to compensate
599 * for two bugs in the smb client:
601 * 1) During Daylight Savings Time, the LastWriteTime is ahead
602 * in time by the DaylightBias (ignoring the sign - the
603 * DaylightBias is always stored as a negative number). If
604 * the DaylightBias is -60, then the LastWriteTime will be
605 * ahead by 60 minutes.
607 * 2) If the local time zone is a positive offset from GMT, then
608 * the LastWriteTime will be the correct local time plus the
609 * Bias (ignoring the sign - a positive offset from GMT is
610 * always stored as a negative Bias). If the Bias is -120,
611 * then the LastWriteTime will be ahead by 120 minutes.
613 * These bugs can occur at the same time.
616 GetTimeZoneInfo(&dst, &dstBias, &bias);
618 /* First adjust for DST */
620 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
622 /* Now adjust for a positive offset from GMT (a negative bias). */
624 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
627 #ifndef USE_NUMERIC_TIME_CONV
629 * Calculate the difference (in seconds) between local time and GMT.
630 * This enables us to convert file times to kludge-GMT.
636 struct tm gmt_tm, local_tm;
637 int days, hours, minutes, seconds;
640 gmt_tm = *(gmtime(&t));
641 local_tm = *(localtime(&t));
643 days = local_tm.tm_yday - gmt_tm.tm_yday;
644 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
645 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
646 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
650 #endif /* USE_NUMERIC_TIME_CONV */
652 #ifdef USE_NUMERIC_TIME_CONV
653 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
655 // Note that LONGLONG is a 64-bit value
658 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
659 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
660 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
663 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
668 time_t ersatz_unixTime;
671 * Must use kludge-GMT instead of real GMT.
672 * kludge-GMT is computed by adding time zone difference to localtime.
675 * ltp = gmtime(&unixTime);
677 ersatz_unixTime = unixTime - smb_NowTZ;
678 ltp = localtime(&ersatz_unixTime);
680 /* if we fail, make up something */
683 localJunk.tm_year = 89 - 20;
684 localJunk.tm_mon = 4;
685 localJunk.tm_mday = 12;
686 localJunk.tm_hour = 0;
687 localJunk.tm_min = 0;
688 localJunk.tm_sec = 0;
691 stm.wYear = ltp->tm_year + 1900;
692 stm.wMonth = ltp->tm_mon + 1;
693 stm.wDayOfWeek = ltp->tm_wday;
694 stm.wDay = ltp->tm_mday;
695 stm.wHour = ltp->tm_hour;
696 stm.wMinute = ltp->tm_min;
697 stm.wSecond = ltp->tm_sec;
698 stm.wMilliseconds = 0;
700 SystemTimeToFileTime(&stm, largeTimep);
702 #endif /* USE_NUMERIC_TIME_CONV */
704 #ifdef USE_NUMERIC_TIME_CONV
705 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
707 // Note that LONGLONG is a 64-bit value
710 ll = largeTimep->dwHighDateTime;
712 ll += largeTimep->dwLowDateTime;
714 ll -= 116444736000000000;
717 *unixTimep = (DWORD)ll;
719 #else /* USE_NUMERIC_TIME_CONV */
720 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
726 FileTimeToSystemTime(largeTimep, &stm);
728 lt.tm_year = stm.wYear - 1900;
729 lt.tm_mon = stm.wMonth - 1;
730 lt.tm_wday = stm.wDayOfWeek;
731 lt.tm_mday = stm.wDay;
732 lt.tm_hour = stm.wHour;
733 lt.tm_min = stm.wMinute;
734 lt.tm_sec = stm.wSecond;
737 save_timezone = _timezone;
738 _timezone += smb_NowTZ;
739 *unixTimep = mktime(<);
740 _timezone = save_timezone;
742 #endif /* USE_NUMERIC_TIME_CONV */
744 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
754 /* if we fail, make up something */
757 localJunk.tm_year = 89 - 20;
758 localJunk.tm_mon = 4;
759 localJunk.tm_mday = 12;
760 localJunk.tm_hour = 0;
761 localJunk.tm_min = 0;
762 localJunk.tm_sec = 0;
765 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
766 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
767 *searchTimep = (dosDate<<16) | dosTime;
770 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
772 unsigned short dosDate;
773 unsigned short dosTime;
776 dosDate = (unsigned short) (searchTime & 0xffff);
777 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
779 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
780 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
781 localTm.tm_mday = (dosDate) & 0x1f;
782 localTm.tm_hour = (dosTime>>11) & 0x1f;
783 localTm.tm_min = (dosTime >> 5) & 0x3f;
784 localTm.tm_sec = (dosTime & 0x1f) * 2;
785 localTm.tm_isdst = -1; /* compute whether DST in effect */
787 *unixTimep = mktime(&localTm);
790 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
792 time_t diff_t = unixTime - smb_localZero;
793 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
794 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
796 *dosUTimep = (afs_uint32)diff_t;
799 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
801 *unixTimep = dosTime + smb_localZero;
804 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
808 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
809 lock_ObtainWrite(&smb_rctLock);
810 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
811 if (vcp->magic != SMB_VC_MAGIC)
812 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
815 if (lsn == vcp->lsn && lana == vcp->lana &&
816 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
817 smb_HoldVCNoLock(vcp);
821 if (!vcp && (flags & SMB_FLAG_CREATE)) {
822 vcp = malloc(sizeof(*vcp));
823 memset(vcp, 0, sizeof(*vcp));
824 vcp->vcID = ++numVCs;
825 vcp->magic = SMB_VC_MAGIC;
826 vcp->refCount = 2; /* smb_allVCsp and caller */
829 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
830 vcp->nextp = smb_allVCsp;
832 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
837 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
838 /* We must obtain a challenge for extended auth
839 * in case the client negotiates smb v3
841 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
842 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
843 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
844 ULONG lsaRespSize = 0;
846 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
848 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
855 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
856 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
857 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
858 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
859 nts, ntsEx, lsaRespSize);
861 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
863 if (ntsEx == STATUS_SUCCESS) {
864 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
865 LsaFreeReturnBuffer(lsaResp);
868 * This will cause the subsequent authentication to fail but
869 * that is better than us dereferencing a NULL pointer and
872 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
876 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
878 if (numVCs >= CM_SESSION_RESERVED) {
880 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
883 lock_ReleaseWrite(&smb_rctLock);
884 lock_ReleaseWrite(&smb_globalLock);
888 int smb_IsStarMask(char *maskp)
893 for(i=0; i<11; i++) {
895 if (tc == '?' || tc == '*' || tc == '>')
901 void smb_ReleaseVCInternal(smb_vc_t *vcp)
908 if (vcp->refCount == 0) {
909 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
910 /* remove VCP from smb_deadVCsp */
911 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
917 lock_FinalizeMutex(&vcp->mx);
918 memset(vcp,0,sizeof(smb_vc_t));
921 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
925 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
926 avcp?"not ":"",vcp, vcp->refCount);
928 GenerateMiniDump(NULL);
930 /* This is a wrong. However, I suspect that there is an undercount
931 * and I don't want to release 1.4.1 in a state that will allow
932 * smb_vc_t objects to be deallocated while still in the
933 * smb_allVCsp list. The list is supposed to keep a reference
934 * to the smb_vc_t. Put it back.
941 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
943 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
944 smb_ReleaseVCInternal(vcp);
947 void smb_ReleaseVC(smb_vc_t *vcp)
949 lock_ObtainWrite(&smb_rctLock);
950 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
951 smb_ReleaseVCInternal(vcp);
952 lock_ReleaseWrite(&smb_rctLock);
955 void smb_HoldVCNoLock(smb_vc_t *vcp)
958 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
961 void smb_HoldVC(smb_vc_t *vcp)
963 lock_ObtainWrite(&smb_rctLock);
965 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
966 lock_ReleaseWrite(&smb_rctLock);
969 void smb_CleanupDeadVC(smb_vc_t *vcp)
977 smb_user_t *uidpIter;
978 smb_user_t *uidpNext;
982 lock_ObtainMutex(&vcp->mx);
983 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
984 lock_ReleaseMutex(&vcp->mx);
985 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
988 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
989 lock_ReleaseMutex(&vcp->mx);
990 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
992 lock_ObtainWrite(&smb_rctLock);
993 /* remove VCP from smb_allVCsp */
994 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
995 if ((*vcpp)->magic != SMB_VC_MAGIC)
996 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1000 vcp->nextp = smb_deadVCsp;
1002 /* Hold onto the reference until we are done with this function */
1007 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1008 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1010 if (fidpIter->delete)
1013 fid = fidpIter->fid;
1014 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1016 smb_HoldFIDNoLock(fidpIter);
1017 lock_ReleaseWrite(&smb_rctLock);
1019 smb_CloseFID(vcp, fidpIter, NULL, 0);
1020 smb_ReleaseFID(fidpIter);
1022 lock_ObtainWrite(&smb_rctLock);
1023 fidpNext = vcp->fidsp;
1026 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1027 tidpNext = tidpIter->nextp;
1028 if (tidpIter->delete)
1030 tidpIter->delete = 1;
1032 tid = tidpIter->tid;
1033 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1035 smb_HoldTIDNoLock(tidpIter);
1036 lock_ReleaseWrite(&smb_rctLock);
1038 smb_ReleaseTID(tidpIter);
1040 lock_ObtainWrite(&smb_rctLock);
1041 tidpNext = vcp->tidsp;
1044 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1045 uidpNext = uidpIter->nextp;
1046 if (uidpIter->delete)
1048 uidpIter->delete = 1;
1050 /* do not add an additional reference count for the smb_user_t
1051 * as the smb_vc_t already is holding a reference */
1052 lock_ReleaseWrite(&smb_rctLock);
1054 smb_ReleaseUID(uidpIter);
1056 lock_ObtainWrite(&smb_rctLock);
1057 uidpNext = vcp->usersp;
1060 /* The vcp is now on the deadVCsp list. We intentionally drop the
1061 * reference so that the refcount can reach 0 and we can delete it */
1062 smb_ReleaseVCNoLock(vcp);
1064 lock_ReleaseWrite(&smb_rctLock);
1065 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1068 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1072 lock_ObtainWrite(&smb_rctLock);
1074 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1075 if (tidp->refCount == 0 && tidp->delete) {
1077 lock_ReleaseWrite(&smb_rctLock);
1078 smb_ReleaseTID(tidp);
1079 lock_ObtainWrite(&smb_rctLock);
1083 if (tid == tidp->tid) {
1088 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1089 tidp = malloc(sizeof(*tidp));
1090 memset(tidp, 0, sizeof(*tidp));
1091 tidp->nextp = vcp->tidsp;
1094 smb_HoldVCNoLock(vcp);
1096 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1099 lock_ReleaseWrite(&smb_rctLock);
1103 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1108 void smb_ReleaseTID(smb_tid_t *tidp)
1115 lock_ObtainWrite(&smb_rctLock);
1116 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1117 if (tidp->refCount == 0 && (tidp->delete)) {
1118 ltpp = &tidp->vcp->tidsp;
1119 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1123 osi_assertx(tp != NULL, "null smb_tid_t");
1125 lock_FinalizeMutex(&tidp->mx);
1126 userp = tidp->userp; /* remember to drop ref later */
1128 smb_ReleaseVCNoLock(tidp->vcp);
1131 lock_ReleaseWrite(&smb_rctLock);
1133 cm_ReleaseUser(userp);
1136 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1138 smb_user_t *uidp = NULL;
1140 lock_ObtainWrite(&smb_rctLock);
1141 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1142 if (uid == uidp->userID) {
1144 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1146 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1150 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1151 uidp = malloc(sizeof(*uidp));
1152 memset(uidp, 0, sizeof(*uidp));
1153 uidp->nextp = vcp->usersp;
1154 uidp->refCount = 2; /* one for the vcp and one for the caller */
1156 smb_HoldVCNoLock(vcp);
1158 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1160 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1162 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1164 lock_ReleaseWrite(&smb_rctLock);
1168 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1170 smb_username_t *unp= NULL;
1172 lock_ObtainWrite(&smb_rctLock);
1173 for(unp = usernamesp; unp; unp = unp->nextp) {
1174 if (stricmp(unp->name, usern) == 0 &&
1175 stricmp(unp->machine, machine) == 0) {
1180 if (!unp && (flags & SMB_FLAG_CREATE)) {
1181 unp = malloc(sizeof(*unp));
1182 memset(unp, 0, sizeof(*unp));
1184 unp->nextp = usernamesp;
1185 unp->name = strdup(usern);
1186 unp->machine = strdup(machine);
1188 lock_InitializeMutex(&unp->mx, "username_t mutex");
1189 if (flags & SMB_FLAG_AFSLOGON)
1190 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1193 lock_ReleaseWrite(&smb_rctLock);
1197 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1199 smb_user_t *uidp= NULL;
1201 lock_ObtainWrite(&smb_rctLock);
1202 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1205 if (stricmp(uidp->unp->name, usern) == 0) {
1207 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1208 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1213 lock_ReleaseWrite(&smb_rctLock);
1217 void smb_ReleaseUsername(smb_username_t *unp)
1220 smb_username_t **lupp;
1221 cm_user_t *userp = NULL;
1222 time_t now = osi_Time();
1224 lock_ObtainWrite(&smb_rctLock);
1225 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1226 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1227 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1229 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1233 osi_assertx(up != NULL, "null smb_username_t");
1235 up->nextp = NULL; /* do not remove this */
1236 lock_FinalizeMutex(&unp->mx);
1242 lock_ReleaseWrite(&smb_rctLock);
1245 cm_ReleaseUser(userp);
1249 void smb_HoldUIDNoLock(smb_user_t *uidp)
1254 void smb_ReleaseUID(smb_user_t *uidp)
1258 smb_username_t *unp = NULL;
1260 lock_ObtainWrite(&smb_rctLock);
1261 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1262 if (uidp->refCount == 0) {
1263 lupp = &uidp->vcp->usersp;
1264 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1268 osi_assertx(up != NULL, "null smb_user_t");
1270 lock_FinalizeMutex(&uidp->mx);
1272 smb_ReleaseVCNoLock(uidp->vcp);
1276 lock_ReleaseWrite(&smb_rctLock);
1280 cm_ReleaseUserVCRef(unp->userp);
1281 smb_ReleaseUsername(unp);
1285 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1287 cm_user_t *up = NULL;
1292 lock_ObtainMutex(&uidp->mx);
1294 up = uidp->unp->userp;
1297 lock_ReleaseMutex(&uidp->mx);
1303 /* retrieve a held reference to a user structure corresponding to an incoming
1305 * corresponding release function is cm_ReleaseUser.
1307 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1310 cm_user_t *up = NULL;
1313 smbp = (smb_t *) inp;
1314 uidp = smb_FindUID(vcp, smbp->uid, 0);
1318 up = smb_GetUserFromUID(uidp);
1320 smb_ReleaseUID(uidp);
1325 * Return a pointer to a pathname extracted from a TID structure. The
1326 * TID structure is not held; assume it won't go away.
1328 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1333 tidp = smb_FindTID(vcp, tid, 0);
1337 if (tidp->flags & SMB_TIDFLAG_IPC) {
1338 code = CM_ERROR_TIDIPC;
1339 /* tidp->pathname would be NULL, but that's fine */
1341 *treepath = tidp->pathname;
1342 smb_ReleaseTID(tidp);
1347 /* check to see if we have a chained fid, that is, a fid that comes from an
1348 * OpenAndX message that ran earlier in this packet. In this case, the fid
1349 * field in a read, for example, request, isn't set, since the value is
1350 * supposed to be inherited from the openAndX call.
1352 int smb_ChainFID(int fid, smb_packet_t *inp)
1354 if (inp->fid == 0 || inp->inCount == 0)
1360 /* are we a priv'd user? What does this mean on NT? */
1361 int smb_SUser(cm_user_t *userp)
1366 /* find a file ID. If we pass in 0 we select an unused File ID.
1367 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1368 * smb_fid_t data structure if desired File ID cannot be found.
1370 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1375 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1378 lock_ObtainWrite(&smb_rctLock);
1379 /* figure out if we need to allocate a new file ID */
1382 fid = vcp->fidCounter;
1386 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1387 if (fidp->refCount == 0 && fidp->delete) {
1389 lock_ReleaseWrite(&smb_rctLock);
1390 smb_ReleaseFID(fidp);
1391 lock_ObtainWrite(&smb_rctLock);
1394 if (fid == fidp->fid) {
1397 if (fid == 0xFFFF) {
1399 "New FID number wraps on vcp 0x%x", vcp);
1409 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1410 char eventName[MAX_PATH];
1412 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1413 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1414 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1415 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1416 thrd_CloseHandle(event);
1418 if (fid == 0xFFFF) {
1419 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1425 fidp = malloc(sizeof(*fidp));
1426 memset(fidp, 0, sizeof(*fidp));
1427 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1430 smb_HoldVCNoLock(vcp);
1431 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1433 fidp->curr_chunk = fidp->prev_chunk = -2;
1434 fidp->raw_write_event = event;
1436 vcp->fidCounter = fid+1;
1437 if (vcp->fidCounter == 0xFFFF) {
1438 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1440 vcp->fidCounter = 1;
1445 lock_ReleaseWrite(&smb_rctLock);
1449 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1451 smb_fid_t *fidp = NULL;
1457 lock_ObtainWrite(&smb_rctLock);
1458 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1459 if (scp == fidp->scp) {
1464 lock_ReleaseWrite(&smb_rctLock);
1468 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1474 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1475 /* the sm_fid_t->mx and smb_rctLock must not be held */
1476 void smb_ReleaseFID(smb_fid_t *fidp)
1478 cm_scache_t *scp = NULL;
1479 cm_user_t *userp = NULL;
1480 smb_vc_t *vcp = NULL;
1481 smb_ioctl_t *ioctlp;
1483 lock_ObtainMutex(&fidp->mx);
1484 lock_ObtainWrite(&smb_rctLock);
1485 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1486 if (fidp->refCount == 0 && (fidp->delete)) {
1489 scp = fidp->scp; /* release after lock is released */
1491 lock_ObtainMutex(&scp->mx);
1492 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1493 lock_ReleaseMutex(&scp->mx);
1494 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1497 userp = fidp->userp;
1501 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1502 thrd_CloseHandle(fidp->raw_write_event);
1504 /* and see if there is ioctl stuff to free */
1505 ioctlp = fidp->ioctlp;
1508 cm_FreeSpace(ioctlp->prefix);
1509 if (ioctlp->inAllocp)
1510 free(ioctlp->inAllocp);
1511 if (ioctlp->outAllocp)
1512 free(ioctlp->outAllocp);
1515 lock_ReleaseMutex(&fidp->mx);
1516 lock_FinalizeMutex(&fidp->mx);
1520 smb_ReleaseVCNoLock(vcp);
1522 lock_ReleaseMutex(&fidp->mx);
1524 lock_ReleaseWrite(&smb_rctLock);
1526 /* now release the scache structure */
1528 cm_ReleaseSCache(scp);
1531 cm_ReleaseUser(userp);
1535 * Case-insensitive search for one string in another;
1536 * used to find variable names in submount pathnames.
1538 static char *smb_stristr(char *str1, char *str2)
1542 for (cursor = str1; *cursor; cursor++)
1543 if (stricmp(cursor, str2) == 0)
1550 * Substitute a variable value for its name in a submount pathname. Variable
1551 * name has been identified by smb_stristr() and is in substr. Variable name
1552 * length (plus one) is in substr_size. Variable value is in newstr.
1554 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1559 strcpy(temp, substr + substr_size - 1);
1560 strcpy(substr, newstr);
1564 char VNUserName[] = "%USERNAME%";
1565 char VNLCUserName[] = "%LCUSERNAME%";
1566 char VNComputerName[] = "%COMPUTERNAME%";
1567 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1570 typedef struct smb_findShare_rock {
1574 } smb_findShare_rock_t;
1576 #define SMB_FINDSHARE_EXACT_MATCH 1
1577 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1579 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1583 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1584 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1585 if(!stricmp(dep->name, vrock->shareName))
1586 matchType = SMB_FINDSHARE_EXACT_MATCH;
1588 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1589 if(vrock->match) free(vrock->match);
1590 vrock->match = strdup(dep->name);
1591 vrock->matchType = matchType;
1593 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1594 return CM_ERROR_STOPNOW;
1600 /* find a shareName in the table of submounts */
1601 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1605 char pathName[1024];
1612 DWORD allSubmount = 1;
1614 /* if allSubmounts == 0, only return the //mountRoot/all share
1615 * if in fact it has been been created in the subMounts table.
1616 * This is to allow sites that want to restrict access to the
1619 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1620 0, KEY_QUERY_VALUE, &parmKey);
1621 if (code == ERROR_SUCCESS) {
1622 len = sizeof(allSubmount);
1623 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1624 (BYTE *) &allSubmount, &len);
1625 if (code != ERROR_SUCCESS) {
1628 RegCloseKey (parmKey);
1631 if (allSubmount && _stricmp(shareName, "all") == 0) {
1636 /* In case, the all share is disabled we need to still be able
1637 * to handle ioctl requests
1639 if (_stricmp(shareName, "ioctl$") == 0) {
1640 *pathNamep = strdup("/.__ioctl__");
1644 if (_stricmp(shareName, "IPC$") == 0 ||
1645 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1646 _stricmp(shareName, "DESKTOP.INI") == 0
1652 /* Check for volume references
1654 * They look like <cell>{%,#}<volume>
1656 if (strchr(shareName, '%') != NULL ||
1657 strchr(shareName, '#') != NULL) {
1658 char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1659 /* make room for '/@vol:' + mountchar + NULL terminator*/
1661 osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1662 osi_LogSaveString(smb_logp, shareName));
1664 snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1665 "/" CM_PREFIX_VOL "%s", shareName);
1666 pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1667 len = strlen(pathstr) + 1;
1669 *pathNamep = malloc(len);
1671 strcpy(*pathNamep, pathstr);
1673 osi_Log1(smb_logp, " returning pathname [%s]",
1674 osi_LogSaveString(smb_logp, *pathNamep));
1682 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1683 0, KEY_QUERY_VALUE, &parmKey);
1684 if (code == ERROR_SUCCESS) {
1685 len = sizeof(pathName);
1686 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1687 (BYTE *) pathName, &len);
1688 if (code != ERROR_SUCCESS)
1690 RegCloseKey (parmKey);
1694 if (len != 0 && len != sizeof(pathName) - 1) {
1695 /* We can accept either unix or PC style AFS pathnames. Convert
1696 * Unix-style to PC style here for internal use.
1699 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1700 p += strlen(cm_mountRoot); /* skip mount path */
1703 if (*q == '/') *q = '\\'; /* change to \ */
1709 if (var = smb_stristr(p, VNUserName)) {
1710 if (uidp && uidp->unp)
1711 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1713 smb_subst(p, var, sizeof(VNUserName)," ");
1715 else if (var = smb_stristr(p, VNLCUserName))
1717 if (uidp && uidp->unp)
1718 strcpy(temp, uidp->unp->name);
1722 smb_subst(p, var, sizeof(VNLCUserName), temp);
1724 else if (var = smb_stristr(p, VNComputerName))
1726 sizeTemp = sizeof(temp);
1727 GetComputerName((LPTSTR)temp, &sizeTemp);
1728 smb_subst(p, var, sizeof(VNComputerName), temp);
1730 else if (var = smb_stristr(p, VNLCComputerName))
1732 sizeTemp = sizeof(temp);
1733 GetComputerName((LPTSTR)temp, &sizeTemp);
1735 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1740 *pathNamep = strdup(p);
1745 /* First lookup shareName in root.afs */
1747 smb_findShare_rock_t vrock;
1749 char * p = shareName;
1752 /* attempt to locate a partial match in root.afs. This is because
1753 when using the ANSI RAP calls, the share name is limited to 13 chars
1754 and hence is truncated. Of course we prefer exact matches. */
1756 thyper.HighPart = 0;
1759 vrock.shareName = shareName;
1761 vrock.matchType = 0;
1763 cm_HoldSCache(cm_data.rootSCachep);
1764 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1765 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1766 cm_ReleaseSCache(cm_data.rootSCachep);
1768 if (vrock.matchType) {
1769 sprintf(pathName,"/%s/",vrock.match);
1770 *pathNamep = strdup(strlwr(pathName));
1775 /* if we get here, there was no match for the share in root.afs */
1776 /* so try to create \\<netbiosName>\<cellname> */
1781 /* Get the full name for this cell */
1782 code = cm_SearchCellFile(p, temp, 0, 0);
1783 #ifdef AFS_AFSDB_ENV
1784 if (code && cm_dnsEnabled) {
1786 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1789 /* construct the path */
1791 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1792 *pathNamep = strdup(strlwr(pathName));
1801 /* Client-side offline caching policy types */
1802 #define CSC_POLICY_MANUAL 0
1803 #define CSC_POLICY_DOCUMENTS 1
1804 #define CSC_POLICY_PROGRAMS 2
1805 #define CSC_POLICY_DISABLE 3
1807 int smb_FindShareCSCPolicy(char *shareName)
1813 int retval = CSC_POLICY_MANUAL;
1815 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1816 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1819 REG_OPTION_NON_VOLATILE,
1825 len = sizeof(policy);
1826 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1828 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1830 else if (stricmp(policy, "documents") == 0)
1832 retval = CSC_POLICY_DOCUMENTS;
1834 else if (stricmp(policy, "programs") == 0)
1836 retval = CSC_POLICY_PROGRAMS;
1838 else if (stricmp(policy, "disable") == 0)
1840 retval = CSC_POLICY_DISABLE;
1843 RegCloseKey(hkCSCPolicy);
1847 /* find a dir search structure by cookie value, and return it held.
1848 * Must be called with smb_globalLock held.
1850 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1852 smb_dirSearch_t *dsp;
1854 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1855 if (dsp->cookie == cookie) {
1856 if (dsp != smb_firstDirSearchp) {
1857 /* move to head of LRU queue, too, if we're not already there */
1858 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1859 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1860 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1861 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1862 if (!smb_lastDirSearchp)
1863 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1865 lock_ObtainMutex(&dsp->mx);
1867 lock_ReleaseMutex(&dsp->mx);
1873 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1874 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1875 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1881 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1883 lock_ObtainWrite(&smb_globalLock);
1884 lock_ObtainMutex(&dsp->mx);
1885 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1886 dsp->cookie, dsp, dsp->scp);
1887 dsp->flags |= SMB_DIRSEARCH_DELETE;
1888 if (dsp->scp != NULL) {
1889 lock_ObtainMutex(&dsp->scp->mx);
1890 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1891 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1892 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1893 dsp->scp->bulkStatProgress = hzero;
1895 lock_ReleaseMutex(&dsp->scp->mx);
1897 lock_ReleaseMutex(&dsp->mx);
1898 lock_ReleaseWrite(&smb_globalLock);
1901 /* Must be called with the smb_globalLock held */
1902 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1904 cm_scache_t *scp = NULL;
1906 lock_ObtainMutex(&dsp->mx);
1907 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1908 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1909 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1910 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1911 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1912 lock_ReleaseMutex(&dsp->mx);
1913 lock_FinalizeMutex(&dsp->mx);
1915 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1916 dsp->cookie, dsp, scp);
1919 lock_ReleaseMutex(&dsp->mx);
1921 /* do this now to avoid spurious locking hierarchy creation */
1923 cm_ReleaseSCache(scp);
1926 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1928 lock_ObtainWrite(&smb_globalLock);
1929 smb_ReleaseDirSearchNoLock(dsp);
1930 lock_ReleaseWrite(&smb_globalLock);
1933 /* find a dir search structure by cookie value, and return it held */
1934 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1936 smb_dirSearch_t *dsp;
1938 lock_ObtainWrite(&smb_globalLock);
1939 dsp = smb_FindDirSearchNoLock(cookie);
1940 lock_ReleaseWrite(&smb_globalLock);
1944 /* GC some dir search entries, in the address space expected by the specific protocol.
1945 * Must be called with smb_globalLock held; release the lock temporarily.
1947 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1948 void smb_GCDirSearches(int isV3)
1950 smb_dirSearch_t *prevp;
1951 smb_dirSearch_t *tp;
1952 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1956 victimCount = 0; /* how many have we got so far */
1957 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1958 /* we'll move tp from queue, so
1961 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1962 /* if no one is using this guy, and we're either in the new protocol,
1963 * or we're in the old one and this is a small enough ID to be useful
1964 * to the old protocol, GC this guy.
1966 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1967 /* hold and delete */
1968 lock_ObtainMutex(&tp->mx);
1969 tp->flags |= SMB_DIRSEARCH_DELETE;
1970 lock_ReleaseMutex(&tp->mx);
1971 victimsp[victimCount++] = tp;
1975 /* don't do more than this */
1976 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1980 /* now release them */
1981 for (i = 0; i < victimCount; i++) {
1982 smb_ReleaseDirSearchNoLock(victimsp[i]);
1986 /* function for allocating a dir search entry. We need these to remember enough context
1987 * since we don't get passed the path from call to call during a directory search.
1989 * Returns a held dir search structure, and bumps the reference count on the vnode,
1990 * since it saves a pointer to the vnode.
1992 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1994 smb_dirSearch_t *dsp;
2000 lock_ObtainWrite(&smb_globalLock);
2003 /* what's the biggest ID allowed in this version of the protocol */
2004 /* TODO: do we really want a non v3 dir search request to wrap
2005 smb_dirSearchCounter? */
2006 maxAllowed = isV3 ? 65535 : 255;
2007 if (smb_dirSearchCounter > maxAllowed)
2008 smb_dirSearchCounter = 1;
2010 start = smb_dirSearchCounter;
2013 /* twice so we have enough tries to find guys we GC after one pass;
2014 * 10 extra is just in case I mis-counted.
2016 if (++counter > 2*maxAllowed+10)
2017 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2019 if (smb_dirSearchCounter > maxAllowed) {
2020 smb_dirSearchCounter = 1;
2022 if (smb_dirSearchCounter == start) {
2024 smb_GCDirSearches(isV3);
2027 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2029 /* don't need to watch for refcount zero and deleted, since
2030 * we haven't dropped the global lock.
2032 lock_ObtainMutex(&dsp->mx);
2034 lock_ReleaseMutex(&dsp->mx);
2035 ++smb_dirSearchCounter;
2039 dsp = malloc(sizeof(*dsp));
2040 memset(dsp, 0, sizeof(*dsp));
2041 dsp->cookie = smb_dirSearchCounter;
2042 ++smb_dirSearchCounter;
2044 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2045 dsp->lastTime = osi_Time();
2046 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2047 if (!smb_lastDirSearchp)
2048 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2050 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2054 lock_ReleaseWrite(&smb_globalLock);
2058 static smb_packet_t *GetPacket(void)
2062 lock_ObtainWrite(&smb_globalLock);
2063 tbp = smb_packetFreeListp;
2065 smb_packetFreeListp = tbp->nextp;
2066 lock_ReleaseWrite(&smb_globalLock);
2068 tbp = calloc(65540,1);
2069 tbp->magic = SMB_PACKETMAGIC;
2072 tbp->resumeCode = 0;
2078 tbp->ncb_length = 0;
2083 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2088 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2092 memcpy(tbp, pkt, sizeof(smb_packet_t));
2093 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2095 smb_HoldVC(tbp->vcp);
2099 static NCB *GetNCB(void)
2104 lock_ObtainWrite(&smb_globalLock);
2105 tbp = smb_ncbFreeListp;
2107 smb_ncbFreeListp = tbp->nextp;
2108 lock_ReleaseWrite(&smb_globalLock);
2110 tbp = calloc(sizeof(*tbp),1);
2111 tbp->magic = SMB_NCBMAGIC;
2114 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2116 memset(&tbp->ncb, 0, sizeof(NCB));
2121 void smb_FreePacket(smb_packet_t *tbp)
2123 smb_vc_t * vcp = NULL;
2124 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2126 lock_ObtainWrite(&smb_globalLock);
2127 tbp->nextp = smb_packetFreeListp;
2128 smb_packetFreeListp = tbp;
2129 tbp->magic = SMB_PACKETMAGIC;
2133 tbp->resumeCode = 0;
2139 tbp->ncb_length = 0;
2141 lock_ReleaseWrite(&smb_globalLock);
2147 static void FreeNCB(NCB *bufferp)
2151 tbp = (smb_ncb_t *) bufferp;
2152 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2154 lock_ObtainWrite(&smb_globalLock);
2155 tbp->nextp = smb_ncbFreeListp;
2156 smb_ncbFreeListp = tbp;
2157 lock_ReleaseWrite(&smb_globalLock);
2160 /* get a ptr to the data part of a packet, and its count */
2161 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2165 unsigned char *afterParmsp;
2167 parmBytes = *smbp->wctp << 1;
2168 afterParmsp = smbp->wctp + parmBytes + 1;
2170 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2171 if (nbytesp) *nbytesp = dataBytes;
2173 /* don't forget to skip the data byte count, since it follows
2174 * the parameters; that's where the "2" comes from below.
2176 return (unsigned char *) (afterParmsp + 2);
2179 /* must set all the returned parameters before playing around with the
2180 * data region, since the data region is located past the end of the
2181 * variable number of parameters.
2183 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2185 unsigned char *afterParmsp;
2187 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2189 *afterParmsp++ = dsize & 0xff;
2190 *afterParmsp = (dsize>>8) & 0xff;
2193 /* return the parm'th parameter in the smbp packet */
2194 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2197 unsigned char *parmDatap;
2199 parmCount = *smbp->wctp;
2201 if (parm >= parmCount) {
2204 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2205 parm, parmCount, smbp->ncb_length);
2206 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2207 parm, parmCount, smbp->ncb_length);
2208 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2209 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2210 osi_panic(s, __FILE__, __LINE__);
2212 parmDatap = smbp->wctp + (2*parm) + 1;
2214 return parmDatap[0] + (parmDatap[1] << 8);
2217 /* return the parm'th parameter in the smbp packet */
2218 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2221 unsigned char *parmDatap;
2223 parmCount = *smbp->wctp;
2225 if (parm >= parmCount) {
2228 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2229 parm, parmCount, smbp->ncb_length);
2230 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2231 parm, parmCount, smbp->ncb_length);
2232 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2233 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2234 osi_panic(s, __FILE__, __LINE__);
2236 parmDatap = smbp->wctp + (2*parm) + 1;
2238 return parmDatap[0];
2241 /* return the parm'th parameter in the smbp packet */
2242 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2245 unsigned char *parmDatap;
2247 parmCount = *smbp->wctp;
2249 if (parm + 1 >= parmCount) {
2252 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2253 parm, parmCount, smbp->ncb_length);
2254 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2255 parm, parmCount, smbp->ncb_length);
2256 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2257 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2258 osi_panic(s, __FILE__, __LINE__);
2260 parmDatap = smbp->wctp + (2*parm) + 1;
2262 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2265 /* return the parm'th parameter in the smbp packet */
2266 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2269 unsigned char *parmDatap;
2271 parmCount = *smbp->wctp;
2273 if (parm * 2 + offset >= parmCount * 2) {
2276 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2277 parm, offset, parmCount, smbp->ncb_length);
2278 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2279 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2280 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2281 parm, offset, parmCount, smbp->ncb_length);
2282 osi_panic(s, __FILE__, __LINE__);
2284 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2286 return parmDatap[0] + (parmDatap[1] << 8);
2289 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2293 /* make sure we have enough slots */
2294 if (*smbp->wctp <= slot)
2295 *smbp->wctp = slot+1;
2297 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2298 *parmDatap++ = parmValue & 0xff;
2299 *parmDatap = (parmValue>>8) & 0xff;
2302 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2306 /* make sure we have enough slots */
2307 if (*smbp->wctp <= slot)
2308 *smbp->wctp = slot+2;
2310 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2311 *parmDatap++ = parmValue & 0xff;
2312 *parmDatap++ = (parmValue>>8) & 0xff;
2313 *parmDatap++ = (parmValue>>16) & 0xff;
2314 *parmDatap = (parmValue>>24) & 0xff;
2317 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2322 /* make sure we have enough slots */
2323 if (*smbp->wctp <= slot)
2324 *smbp->wctp = slot+4;
2326 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2328 *parmDatap++ = *parmValuep++;
2331 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2335 /* make sure we have enough slots */
2336 if (*smbp->wctp <= slot) {
2337 if (smbp->oddByte) {
2339 *smbp->wctp = slot+1;
2344 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2345 *parmDatap++ = parmValue & 0xff;
2348 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2352 lastSlashp = strrchr(inPathp, '\\');
2354 *lastComponentp = lastSlashp;
2357 if (inPathp == lastSlashp)
2359 *outPathp++ = *inPathp++;
2368 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2373 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2378 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2384 tlen = inp[0] + (inp[1]<<8);
2385 inp += 2; /* skip length field */
2388 *chainpp = inp + tlen;
2397 /* format a packet as a response */
2398 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2403 outp = (smb_t *) op;
2405 /* zero the basic structure through the smb_wct field, and zero the data
2406 * size field, assuming that wct stays zero; otherwise, you have to
2407 * explicitly set the data size field, too.
2409 inSmbp = (smb_t *) inp;
2410 memset(outp, 0, sizeof(smb_t)+2);
2416 outp->com = inSmbp->com;
2417 outp->tid = inSmbp->tid;
2418 outp->pid = inSmbp->pid;
2419 outp->uid = inSmbp->uid;
2420 outp->mid = inSmbp->mid;
2421 outp->res[0] = inSmbp->res[0];
2422 outp->res[1] = inSmbp->res[1];
2423 op->inCom = inSmbp->com;
2425 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2426 #ifdef SEND_CANONICAL_PATHNAMES
2427 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2429 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2431 /* copy fields in generic packet area */
2432 op->wctp = &outp->wct;
2435 /* send a (probably response) packet; vcp tells us to whom to send it.
2436 * we compute the length by looking at wct and bcc fields.
2438 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2452 memset((char *)ncbp, 0, sizeof(NCB));
2454 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2455 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2456 extra += tp[0] + (tp[1]<<8);
2457 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2458 extra += 3; /* wct and length fields */
2460 ncbp->ncb_length = extra; /* bytes to send */
2461 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2462 ncbp->ncb_lana_num = vcp->lana;
2463 ncbp->ncb_command = NCBSEND; /* op means send data */
2464 ncbp->ncb_buffer = (char *) inp;/* packet */
2465 code = Netbios(ncbp);
2468 const char * s = ncb_error_string(code);
2469 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2470 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2472 lock_ObtainMutex(&vcp->mx);
2473 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2474 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2476 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2477 lock_ReleaseMutex(&vcp->mx);
2478 lock_ObtainWrite(&smb_globalLock);
2479 dead_sessions[vcp->session] = TRUE;
2480 lock_ReleaseWrite(&smb_globalLock);
2481 smb_CleanupDeadVC(vcp);
2483 lock_ReleaseMutex(&vcp->mx);
2491 void smb_MapNTError(long code, unsigned long *NTStatusp)
2493 unsigned long NTStatus;
2495 /* map CM_ERROR_* errors to NT 32-bit status codes */
2496 /* NT Status codes are listed in ntstatus.h not winerror.h */
2497 if (code == CM_ERROR_NOSUCHCELL) {
2498 NTStatus = 0xC000000FL; /* No such file */
2500 else if (code == CM_ERROR_NOSUCHVOLUME) {
2501 NTStatus = 0xC000000FL; /* No such file */
2503 else if (code == CM_ERROR_TIMEDOUT) {
2505 NTStatus = 0xC00000CFL; /* Sharing Paused */
2507 NTStatus = 0x00000102L; /* Timeout */
2510 else if (code == CM_ERROR_RETRY) {
2511 NTStatus = 0xC000022DL; /* Retry */
2513 else if (code == CM_ERROR_NOACCESS) {
2514 NTStatus = 0xC0000022L; /* Access denied */
2516 else if (code == CM_ERROR_READONLY) {
2517 NTStatus = 0xC00000A2L; /* Write protected */
2519 else if (code == CM_ERROR_NOSUCHFILE ||
2520 code == CM_ERROR_BPLUS_NOMATCH) {
2521 NTStatus = 0xC000000FL; /* No such file */
2523 else if (code == CM_ERROR_NOSUCHPATH) {
2524 NTStatus = 0xC000003AL; /* Object path not found */
2526 else if (code == CM_ERROR_TOOBIG) {
2527 NTStatus = 0xC000007BL; /* Invalid image format */
2529 else if (code == CM_ERROR_INVAL) {
2530 NTStatus = 0xC000000DL; /* Invalid parameter */
2532 else if (code == CM_ERROR_BADFD) {
2533 NTStatus = 0xC0000008L; /* Invalid handle */
2535 else if (code == CM_ERROR_BADFDOP) {
2536 NTStatus = 0xC0000022L; /* Access denied */
2538 else if (code == CM_ERROR_EXISTS) {
2539 NTStatus = 0xC0000035L; /* Object name collision */
2541 else if (code == CM_ERROR_NOTEMPTY) {
2542 NTStatus = 0xC0000101L; /* Directory not empty */
2544 else if (code == CM_ERROR_CROSSDEVLINK) {
2545 NTStatus = 0xC00000D4L; /* Not same device */
2547 else if (code == CM_ERROR_NOTDIR) {
2548 NTStatus = 0xC0000103L; /* Not a directory */
2550 else if (code == CM_ERROR_ISDIR) {
2551 NTStatus = 0xC00000BAL; /* File is a directory */
2553 else if (code == CM_ERROR_BADOP) {
2555 /* I have no idea where this comes from */
2556 NTStatus = 0xC09820FFL; /* SMB no support */
2558 NTStatus = 0xC00000BBL; /* Not supported */
2559 #endif /* COMMENT */
2561 else if (code == CM_ERROR_BADSHARENAME) {
2562 NTStatus = 0xC00000CCL; /* Bad network name */
2564 else if (code == CM_ERROR_NOIPC) {
2566 NTStatus = 0xC0000022L; /* Access Denied */
2568 NTStatus = 0xC000013DL; /* Remote Resources */
2571 else if (code == CM_ERROR_CLOCKSKEW) {
2572 NTStatus = 0xC0000133L; /* Time difference at DC */
2574 else if (code == CM_ERROR_BADTID) {
2575 NTStatus = 0xC0982005L; /* SMB bad TID */
2577 else if (code == CM_ERROR_USESTD) {
2578 NTStatus = 0xC09820FBL; /* SMB use standard */
2580 else if (code == CM_ERROR_QUOTA) {
2582 NTStatus = 0xC0000044L; /* Quota exceeded */
2584 NTStatus = 0xC000007FL; /* Disk full */
2587 else if (code == CM_ERROR_SPACE) {
2588 NTStatus = 0xC000007FL; /* Disk full */
2590 else if (code == CM_ERROR_ATSYS) {
2591 NTStatus = 0xC0000033L; /* Object name invalid */
2593 else if (code == CM_ERROR_BADNTFILENAME) {
2594 NTStatus = 0xC0000033L; /* Object name invalid */
2596 else if (code == CM_ERROR_WOULDBLOCK) {
2597 NTStatus = 0xC0000055L; /* Lock not granted */
2599 else if (code == CM_ERROR_SHARING_VIOLATION) {
2600 NTStatus = 0xC0000043L; /* Sharing violation */
2602 else if (code == CM_ERROR_LOCK_CONFLICT) {
2603 NTStatus = 0xC0000054L; /* Lock conflict */
2605 else if (code == CM_ERROR_PARTIALWRITE) {
2606 NTStatus = 0xC000007FL; /* Disk full */
2608 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2609 NTStatus = 0xC0000023L; /* Buffer too small */
2611 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2612 NTStatus = 0xC0000035L; /* Object name collision */
2614 else if (code == CM_ERROR_BADPASSWORD) {
2615 NTStatus = 0xC000006DL; /* unknown username or bad password */
2617 else if (code == CM_ERROR_BADLOGONTYPE) {
2618 NTStatus = 0xC000015BL; /* logon type not granted */
2620 else if (code == CM_ERROR_GSSCONTINUE) {
2621 NTStatus = 0xC0000016L; /* more processing required */
2623 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2625 NTStatus = 0xC0000280L; /* reparse point not resolved */
2627 NTStatus = 0xC0000022L; /* Access Denied */
2630 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2631 NTStatus = 0xC0000257L; /* Path Not Covered */
2634 else if (code == CM_ERROR_ALLBUSY) {
2635 NTStatus = 0xC00000BFL; /* Network Busy */
2637 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2638 NTStatus = 0xC0000350L; /* Remote Host Down */
2641 /* we do not want to be telling the SMB/CIFS client that
2642 * the AFS Client Service is busy or down.
2644 else if (code == CM_ERROR_ALLBUSY ||
2645 code == CM_ERROR_ALLOFFLINE ||
2646 code == CM_ERROR_ALLDOWN) {
2647 NTStatus = 0xC00000BEL; /* Bad Network Path */
2650 else if (code == RXKADUNKNOWNKEY) {
2651 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2653 else if (code == CM_ERROR_BAD_LEVEL) {
2654 NTStatus = 0xC0000148L; /* Invalid Level */
2656 NTStatus = 0xC0982001L; /* SMB non-specific error */
2659 *NTStatusp = NTStatus;
2660 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2663 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2664 unsigned char *classp)
2666 unsigned char class;
2667 unsigned short error;
2669 /* map CM_ERROR_* errors to SMB errors */
2670 if (code == CM_ERROR_NOSUCHCELL) {
2672 error = 3; /* bad path */
2674 else if (code == CM_ERROR_NOSUCHVOLUME) {
2676 error = 3; /* bad path */
2678 else if (code == CM_ERROR_TIMEDOUT) {
2680 error = 81; /* server is paused */
2682 else if (code == CM_ERROR_RETRY) {
2683 class = 2; /* shouldn't happen */
2686 else if (code == CM_ERROR_NOACCESS) {
2688 error = 4; /* bad access */
2690 else if (code == CM_ERROR_READONLY) {
2692 error = 19; /* read only */
2694 else if (code == CM_ERROR_NOSUCHFILE ||
2695 code == CM_ERROR_BPLUS_NOMATCH) {
2697 error = 2; /* ENOENT! */
2699 else if (code == CM_ERROR_NOSUCHPATH) {
2701 error = 3; /* Bad path */
2703 else if (code == CM_ERROR_TOOBIG) {
2705 error = 11; /* bad format */
2707 else if (code == CM_ERROR_INVAL) {
2708 class = 2; /* server non-specific error code */
2711 else if (code == CM_ERROR_BADFD) {
2713 error = 6; /* invalid file handle */
2715 else if (code == CM_ERROR_BADFDOP) {
2716 class = 1; /* invalid op on FD */
2719 else if (code == CM_ERROR_EXISTS) {
2721 error = 80; /* file already exists */
2723 else if (code == CM_ERROR_NOTEMPTY) {
2725 error = 5; /* delete directory not empty */
2727 else if (code == CM_ERROR_CROSSDEVLINK) {
2729 error = 17; /* EXDEV */
2731 else if (code == CM_ERROR_NOTDIR) {
2732 class = 1; /* bad path */
2735 else if (code == CM_ERROR_ISDIR) {
2736 class = 1; /* access denied; DOS doesn't have a good match */
2739 else if (code == CM_ERROR_BADOP) {
2743 else if (code == CM_ERROR_BADSHARENAME) {
2747 else if (code == CM_ERROR_NOIPC) {
2749 error = 4; /* bad access */
2751 else if (code == CM_ERROR_CLOCKSKEW) {
2752 class = 1; /* invalid function */
2755 else if (code == CM_ERROR_BADTID) {
2759 else if (code == CM_ERROR_USESTD) {
2763 else if (code == CM_ERROR_REMOTECONN) {
2767 else if (code == CM_ERROR_QUOTA) {
2768 if (vcp->flags & SMB_VCFLAG_USEV3) {
2770 error = 39; /* disk full */
2774 error = 5; /* access denied */
2777 else if (code == CM_ERROR_SPACE) {
2778 if (vcp->flags & SMB_VCFLAG_USEV3) {
2780 error = 39; /* disk full */
2784 error = 5; /* access denied */
2787 else if (code == CM_ERROR_PARTIALWRITE) {
2789 error = 39; /* disk full */
2791 else if (code == CM_ERROR_ATSYS) {
2793 error = 2; /* ENOENT */
2795 else if (code == CM_ERROR_WOULDBLOCK) {
2797 error = 33; /* lock conflict */
2799 else if (code == CM_ERROR_LOCK_CONFLICT) {
2801 error = 33; /* lock conflict */
2803 else if (code == CM_ERROR_SHARING_VIOLATION) {
2805 error = 33; /* lock conflict */
2807 else if (code == CM_ERROR_NOFILES) {
2809 error = 18; /* no files in search */
2811 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2813 error = 183; /* Samba uses this */
2815 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2816 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2818 error = 2; /* bad password */
2820 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2822 error = 3; /* bad path */
2831 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2834 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2836 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2837 return CM_ERROR_BADOP;
2840 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2842 unsigned short EchoCount, i;
2843 char *data, *outdata;
2846 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2848 for (i=1; i<=EchoCount; i++) {
2849 data = smb_GetSMBData(inp, &dataSize);
2850 smb_SetSMBParm(outp, 0, i);
2851 smb_SetSMBDataLength(outp, dataSize);
2852 outdata = smb_GetSMBData(outp, NULL);
2853 memcpy(outdata, data, dataSize);
2854 smb_SendPacket(vcp, outp);
2860 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2863 long count, minCount, finalCount;
2868 cm_user_t *userp = NULL;
2871 char *rawBuf = NULL;
2876 fd = smb_GetSMBParm(inp, 0);
2877 count = smb_GetSMBParm(inp, 3);
2878 minCount = smb_GetSMBParm(inp, 4);
2879 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2881 if (*inp->wctp == 10) {
2882 /* we were sent a request with 64-bit file offsets */
2883 #ifdef AFS_LARGEFILES
2884 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2886 if (LargeIntegerLessThanZero(offset)) {
2887 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2891 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2892 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2895 offset.HighPart = 0;
2899 /* we were sent a request with 32-bit file offsets */
2900 offset.HighPart = 0;
2903 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2904 fd, offset.HighPart, offset.LowPart, count);
2906 fidp = smb_FindFID(vcp, fd, 0);
2910 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
2911 smb_CloseFID(vcp, fidp, NULL, 0);
2912 code = CM_ERROR_NOSUCHFILE;
2917 pid = ((smb_t *) inp)->pid;
2919 LARGE_INTEGER LOffset, LLength;
2922 key = cm_GenerateKey(vcp->vcID, pid, fd);
2924 LOffset.HighPart = offset.HighPart;
2925 LOffset.LowPart = offset.LowPart;
2926 LLength.HighPart = 0;
2927 LLength.LowPart = count;
2929 lock_ObtainMutex(&fidp->scp->mx);
2930 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2931 lock_ReleaseMutex(&fidp->scp->mx);
2937 lock_ObtainMutex(&smb_RawBufLock);
2939 /* Get a raw buf, from head of list */
2940 rawBuf = smb_RawBufs;
2941 smb_RawBufs = *(char **)smb_RawBufs;
2943 lock_ReleaseMutex(&smb_RawBufLock);
2947 lock_ObtainMutex(&fidp->mx);
2948 if (fidp->flags & SMB_FID_IOCTL)
2950 lock_ReleaseMutex(&fidp->mx);
2951 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2953 /* Give back raw buffer */
2954 lock_ObtainMutex(&smb_RawBufLock);
2955 *((char **) rawBuf) = smb_RawBufs;
2957 smb_RawBufs = rawBuf;
2958 lock_ReleaseMutex(&smb_RawBufLock);
2961 smb_ReleaseFID(fidp);
2964 lock_ReleaseMutex(&fidp->mx);
2966 userp = smb_GetUserFromVCP(vcp, inp);
2968 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2974 cm_ReleaseUser(userp);
2977 smb_ReleaseFID(fidp);
2981 memset((char *)ncbp, 0, sizeof(NCB));
2983 ncbp->ncb_length = (unsigned short) finalCount;
2984 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2985 ncbp->ncb_lana_num = vcp->lana;
2986 ncbp->ncb_command = NCBSEND;
2987 ncbp->ncb_buffer = rawBuf;
2989 code = Netbios(ncbp);
2991 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2994 /* Give back raw buffer */
2995 lock_ObtainMutex(&smb_RawBufLock);
2996 *((char **) rawBuf) = smb_RawBufs;
2998 smb_RawBufs = rawBuf;
2999 lock_ReleaseMutex(&smb_RawBufLock);
3005 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3007 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3012 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3014 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3019 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3026 int VistaProtoIndex;
3027 int protoIndex; /* index we're using */
3032 char protocol_array[10][1024]; /* protocol signature of the client */
3033 int caps; /* capabilities */
3036 TIME_ZONE_INFORMATION tzi;
3038 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3041 namep = smb_GetSMBData(inp, &dbytes);
3044 coreProtoIndex = -1; /* not found */
3047 VistaProtoIndex = -1;
3048 while(namex < dbytes) {
3049 osi_Log1(smb_logp, "Protocol %s",
3050 osi_LogSaveString(smb_logp, namep+1));
3051 strcpy(protocol_array[tcounter], namep+1);
3053 /* namep points at the first protocol, or really, a 0x02
3054 * byte preceding the null-terminated ASCII name.
3056 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3057 coreProtoIndex = tcounter;
3059 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3060 v3ProtoIndex = tcounter;
3062 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3063 NTProtoIndex = tcounter;
3065 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3066 VistaProtoIndex = tcounter;
3069 /* compute size of protocol entry */
3070 entryLength = (int)strlen(namep+1);
3071 entryLength += 2; /* 0x02 bytes and null termination */
3073 /* advance over this protocol entry */
3074 namex += entryLength;
3075 namep += entryLength;
3076 tcounter++; /* which proto entry we're looking at */
3079 lock_ObtainMutex(&vcp->mx);
3081 if (VistaProtoIndex != -1) {
3082 protoIndex = VistaProtoIndex;
3083 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3086 if (NTProtoIndex != -1) {
3087 protoIndex = NTProtoIndex;
3088 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3090 else if (v3ProtoIndex != -1) {
3091 protoIndex = v3ProtoIndex;
3092 vcp->flags |= SMB_VCFLAG_USEV3;
3094 else if (coreProtoIndex != -1) {
3095 protoIndex = coreProtoIndex;
3096 vcp->flags |= SMB_VCFLAG_USECORE;
3098 else protoIndex = -1;
3099 lock_ReleaseMutex(&vcp->mx);
3101 if (protoIndex == -1)
3102 return CM_ERROR_INVAL;
3103 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3104 smb_SetSMBParm(outp, 0, protoIndex);
3105 if (smb_authType != SMB_AUTH_NONE) {
3106 smb_SetSMBParmByte(outp, 1,
3107 NEGOTIATE_SECURITY_USER_LEVEL |
3108 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3110 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3112 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3113 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3114 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3115 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3116 /* The session key is not a well documented field however most clients
3117 * will echo back the session key to the server. Currently we are using
3118 * the same value for all sessions. We should generate a random value
3119 * and store it into the vcp
3121 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3122 smb_SetSMBParm(outp, 8, 1);
3124 * Tried changing the capabilities to support for W2K - defect 117695
3125 * Maybe something else needs to be changed here?
3129 smb_SetSMBParmLong(outp, 9, 0x43fd);
3131 smb_SetSMBParmLong(outp, 9, 0x251);
3134 * 32-bit error codes *
3139 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3141 NTNEGOTIATE_CAPABILITY_DFS |
3143 #ifdef AFS_LARGEFILES
3144 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3146 NTNEGOTIATE_CAPABILITY_NTFIND |
3147 NTNEGOTIATE_CAPABILITY_RAWMODE |
3148 NTNEGOTIATE_CAPABILITY_NTSMB;
3150 if ( smb_authType == SMB_AUTH_EXTENDED )
3151 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3153 smb_SetSMBParmLong(outp, 9, caps);
3155 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3156 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3157 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3159 GetTimeZoneInformation(&tzi);
3160 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3162 if (smb_authType == SMB_AUTH_NTLM) {
3163 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3164 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3165 /* paste in encryption key */
3166 datap = smb_GetSMBData(outp, NULL);
3167 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3168 /* and the faux domain name */
3169 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3170 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3174 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3176 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3178 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3180 datap = smb_GetSMBData(outp, NULL);
3181 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3184 datap += sizeof(smb_ServerGUID);
3185 memcpy(datap, secBlob, secBlobLength);
3189 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3190 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3193 else if (v3ProtoIndex != -1) {
3194 smb_SetSMBParm(outp, 0, protoIndex);
3196 /* NOTE: Extended authentication cannot be negotiated with v3
3197 * therefore we fail over to NTLM
3199 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3200 smb_SetSMBParm(outp, 1,
3201 NEGOTIATE_SECURITY_USER_LEVEL |
3202 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3204 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3206 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3207 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3208 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3209 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3210 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3211 smb_SetSMBParm(outp, 7, 1);
3213 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3214 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3215 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3217 GetTimeZoneInformation(&tzi);
3218 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3220 /* NOTE: Extended authentication cannot be negotiated with v3
3221 * therefore we fail over to NTLM
3223 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3224 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3225 smb_SetSMBParm(outp, 12, 0); /* resvd */
3226 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3227 datap = smb_GetSMBData(outp, NULL);
3228 /* paste in a new encryption key */
3229 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3230 /* and the faux domain name */
3231 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3233 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3234 smb_SetSMBParm(outp, 12, 0); /* resvd */
3235 smb_SetSMBDataLength(outp, 0);
3238 else if (coreProtoIndex != -1) { /* not really supported anymore */
3239 smb_SetSMBParm(outp, 0, protoIndex);
3240 smb_SetSMBDataLength(outp, 0);
3245 void smb_CheckVCs(void)
3247 smb_vc_t * vcp, *nextp;
3248 smb_packet_t * outp = GetPacket();
3251 lock_ObtainWrite(&smb_rctLock);
3252 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3254 if (vcp->magic != SMB_VC_MAGIC)
3255 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3256 __FILE__, __LINE__);
3260 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3263 smb_HoldVCNoLock(vcp);
3265 smb_HoldVCNoLock(nextp);
3266 smb_FormatResponsePacket(vcp, NULL, outp);
3267 smbp = (smb_t *)outp;
3268 outp->inCom = smbp->com = 0x2b /* Echo */;
3276 smb_SetSMBParm(outp, 0, 0);
3277 smb_SetSMBDataLength(outp, 0);
3278 lock_ReleaseWrite(&smb_rctLock);
3280 smb_SendPacket(vcp, outp);
3282 lock_ObtainWrite(&smb_rctLock);
3283 smb_ReleaseVCNoLock(vcp);
3285 smb_ReleaseVCNoLock(nextp);
3287 lock_ReleaseWrite(&smb_rctLock);
3288 smb_FreePacket(outp);
3291 void smb_Daemon(void *parmp)
3293 afs_uint32 count = 0;
3294 smb_username_t **unpp;
3297 while(smbShutdownFlag == 0) {
3301 if (smbShutdownFlag == 1)
3304 if ((count % 72) == 0) { /* every five minutes */
3306 time_t old_localZero = smb_localZero;
3308 /* Initialize smb_localZero */
3309 myTime.tm_isdst = -1; /* compute whether on DST or not */
3310 myTime.tm_year = 70;
3316 smb_localZero = mktime(&myTime);
3318 #ifndef USE_NUMERIC_TIME_CONV
3319 smb_CalculateNowTZ();
3320 #endif /* USE_NUMERIC_TIME_CONV */
3321 #ifdef AFS_FREELANCE
3322 if ( smb_localZero != old_localZero )
3323 cm_noteLocalMountPointChange();
3329 /* GC smb_username_t objects that will no longer be used */
3331 lock_ObtainWrite(&smb_rctLock);
3332 for ( unpp=&usernamesp; *unpp; ) {
3334 smb_username_t *unp;
3336 lock_ObtainMutex(&(*unpp)->mx);
3337 if ( (*unpp)->refCount > 0 ||
3338 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3339 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3341 else if (!smb_LogoffTokenTransfer ||
3342 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3344 lock_ReleaseMutex(&(*unpp)->mx);
3352 lock_FinalizeMutex(&unp->mx);
3358 lock_ReleaseWrite(&smb_rctLock);
3359 cm_ReleaseUser(userp);
3360 lock_ObtainWrite(&smb_rctLock);
3363 unpp = &(*unpp)->nextp;
3366 lock_ReleaseWrite(&smb_rctLock);
3368 /* XXX GC dir search entries */
3372 void smb_WaitingLocksDaemon()
3374 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3375 smb_waitingLock_t *wl, *wlNext;
3378 smb_packet_t *inp, *outp;
3382 while (smbShutdownFlag == 0) {
3383 lock_ObtainWrite(&smb_globalLock);
3384 nwlRequest = smb_allWaitingLocks;
3385 if (nwlRequest == NULL) {
3386 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3391 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3398 lock_ObtainWrite(&smb_globalLock);
3400 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3402 wlRequest = nwlRequest;
3403 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3404 lock_ReleaseWrite(&smb_globalLock);
3408 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3409 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3412 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3414 /* wl->state is either _DONE or _WAITING. _ERROR
3415 would no longer be on the queue. */
3416 code = cm_RetryLock( wl->lockp,
3417 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3420 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3421 } else if (code != CM_ERROR_WOULDBLOCK) {
3422 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3427 if (code == CM_ERROR_WOULDBLOCK) {
3430 if (wlRequest->timeRemaining != 0xffffffff
3431 && (wlRequest->timeRemaining -= 1000) < 0)
3443 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3446 scp = wlRequest->scp;
3447 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3451 lock_ObtainMutex(&scp->mx);
3453 for (wl = wlRequest->locks; wl; wl = wlNext) {
3454 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3456 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3457 wl->LLength, wl->key, NULL, &req);
3459 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3464 lock_ReleaseMutex(&scp->mx);
3468 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3471 for (wl = wlRequest->locks; wl; wl = wlNext) {
3472 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3473 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3478 vcp = wlRequest->vcp;
3479 inp = wlRequest->inp;
3480 outp = wlRequest->outp;
3482 ncbp->ncb_length = inp->ncb_length;
3483 inp->spacep = cm_GetSpace();
3485 /* Remove waitingLock from list */
3486 lock_ObtainWrite(&smb_globalLock);
3487 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3489 lock_ReleaseWrite(&smb_globalLock);
3491 /* Resume packet processing */
3493 smb_SetSMBDataLength(outp, 0);
3494 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3495 outp->resumeCode = code;
3497 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3500 cm_FreeSpace(inp->spacep);
3501 smb_FreePacket(inp);
3502 smb_FreePacket(outp);
3504 cm_ReleaseSCache(wlRequest->scp);
3507 } while (nwlRequest && smbShutdownFlag == 0);
3512 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3514 osi_Log0(smb_logp, "SMB receive get disk attributes");
3516 smb_SetSMBParm(outp, 0, 32000);
3517 smb_SetSMBParm(outp, 1, 64);
3518 smb_SetSMBParm(outp, 2, 1024);
3519 smb_SetSMBParm(outp, 3, 30000);
3520 smb_SetSMBParm(outp, 4, 0);
3521 smb_SetSMBDataLength(outp, 0);
3525 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3529 unsigned short newTid;
3530 char shareName[AFSPATHMAX];
3538 osi_Log0(smb_logp, "SMB receive tree connect");
3540 /* parse input parameters */
3541 tp = smb_GetSMBData(inp, NULL);
3542 pathp = smb_ParseASCIIBlock(tp, &tp);
3543 if (smb_StoreAnsiFilenames)
3544 OemToChar(pathp,pathp);
3545 passwordp = smb_ParseASCIIBlock(tp, &tp);
3546 tp = strrchr(pathp, '\\');
3548 return CM_ERROR_BADSMB;
3549 strcpy(shareName, tp+1);
3551 lock_ObtainMutex(&vcp->mx);
3552 newTid = vcp->tidCounter++;
3553 lock_ReleaseMutex(&vcp->mx);
3555 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3556 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3557 userp = smb_GetUserFromUID(uidp);
3558 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3560 smb_ReleaseUID(uidp);
3562 smb_ReleaseTID(tidp);
3563 return CM_ERROR_BADSHARENAME;
3565 lock_ObtainMutex(&tidp->mx);
3566 tidp->userp = userp;
3567 tidp->pathname = sharePath;
3568 lock_ReleaseMutex(&tidp->mx);
3569 smb_ReleaseTID(tidp);
3571 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3572 smb_SetSMBParm(rsp, 1, newTid);
3573 smb_SetSMBDataLength(rsp, 0);
3575 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3579 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3583 if (*inp++ != 0x1) return NULL;
3584 tlen = inp[0] + (inp[1]<<8);
3585 inp += 2; /* skip length field */
3588 *chainpp = inp + tlen;
3591 if (lengthp) *lengthp = tlen;
3596 /* set maskp to the mask part of the incoming path.
3597 * Mask is 11 bytes long (8.3 with the dot elided).
3598 * Returns true if succeeds with a valid name, otherwise it does
3599 * its best, but returns false.
3601 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3609 /* starts off valid */
3612 /* mask starts out all blanks */
3613 memset(maskp, ' ', 11);
3615 /* find last backslash, or use whole thing if there is none */
3616 tp = strrchr(pathp, '\\');
3617 if (!tp) tp = pathp;
3618 else tp++; /* skip slash */
3622 /* names starting with a dot are illegal */
3623 if (*tp == '.') valid8Dot3 = 0;
3627 if (tc == 0) return valid8Dot3;
3628 if (tc == '.' || tc == '"') break;
3629 if (i < 8) *up++ = tc;
3630 else valid8Dot3 = 0;
3633 /* if we get here, tp point after the dot */
3634 up = maskp+8; /* ext goes here */
3641 if (tc == '.' || tc == '"')
3644 /* copy extension if not too long */
3654 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3664 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3666 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3670 /* otherwise, we have a valid 8.3 name; see if we have a match,
3671 * treating '?' as a wildcard in maskp (but not in the file name).
3673 tp1 = umask; /* real name, in mask format */
3674 tp2 = maskp; /* mask, in mask format */
3675 for(i=0; i<11; i++) {
3676 tc1 = *tp1++; /* char from real name */
3677 tc2 = *tp2++; /* char from mask */
3678 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3679 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3682 if (tc2 == '?' && tc1 != ' ')
3689 /* we got a match */
3693 char *smb_FindMask(char *pathp)
3697 tp = strrchr(pathp, '\\'); /* find last slash */
3700 return tp+1; /* skip the slash */
3702 return pathp; /* no slash, return the entire path */
3705 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3707 unsigned char *pathp;
3709 unsigned char mask[11];
3710 unsigned char *statBlockp;
3711 unsigned char initStatBlock[21];
3714 osi_Log0(smb_logp, "SMB receive search volume");
3716 /* pull pathname and stat block out of request */
3717 tp = smb_GetSMBData(inp, NULL);
3718 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3719 osi_assertx(pathp != NULL, "null path");
3720 if (smb_StoreAnsiFilenames)
3721 OemToChar(pathp,pathp);
3722 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3723 osi_assertx(statBlockp != NULL, "null statBlock");
3725 statBlockp = initStatBlock;
3729 /* for returning to caller */
3730 smb_Get8Dot3MaskFromPath(mask, pathp);
3732 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3733 tp = smb_GetSMBData(outp, NULL);
3735 *tp++ = 43; /* bytes in a dir entry */
3736 *tp++ = 0; /* high byte in counter */
3738 /* now marshall the dir entry, starting with the search status */
3739 *tp++ = statBlockp[0]; /* Reserved */
3740 memcpy(tp, mask, 11); tp += 11; /* FileName */
3742 /* now pass back server use info, with 1st byte non-zero */
3744 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3746 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3748 *tp++ = 0x8; /* attribute: volume */
3758 /* 4 byte file size */
3764 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3765 memset(tp, ' ', 13);
3768 /* set the length of the data part of the packet to 43 + 3, for the dir
3769 * entry plus the 5 and the length fields.
3771 smb_SetSMBDataLength(outp, 46);
3775 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3776 cm_user_t *userp, cm_req_t *reqp)
3784 smb_dirListPatch_t *patchp;
3785 smb_dirListPatch_t *npatchp;
3787 for (patchp = *dirPatchespp; patchp; patchp =
3788 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3790 dptr = patchp->dptr;
3792 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3794 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3795 *dptr++ = SMB_ATTR_HIDDEN;
3798 lock_ObtainMutex(&scp->mx);
3799 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3800 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3802 lock_ReleaseMutex(&scp->mx);
3803 cm_ReleaseSCache(scp);
3804 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3805 *dptr++ = SMB_ATTR_HIDDEN;
3809 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3811 attr = smb_Attributes(scp);
3812 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3813 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3814 attr |= SMB_ATTR_HIDDEN;
3818 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3821 shortTemp = (unsigned short) (dosTime & 0xffff);
3822 *((u_short *)dptr) = shortTemp;
3825 /* and copy out date */
3826 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3827 *((u_short *)dptr) = shortTemp;
3830 /* copy out file length */
3831 *((u_long *)dptr) = scp->length.LowPart;
3833 lock_ReleaseMutex(&scp->mx);
3834 cm_ReleaseSCache(scp);
3837 /* now free the patches */
3838 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3839 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3843 /* and mark the list as empty */
3844 *dirPatchespp = NULL;
3849 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3858 smb_dirListPatch_t *dirListPatchesp;
3859 smb_dirListPatch_t *curPatchp;
3863 osi_hyper_t dirLength;
3864 osi_hyper_t bufferOffset;
3865 osi_hyper_t curOffset;
3867 unsigned char *inCookiep;
3868 smb_dirSearch_t *dsp;
3872 unsigned long clientCookie;
3873 cm_pageHeader_t *pageHeaderp;
3874 cm_user_t *userp = NULL;
3881 long nextEntryCookie;
3882 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3883 char resByte; /* reserved byte from the cookie */
3884 char *op; /* output data ptr */
3885 char *origOp; /* original value of op */
3886 cm_space_t *spacep; /* for pathname buffer */
3897 maxCount = smb_GetSMBParm(inp, 0);
3899 dirListPatchesp = NULL;
3901 caseFold = CM_FLAG_CASEFOLD;
3903 tp = smb_GetSMBData(inp, NULL);
3904 pathp = smb_ParseASCIIBlock(tp, &tp);
3905 if (smb_StoreAnsiFilenames)
3906 OemToChar(pathp,pathp);
3907 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3909 /* bail out if request looks bad */
3910 if (!tp || !pathp) {
3911 return CM_ERROR_BADSMB;
3914 /* We can handle long names */
3915 if (vcp->flags & SMB_VCFLAG_USENT)
3916 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3918 /* make sure we got a whole search status */
3919 if (dataLength < 21) {
3920 nextCookie = 0; /* start at the beginning of the dir */
3923 attribute = smb_GetSMBParm(inp, 1);
3925 /* handle volume info in another function */
3926 if (attribute & 0x8)
3927 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3929 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3930 maxCount, osi_LogSaveString(smb_logp, pathp));
3932 if (*pathp == 0) { /* null pathp, treat as root dir */
3933 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3934 return CM_ERROR_NOFILES;
3938 dsp = smb_NewDirSearch(0);
3939 dsp->attribute = attribute;
3940 smb_Get8Dot3MaskFromPath(mask, pathp);
3941 memcpy(dsp->mask, mask, 11);
3943 /* track if this is likely to match a lot of entries */
3944 if (smb_IsStarMask(mask))
3949 /* pull the next cookie value out of the search status block */
3950 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3951 + (inCookiep[16]<<24);
3952 dsp = smb_FindDirSearch(inCookiep[12]);
3954 /* can't find dir search status; fatal error */
3955 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3956 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3957 return CM_ERROR_BADFD;
3959 attribute = dsp->attribute;
3960 resByte = inCookiep[0];
3962 /* copy out client cookie, in host byte order. Don't bother
3963 * interpreting it, since we're just passing it through, anyway.
3965 memcpy(&clientCookie, &inCookiep[17], 4);
3967 memcpy(mask, dsp->mask, 11);
3969 /* assume we're doing a star match if it has continued for more
3975 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3976 nextCookie, dsp->cookie, attribute);
3978 userp = smb_GetUserFromVCP(vcp, inp);
3980 /* try to get the vnode for the path name next */
3981 lock_ObtainMutex(&dsp->mx);
3984 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
3988 spacep = inp->spacep;
3989 smb_StripLastComponent(spacep->data, NULL, pathp);
3990 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3992 lock_ReleaseMutex(&dsp->mx);
3993 cm_ReleaseUser(userp);
3994 smb_DeleteDirSearch(dsp);
3995 smb_ReleaseDirSearch(dsp);
3996 return CM_ERROR_NOFILES;
3998 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3999 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4002 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4003 cm_ReleaseSCache(scp);
4004 lock_ReleaseMutex(&dsp->mx);
4005 cm_ReleaseUser(userp);
4006 smb_DeleteDirSearch(dsp);
4007 smb_ReleaseDirSearch(dsp);
4008 if ( WANTS_DFS_PATHNAMES(inp) )
4009 return CM_ERROR_PATH_NOT_COVERED;
4011 return CM_ERROR_BADSHARENAME;
4013 #endif /* DFS_SUPPORT */
4016 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4017 /* we need one hold for the entry we just stored into,
4018 * and one for our own processing. When we're done with this
4019 * function, we'll drop the one for our own processing.
4020 * We held it once from the namei call, and so we do another hold
4024 lock_ObtainMutex(&scp->mx);
4025 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4026 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4027 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4028 dsp->flags |= SMB_DIRSEARCH_BULKST;
4029 dsp->scp->bulkStatProgress = hzero;
4031 lock_ReleaseMutex(&scp->mx);
4034 lock_ReleaseMutex(&dsp->mx);
4036 cm_ReleaseUser(userp);
4037 smb_DeleteDirSearch(dsp);
4038 smb_ReleaseDirSearch(dsp);
4042 /* reserves space for parameter; we'll adjust it again later to the
4043 * real count of the # of entries we returned once we've actually
4044 * assembled the directory listing.
4046 smb_SetSMBParm(outp, 0, 0);
4048 /* get the directory size */
4049 lock_ObtainMutex(&scp->mx);
4050 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4051 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4053 lock_ReleaseMutex(&scp->mx);
4054 cm_ReleaseSCache(scp);
4055 cm_ReleaseUser(userp);
4056 smb_DeleteDirSearch(dsp);
4057 smb_ReleaseDirSearch(dsp);
4061 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4063 dirLength = scp->length;
4065 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4066 curOffset.HighPart = 0;
4067 curOffset.LowPart = nextCookie;
4068 origOp = op = smb_GetSMBData(outp, NULL);
4069 /* and write out the basic header */
4070 *op++ = 5; /* variable block */
4071 op += 2; /* skip vbl block length; we'll fill it in later */
4075 /* make sure that curOffset.LowPart doesn't point to the first
4076 * 32 bytes in the 2nd through last dir page, and that it doesn't
4077 * point at the first 13 32-byte chunks in the first dir page,
4078 * since those are dir and page headers, and don't contain useful
4081 temp = curOffset.LowPart & (2048-1);
4082 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4083 /* we're in the first page */
4084 if (temp < 13*32) temp = 13*32;
4087 /* we're in a later dir page */
4088 if (temp < 32) temp = 32;
4091 /* make sure the low order 5 bits are zero */
4094 /* now put temp bits back ito curOffset.LowPart */
4095 curOffset.LowPart &= ~(2048-1);
4096 curOffset.LowPart |= temp;
4098 /* check if we've returned all the names that will fit in the
4101 if (returnedNames >= maxCount) {
4102 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4103 returnedNames, maxCount);
4107 /* check if we've passed the dir's EOF */
4108 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4110 /* see if we can use the bufferp we have now; compute in which page
4111 * the current offset would be, and check whether that's the offset
4112 * of the buffer we have. If not, get the buffer.
4114 thyper.HighPart = curOffset.HighPart;
4115 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4116 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4119 buf_Release(bufferp);
4122 lock_ReleaseMutex(&scp->mx);
4123 lock_ObtainRead(&scp->bufCreateLock);
4124 code = buf_Get(scp, &thyper, &bufferp);
4125 lock_ReleaseRead(&scp->bufCreateLock);
4126 lock_ObtainMutex(&dsp->mx);
4128 /* now, if we're doing a star match, do bulk fetching of all of
4129 * the status info for files in the dir.
4132 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4133 lock_ObtainMutex(&scp->mx);
4134 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4135 LargeIntegerGreaterThanOrEqualTo(thyper,
4136 scp->bulkStatProgress)) {
4137 /* Don't bulk stat if risking timeout */
4138 int now = GetTickCount();
4139 if (now - req.startTime > RDRtimeout * 1000) {
4140 scp->bulkStatProgress = thyper;
4141 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4142 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4143 dsp->scp->bulkStatProgress = hzero;
4145 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4148 lock_ObtainMutex(&scp->mx);
4150 lock_ReleaseMutex(&dsp->mx);
4152 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4156 bufferOffset = thyper;
4158 /* now get the data in the cache */
4160 code = cm_SyncOp(scp, bufferp, userp, &req,
4162 CM_SCACHESYNC_NEEDCALLBACK |
4163 CM_SCACHESYNC_READ);
4165 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4169 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4171 if (cm_HaveBuffer(scp, bufferp, 0)) {
4172 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4176 /* otherwise, load the buffer and try again */
4177 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4179 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4180 scp, bufferp, code);
4185 buf_Release(bufferp);
4189 } /* if (wrong buffer) ... */
4191 /* now we have the buffer containing the entry we're interested in; copy
4192 * it out if it represents a non-deleted entry.
4194 entryInDir = curOffset.LowPart & (2048-1);
4195 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4197 /* page header will help tell us which entries are free. Page header
4198 * can change more often than once per buffer, since AFS 3 dir page size
4199 * may be less than (but not more than a buffer package buffer.
4201 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4202 temp &= ~(2048 - 1); /* turn off intra-page bits */
4203 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4205 /* now determine which entry we're looking at in the page. If it is
4206 * free (there's a free bitmap at the start of the dir), we should
4207 * skip these 32 bytes.
4209 slotInPage = (entryInDir & 0x7e0) >> 5;
4210 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4211 /* this entry is free */
4212 numDirChunks = 1; /* only skip this guy */
4216 tp = bufferp->datap + entryInBuffer;
4217 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4219 /* while we're here, compute the next entry's location, too,
4220 * since we'll need it when writing out the cookie into the dir
4223 * XXXX Probably should do more sanity checking.
4225 numDirChunks = cm_NameEntries(dep->name, NULL);
4227 /* compute the offset of the cookie representing the next entry */
4228 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4230 /* Compute 8.3 name if necessary */
4231 actualName = dep->name;
4232 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4233 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4234 actualName = shortName;
4237 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4238 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4239 osi_LogSaveString(smb_logp, actualName));
4241 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4242 /* this is one of the entries to use: it is not deleted
4243 * and it matches the star pattern we're looking for.
4246 /* Eliminate entries that don't match requested
4249 /* no hidden files */
4250 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4251 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4255 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4257 /* We have already done the cm_TryBulkStat above */
4258 fid.cell = scp->fid.cell;
4259 fid.volume = scp->fid.volume;
4260 fid.vnode = ntohl(dep->fid.vnode);
4261 fid.unique = ntohl(dep->fid.unique);
4262 fileType = cm_FindFileType(&fid);
4263 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4264 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4266 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4267 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4268 fileType == CM_SCACHETYPE_DFSLINK ||
4269 fileType == CM_SCACHETYPE_INVALID)
4270 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4275 memcpy(op, mask, 11); op += 11;
4276 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4277 *op++ = (char)(nextEntryCookie & 0xff);
4278 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4279 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4280 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4281 memcpy(op, &clientCookie, 4); op += 4;
4283 /* now we emit the attribute. This is sort of tricky,
4284 * since we need to really stat the file to find out
4285 * what type of entry we've got. Right now, we're
4286 * copying out data from a buffer, while holding the
4287 * scp locked, so it isn't really convenient to stat
4288 * something now. We'll put in a place holder now,
4289 * and make a second pass before returning this to get
4290 * the real attributes. So, we just skip the data for
4291 * now, and adjust it later. We allocate a patch
4292 * record to make it easy to find this point later.
4293 * The replay will happen at a time when it is safe to
4294 * unlock the directory.
4296 curPatchp = malloc(sizeof(*curPatchp));
4297 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4298 curPatchp->dptr = op;
4299 curPatchp->fid.cell = scp->fid.cell;
4300 curPatchp->fid.volume = scp->fid.volume;
4301 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4302 curPatchp->fid.unique = ntohl(dep->fid.unique);
4304 /* do hidden attribute here since name won't be around when applying
4308 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4309 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4311 curPatchp->flags = 0;
4313 op += 9; /* skip attr, time, date and size */
4315 /* zero out name area. The spec says to pad with
4316 * spaces, but Samba doesn't, and neither do we.
4320 /* finally, we get to copy out the name; we know that
4321 * it fits in 8.3 or the pattern wouldn't match, but it
4322 * never hurts to be sure.
4324 strncpy(op, actualName, 13);
4325 if (smb_StoreAnsiFilenames)
4328 /* Uppercase if requested by client */
4329 if (!KNOWS_LONG_NAMES(inp))
4334 /* now, adjust the # of entries copied */
4336 } /* if we're including this name */
4339 /* and adjust curOffset to be where the new cookie is */
4340 thyper.HighPart = 0;
4341 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4342 curOffset = LargeIntegerAdd(thyper, curOffset);
4343 } /* while copying data for dir listing */
4345 /* release the mutex */
4346 lock_ReleaseMutex(&scp->mx);
4348 buf_Release(bufferp);
4352 /* apply and free last set of patches; if not doing a star match, this
4353 * will be empty, but better safe (and freeing everything) than sorry.
4355 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4357 /* special return code for unsuccessful search */
4358 if (code == 0 && dataLength < 21 && returnedNames == 0)
4359 code = CM_ERROR_NOFILES;
4361 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4362 returnedNames, code);
4365 smb_DeleteDirSearch(dsp);
4366 smb_ReleaseDirSearch(dsp);
4367 cm_ReleaseSCache(scp);
4368 cm_ReleaseUser(userp);
4372 /* finalize the output buffer */
4373 smb_SetSMBParm(outp, 0, returnedNames);
4374 temp = (long) (op - origOp);
4375 smb_SetSMBDataLength(outp, temp);
4377 /* the data area is a variable block, which has a 5 (already there)
4378 * followed by the length of the # of data bytes. We now know this to
4379 * be "temp," although that includes the 3 bytes of vbl block header.
4380 * Deduct for them and fill in the length field.
4382 temp -= 3; /* deduct vbl block info */
4383 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4384 origOp[1] = (char)(temp & 0xff);
4385 origOp[2] = (char)((temp>>8) & 0xff);
4386 if (returnedNames == 0)
4387 smb_DeleteDirSearch(dsp);
4388 smb_ReleaseDirSearch(dsp);
4389 cm_ReleaseSCache(scp);
4390 cm_ReleaseUser(userp);
4394 /* verify that this is a valid path to a directory. I don't know why they
4395 * don't use the get file attributes call.
4397 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4401 cm_scache_t *rootScp;
4402 cm_scache_t *newScp;
4411 pathp = smb_GetSMBData(inp, NULL);
4412 pathp = smb_ParseASCIIBlock(pathp, NULL);
4414 return CM_ERROR_BADFD;
4415 if (smb_StoreAnsiFilenames)
4416 OemToChar(pathp,pathp);
4417 osi_Log1(smb_logp, "SMB receive check path %s",
4418 osi_LogSaveString(smb_logp, pathp));
4420 rootScp = cm_data.rootSCachep;
4422 userp = smb_GetUserFromVCP(vcp, inp);
4424 caseFold = CM_FLAG_CASEFOLD;
4426 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4428 cm_ReleaseUser(userp);
4429 return CM_ERROR_NOSUCHPATH;
4431 code = cm_NameI(rootScp, pathp,
4432 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4433 userp, tidPathp, &req, &newScp);
4436 cm_ReleaseUser(userp);
4441 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4442 cm_ReleaseSCache(newScp);
4443 cm_ReleaseUser(userp);
4444 if ( WANTS_DFS_PATHNAMES(inp) )
4445 return CM_ERROR_PATH_NOT_COVERED;
4447 return CM_ERROR_BADSHARENAME;
4449 #endif /* DFS_SUPPORT */
4451 /* now lock the vnode with a callback; returns with newScp locked */
4452 lock_ObtainMutex(&newScp->mx);
4453 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4454 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4456 if (code != CM_ERROR_NOACCESS) {
4457 lock_ReleaseMutex(&newScp->mx);
4458 cm_ReleaseSCache(newScp);
4459 cm_ReleaseUser(userp);
4463 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4466 attrs = smb_Attributes(newScp);
4468 if (!(attrs & SMB_ATTR_DIRECTORY))
4469 code = CM_ERROR_NOTDIR;
4471 lock_ReleaseMutex(&newScp->mx);
4473 cm_ReleaseSCache(newScp);
4474 cm_ReleaseUser(userp);
4478 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4482 cm_scache_t *rootScp;
4483 unsigned short attribute;
4485 cm_scache_t *newScp;
4494 /* decode basic attributes we're passed */
4495 attribute = smb_GetSMBParm(inp, 0);
4496 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4498 pathp = smb_GetSMBData(inp, NULL);
4499 pathp = smb_ParseASCIIBlock(pathp, NULL);
4501 return CM_ERROR_BADSMB;
4502 if (smb_StoreAnsiFilenames)
4503 OemToChar(pathp,pathp);
4505 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4506 dosTime, attribute);
4508 rootScp = cm_data.rootSCachep;
4510 userp = smb_GetUserFromVCP(vcp, inp);
4512 caseFold = CM_FLAG_CASEFOLD;
4514 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4516 cm_ReleaseUser(userp);
4517 return CM_ERROR_NOSUCHFILE;
4519 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4520 tidPathp, &req, &newScp);
4523 cm_ReleaseUser(userp);
4528 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4529 cm_ReleaseSCache(newScp);
4530 cm_ReleaseUser(userp);
4531 if ( WANTS_DFS_PATHNAMES(inp) )
4532 return CM_ERROR_PATH_NOT_COVERED;
4534 return CM_ERROR_BADSHARENAME;
4536 #endif /* DFS_SUPPORT */
4538 /* now lock the vnode with a callback; returns with newScp locked; we
4539 * need the current status to determine what the new status is, in some
4542 lock_ObtainMutex(&newScp->mx);
4543 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4544 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4546 lock_ReleaseMutex(&newScp->mx);
4547 cm_ReleaseSCache(newScp);
4548 cm_ReleaseUser(userp);
4552 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4554 /* Check for RO volume */
4555 if (newScp->flags & CM_SCACHEFLAG_RO) {
4556 lock_ReleaseMutex(&newScp->mx);
4557 cm_ReleaseSCache(newScp);
4558 cm_ReleaseUser(userp);
4559 return CM_ERROR_READONLY;
4562 /* prepare for setattr call */
4565 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4566 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4568 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4569 /* we're told to make a writable file read-only */
4570 attr.unixModeBits = newScp->unixModeBits & ~0222;
4571 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4573 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4574 /* we're told to make a read-only file writable */
4575 attr.unixModeBits = newScp->unixModeBits | 0222;
4576 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4578 lock_ReleaseMutex(&newScp->mx);
4580 /* now call setattr */
4582 code = cm_SetAttr(newScp, &attr, userp, &req);
4586 cm_ReleaseSCache(newScp);
4587 cm_ReleaseUser(userp);
4592 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4596 cm_scache_t *rootScp;
4597 cm_scache_t *newScp, *dscp;
4609 pathp = smb_GetSMBData(inp, NULL);
4610 pathp = smb_ParseASCIIBlock(pathp, NULL);
4612 return CM_ERROR_BADSMB;
4614 if (*pathp == 0) /* null path */
4617 if (smb_StoreAnsiFilenames)
4618 OemToChar(pathp,pathp);
4620 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4621 osi_LogSaveString(smb_logp, pathp));
4623 rootScp = cm_data.rootSCachep;
4625 userp = smb_GetUserFromVCP(vcp, inp);
4627 /* we shouldn't need this for V3 requests, but we seem to */
4628 caseFold = CM_FLAG_CASEFOLD;
4630 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4632 cm_ReleaseUser(userp);
4633 return CM_ERROR_NOSUCHFILE;
4637 * XXX Strange hack XXX
4639 * As of Patch 5 (16 July 97), we are having the following problem:
4640 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4641 * requests to look up "desktop.ini" in all the subdirectories.
4642 * This can cause zillions of timeouts looking up non-existent cells
4643 * and volumes, especially in the top-level directory.
4645 * We have not found any way to avoid this or work around it except
4646 * to explicitly ignore the requests for mount points that haven't
4647 * yet been evaluated and for directories that haven't yet been
4650 * We should modify this hack to provide a fake desktop.ini file
4651 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4653 spacep = inp->spacep;
4654 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4655 #ifndef SPECIAL_FOLDERS
4656 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4657 code = cm_NameI(rootScp, spacep->data,
4658 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4659 userp, tidPathp, &req, &dscp);
4662 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4663 if ( WANTS_DFS_PATHNAMES(inp) )
4664 return CM_ERROR_PATH_NOT_COVERED;
4666 return CM_ERROR_BADSHARENAME;
4668 #endif /* DFS_SUPPORT */
4669 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4670 code = CM_ERROR_NOSUCHFILE;
4671 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4672 cm_buf_t *bp = buf_Find(dscp, &hzero);
4677 code = CM_ERROR_NOSUCHFILE;
4679 cm_ReleaseSCache(dscp);
4681 cm_ReleaseUser(userp);
4686 #endif /* SPECIAL_FOLDERS */
4688 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4689 tidPathp, &req, &newScp);
4691 cm_ReleaseUser(userp);
4696 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4697 cm_ReleaseSCache(newScp);
4698 cm_ReleaseUser(userp);
4699 if ( WANTS_DFS_PATHNAMES(inp) )
4700 return CM_ERROR_PATH_NOT_COVERED;
4702 return CM_ERROR_BADSHARENAME;
4704 #endif /* DFS_SUPPORT */
4706 /* now lock the vnode with a callback; returns with newScp locked */
4707 lock_ObtainMutex(&newScp->mx);
4708 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4709 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4711 lock_ReleaseMutex(&newScp->mx);
4712 cm_ReleaseSCache(newScp);
4713 cm_ReleaseUser(userp);
4717 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4720 /* use smb_Attributes instead. Also the fact that a file is
4721 * in a readonly volume doesn't mean it shojuld be marked as RO
4723 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4724 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4725 newScp->fileType == CM_SCACHETYPE_INVALID)
4726 attrs = SMB_ATTR_DIRECTORY;
4729 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4730 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4732 attrs = smb_Attributes(newScp);
4735 smb_SetSMBParm(outp, 0, attrs);
4737 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4738 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4739 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4740 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4741 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4742 smb_SetSMBParm(outp, 5, 0);
4743 smb_SetSMBParm(outp, 6, 0);
4744 smb_SetSMBParm(outp, 7, 0);
4745 smb_SetSMBParm(outp, 8, 0);
4746 smb_SetSMBParm(outp, 9, 0);
4747 smb_SetSMBDataLength(outp, 0);
4748 lock_ReleaseMutex(&newScp->mx);
4750 cm_ReleaseSCache(newScp);
4751 cm_ReleaseUser(userp);
4756 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4760 osi_Log0(smb_logp, "SMB receive tree disconnect");
4762 /* find the tree and free it */
4763 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4765 lock_ObtainWrite(&smb_rctLock);
4767 lock_ReleaseWrite(&smb_rctLock);
4768 smb_ReleaseTID(tidp);
4774 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4792 pathp = smb_GetSMBData(inp, NULL);
4793 pathp = smb_ParseASCIIBlock(pathp, NULL);
4794 if (smb_StoreAnsiFilenames)
4795 OemToChar(pathp,pathp);
4797 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4799 #ifdef DEBUG_VERBOSE
4803 hexpath = osi_HexifyString( pathp );
4804 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4809 share = smb_GetSMBParm(inp, 0);
4810 attribute = smb_GetSMBParm(inp, 1);
4812 spacep = inp->spacep;
4813 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4814 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4815 /* special case magic file name for receiving IOCTL requests
4816 * (since IOCTL calls themselves aren't getting through).
4818 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4819 smb_SetupIoctlFid(fidp, spacep);
4820 smb_SetSMBParm(outp, 0, fidp->fid);
4821 smb_SetSMBParm(outp, 1, 0); /* attrs */
4822 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4823 smb_SetSMBParm(outp, 3, 0);
4824 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4825 smb_SetSMBParm(outp, 5, 0x7fff);
4826 /* pass the open mode back */
4827 smb_SetSMBParm(outp, 6, (share & 0xf));
4828 smb_SetSMBDataLength(outp, 0);
4829 smb_ReleaseFID(fidp);
4833 userp = smb_GetUserFromVCP(vcp, inp);
4835 caseFold = CM_FLAG_CASEFOLD;
4837 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4839 cm_ReleaseUser(userp);
4840 return CM_ERROR_NOSUCHPATH;
4842 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4843 tidPathp, &req, &scp);
4846 cm_ReleaseUser(userp);
4851 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4852 cm_ReleaseSCache(scp);
4853 cm_ReleaseUser(userp);
4854 if ( WANTS_DFS_PATHNAMES(inp) )
4855 return CM_ERROR_PATH_NOT_COVERED;
4857 return CM_ERROR_BADSHARENAME;
4859 #endif /* DFS_SUPPORT */
4861 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4863 cm_ReleaseSCache(scp);
4864 cm_ReleaseUser(userp);
4868 /* don't need callback to check file type, since file types never
4869 * change, and namei and cm_Lookup all stat the object at least once on
4870 * a successful return.
4872 if (scp->fileType != CM_SCACHETYPE_FILE) {
4873 cm_ReleaseSCache(scp);
4874 cm_ReleaseUser(userp);
4875 return CM_ERROR_ISDIR;
4878 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4879 osi_assertx(fidp, "null smb_fid_t");
4881 /* save a pointer to the vnode */
4883 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
4884 lock_ObtainMutex(&scp->mx);
4885 scp->flags |= CM_SCACHEFLAG_SMB_FID;
4886 lock_ReleaseMutex(&scp->mx);
4890 fidp->userp = userp;
4892 lock_ObtainMutex(&fidp->mx);
4893 if ((share & 0xf) == 0)
4894 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
4895 else if ((share & 0xf) == 1)
4896 fidp->flags |= SMB_FID_OPENWRITE;
4898 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
4899 lock_ReleaseMutex(&fidp->mx);
4901 lock_ObtainMutex(&scp->mx);
4902 smb_SetSMBParm(outp, 0, fidp->fid);
4903 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4904 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4905 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4906 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4907 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4908 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4909 /* pass the open mode back; XXXX add access checks */
4910 smb_SetSMBParm(outp, 6, (share & 0xf));
4911 smb_SetSMBDataLength(outp, 0);
4912 lock_ReleaseMutex(&scp->mx);
4915 cm_Open(scp, 0, userp);
4917 /* send and free packet */
4918 smb_ReleaseFID(fidp);
4919 cm_ReleaseUser(userp);
4920 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4924 typedef struct smb_unlinkRock {
4929 char *maskp; /* pointer to the star pattern */
4932 cm_dirEntryList_t * matches;
4935 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4938 smb_unlinkRock_t *rockp;
4946 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4947 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4948 caseFold |= CM_FLAG_8DOT3;
4950 matchName = dep->name;
4951 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4953 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4954 !cm_Is8Dot3(dep->name)) {
4955 cm_Gen8Dot3Name(dep, shortName, NULL);
4956 matchName = shortName;
4957 /* 8.3 matches are always case insensitive */
4958 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4961 osi_Log1(smb_logp, "Found match %s",
4962 osi_LogSaveString(smb_logp, matchName));
4964 cm_DirEntryListAdd(dep->name, &rockp->matches);
4968 /* If we made a case sensitive exact match, we might as well quit now. */
4969 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4970 code = CM_ERROR_STOPNOW;
4979 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4988 smb_unlinkRock_t rock;
4997 attribute = smb_GetSMBParm(inp, 0);
4999 tp = smb_GetSMBData(inp, NULL);
5000 pathp = smb_ParseASCIIBlock(tp, &tp);
5001 if (smb_StoreAnsiFilenames)
5002 OemToChar(pathp,pathp);
5004 osi_Log1(smb_logp, "SMB receive unlink %s",
5005 osi_LogSaveString(smb_logp, pathp));
5007 spacep = inp->spacep;
5008 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5010 userp = smb_GetUserFromVCP(vcp, inp);
5012 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5014 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5016 cm_ReleaseUser(userp);
5017 return CM_ERROR_NOSUCHPATH;
5019 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5022 cm_ReleaseUser(userp);
5027 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5028 cm_ReleaseSCache(dscp);
5029 cm_ReleaseUser(userp);
5030 if ( WANTS_DFS_PATHNAMES(inp) )
5031 return CM_ERROR_PATH_NOT_COVERED;
5033 return CM_ERROR_BADSHARENAME;
5035 #endif /* DFS_SUPPORT */
5037 /* otherwise, scp points to the parent directory. */
5044 rock.maskp = smb_FindMask(pathp);
5045 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5048 thyper.HighPart = 0;
5053 rock.matches = NULL;
5055 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5056 * match. If that fails, we do a case insensitve match.
5058 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5059 !smb_IsStarMask(rock.maskp)) {
5060 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5063 thyper.HighPart = 0;
5064 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5069 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5071 if (code == CM_ERROR_STOPNOW)
5074 if (code == 0 && rock.matches) {
5075 cm_dirEntryList_t * entry;
5077 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5079 osi_Log1(smb_logp, "Unlinking %s",
5080 osi_LogSaveString(smb_logp, entry->name));
5081 code = cm_Unlink(dscp, entry->name, userp, &req);
5083 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5084 smb_NotifyChange(FILE_ACTION_REMOVED,
5085 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5086 dscp, entry->name, NULL, TRUE);
5090 cm_DirEntryListFree(&rock.matches);
5092 cm_ReleaseUser(userp);
5094 cm_ReleaseSCache(dscp);
5096 if (code == 0 && !rock.any)
5097 code = CM_ERROR_NOSUCHFILE;
5101 typedef struct smb_renameRock {
5102 cm_scache_t *odscp; /* old dir */
5103 cm_scache_t *ndscp; /* new dir */
5104 cm_user_t *userp; /* user */
5105 cm_req_t *reqp; /* request struct */
5106 smb_vc_t *vcp; /* virtual circuit */
5107 char *maskp; /* pointer to star pattern of old file name */
5108 int flags; /* tilde, casefold, etc */
5109 char *newNamep; /* ptr to the new file's name */
5110 char oldName[MAX_PATH];
5114 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5117 smb_renameRock_t *rockp;
5120 char shortName[13]="";
5122 rockp = (smb_renameRock_t *) vrockp;
5124 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5125 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5126 caseFold |= CM_FLAG_8DOT3;
5128 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5130 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5131 !cm_Is8Dot3(dep->name)) {
5132 cm_Gen8Dot3Name(dep, shortName, NULL);
5133 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5138 strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
5139 rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
5140 code = CM_ERROR_STOPNOW;
5150 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5153 cm_space_t *spacep = NULL;
5154 smb_renameRock_t rock;
5155 cm_scache_t *oldDscp = NULL;
5156 cm_scache_t *newDscp = NULL;
5157 cm_scache_t *tmpscp= NULL;
5158 cm_scache_t *tmpscp2 = NULL;
5168 userp = smb_GetUserFromVCP(vcp, inp);
5169 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5171 cm_ReleaseUser(userp);
5172 return CM_ERROR_NOSUCHPATH;
5176 spacep = inp->spacep;
5177 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5179 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5180 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5181 userp, tidPathp, &req, &oldDscp);
5183 cm_ReleaseUser(userp);
5188 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5189 cm_ReleaseSCache(oldDscp);
5190 cm_ReleaseUser(userp);
5191 if ( WANTS_DFS_PATHNAMES(inp) )
5192 return CM_ERROR_PATH_NOT_COVERED;
5194 return CM_ERROR_BADSHARENAME;
5196 #endif /* DFS_SUPPORT */
5198 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5199 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5200 userp, tidPathp, &req, &newDscp);
5203 cm_ReleaseSCache(oldDscp);
5204 cm_ReleaseUser(userp);
5209 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5210 cm_ReleaseSCache(oldDscp);
5211 cm_ReleaseSCache(newDscp);
5212 cm_ReleaseUser(userp);
5213 if ( WANTS_DFS_PATHNAMES(inp) )
5214 return CM_ERROR_PATH_NOT_COVERED;
5216 return CM_ERROR_BADSHARENAME;
5218 #endif /* DFS_SUPPORT */
5221 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5222 * next, get the component names, and lower case them.
5225 /* handle the old name first */
5227 oldLastNamep = oldPathp;
5231 /* and handle the new name, too */
5233 newLastNamep = newPathp;
5237 /* TODO: The old name could be a wildcard. The new name must not be */
5239 /* do the vnode call */
5240 rock.odscp = oldDscp;
5241 rock.ndscp = newDscp;
5245 rock.maskp = oldLastNamep;
5246 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5247 rock.newNamep = newLastNamep;
5248 rock.oldName[0] = '\0';
5251 /* Check if the file already exists; if so return error */
5252 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5253 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5254 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5256 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5257 osi_LogSaveString(smb_logp, newLastNamep));
5259 /* Check if the old and the new names differ only in case. If so return
5260 * success, else return CM_ERROR_EXISTS
5262 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5264 /* This would be a success only if the old file is *as same as* the new file */
5265 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5267 if (tmpscp == tmpscp2)
5270 code = CM_ERROR_EXISTS;
5271 cm_ReleaseSCache(tmpscp2);
5274 code = CM_ERROR_NOSUCHFILE;
5277 /* file exist, do not rename, also fixes move */
5278 osi_Log0(smb_logp, "Can't rename. Target already exists");
5279 code = CM_ERROR_EXISTS;
5283 cm_ReleaseSCache(tmpscp);
5284 cm_ReleaseSCache(newDscp);
5285 cm_ReleaseSCache(oldDscp);
5286 cm_ReleaseUser(userp);
5290 /* Now search the directory for the pattern, and do the appropriate rename when found */
5291 thyper.LowPart = 0; /* search dir from here */
5292 thyper.HighPart = 0;
5294 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5295 if (code == 0 && !rock.any) {
5297 thyper.HighPart = 0;
5298 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5299 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5301 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5303 if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
5304 code = cm_Rename(rock.odscp, rock.oldName,
5305 rock.ndscp, rock.newNamep, rock.userp,
5307 /* if the call worked, stop doing the search now, since we
5308 * really only want to rename one file.
5310 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5311 } else if (code == 0) {
5312 code = CM_ERROR_NOSUCHFILE;
5315 /* Handle Change Notification */
5317 * Being lazy, not distinguishing between files and dirs in this
5318 * filter, since we'd have to do a lookup.
5321 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5322 if (oldDscp == newDscp) {
5323 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5324 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5325 filter, oldDscp, oldLastNamep,
5326 newLastNamep, TRUE);
5328 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5329 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5330 filter, oldDscp, oldLastNamep,
5332 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5333 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5334 filter, newDscp, newLastNamep,
5340 cm_ReleaseSCache(tmpscp);
5341 cm_ReleaseUser(userp);
5342 cm_ReleaseSCache(oldDscp);
5343 cm_ReleaseSCache(newDscp);
5348 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5351 cm_space_t *spacep = NULL;
5352 cm_scache_t *oldDscp = NULL;
5353 cm_scache_t *newDscp = NULL;
5354 cm_scache_t *tmpscp= NULL;
5355 cm_scache_t *tmpscp2 = NULL;
5356 cm_scache_t *sscp = NULL;
5365 userp = smb_GetUserFromVCP(vcp, inp);
5367 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5369 cm_ReleaseUser(userp);
5370 return CM_ERROR_NOSUCHPATH;
5375 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5377 spacep = inp->spacep;
5378 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5380 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5381 userp, tidPathp, &req, &oldDscp);
5383 cm_ReleaseUser(userp);
5388 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5389 cm_ReleaseSCache(oldDscp);
5390 cm_ReleaseUser(userp);
5391 if ( WANTS_DFS_PATHNAMES(inp) )
5392 return CM_ERROR_PATH_NOT_COVERED;
5394 return CM_ERROR_BADSHARENAME;
5396 #endif /* DFS_SUPPORT */
5398 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5399 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5400 userp, tidPathp, &req, &newDscp);
5402 cm_ReleaseSCache(oldDscp);
5403 cm_ReleaseUser(userp);
5408 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5409 cm_ReleaseSCache(newDscp);
5410 cm_ReleaseSCache(oldDscp);
5411 cm_ReleaseUser(userp);
5412 if ( WANTS_DFS_PATHNAMES(inp) )
5413 return CM_ERROR_PATH_NOT_COVERED;
5415 return CM_ERROR_BADSHARENAME;
5417 #endif /* DFS_SUPPORT */
5419 /* Now, although we did two lookups for the two directories (because the same
5420 * directory can be referenced through different paths), we only allow hard links
5421 * within the same directory. */
5422 if (oldDscp != newDscp) {
5423 cm_ReleaseSCache(oldDscp);
5424 cm_ReleaseSCache(newDscp);
5425 cm_ReleaseUser(userp);
5426 return CM_ERROR_CROSSDEVLINK;
5429 /* handle the old name first */
5431 oldLastNamep = oldPathp;
5435 /* and handle the new name, too */
5437 newLastNamep = newPathp;
5441 /* now lookup the old name */
5442 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5443 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5445 cm_ReleaseSCache(oldDscp);
5446 cm_ReleaseSCache(newDscp);
5447 cm_ReleaseUser(userp);
5451 /* Check if the file already exists; if so return error */
5452 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5453 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5454 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5456 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5457 osi_LogSaveString(smb_logp, newLastNamep));
5459 /* if the existing link is to the same file, then we return success */
5461 if(sscp == tmpscp) {
5464 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5465 code = CM_ERROR_EXISTS;
5470 cm_ReleaseSCache(tmpscp);
5471 cm_ReleaseSCache(sscp);
5472 cm_ReleaseSCache(newDscp);
5473 cm_ReleaseSCache(oldDscp);
5474 cm_ReleaseUser(userp);
5478 /* now create the hardlink */
5479 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5480 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5481 osi_Log1(smb_logp," Link returns 0x%x", code);
5483 /* Handle Change Notification */
5485 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5486 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5487 smb_NotifyChange(FILE_ACTION_ADDED,
5488 filter, newDscp, newLastNamep,
5493 cm_ReleaseSCache(tmpscp);
5494 cm_ReleaseUser(userp);
5495 cm_ReleaseSCache(sscp);
5496 cm_ReleaseSCache(oldDscp);
5497 cm_ReleaseSCache(newDscp);
5502 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5509 tp = smb_GetSMBData(inp, NULL);
5510 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5511 if (smb_StoreAnsiFilenames)
5512 OemToChar(oldPathp,oldPathp);
5513 newPathp = smb_ParseASCIIBlock(tp, &tp);
5514 if (smb_StoreAnsiFilenames)
5515 OemToChar(newPathp,newPathp);
5517 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5518 osi_LogSaveString(smb_logp, oldPathp),
5519 osi_LogSaveString(smb_logp, newPathp));
5521 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5523 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5529 typedef struct smb_rmdirRock {
5533 char *maskp; /* pointer to the star pattern */
5536 cm_dirEntryList_t * matches;
5539 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5542 smb_rmdirRock_t *rockp;
5547 rockp = (smb_rmdirRock_t *) vrockp;
5549 matchName = dep->name;
5550 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5551 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5553 match = (strcmp(matchName, rockp->maskp) == 0);
5555 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5556 !cm_Is8Dot3(dep->name)) {
5557 cm_Gen8Dot3Name(dep, shortName, NULL);
5558 matchName = shortName;
5559 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5564 cm_DirEntryListAdd(dep->name, &rockp->matches);
5570 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5578 smb_rmdirRock_t rock;
5587 tp = smb_GetSMBData(inp, NULL);
5588 pathp = smb_ParseASCIIBlock(tp, &tp);
5589 if (smb_StoreAnsiFilenames)
5590 OemToChar(pathp,pathp);
5592 spacep = inp->spacep;
5593 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5595 userp = smb_GetUserFromVCP(vcp, inp);
5597 caseFold = CM_FLAG_CASEFOLD;
5599 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5601 cm_ReleaseUser(userp);
5602 return CM_ERROR_NOSUCHPATH;
5604 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5605 userp, tidPathp, &req, &dscp);
5608 cm_ReleaseUser(userp);
5613 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5614 cm_ReleaseSCache(dscp);
5615 cm_ReleaseUser(userp);
5616 if ( WANTS_DFS_PATHNAMES(inp) )
5617 return CM_ERROR_PATH_NOT_COVERED;
5619 return CM_ERROR_BADSHARENAME;
5621 #endif /* DFS_SUPPORT */
5623 /* otherwise, scp points to the parent directory. */
5630 rock.maskp = lastNamep;
5631 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5634 thyper.HighPart = 0;
5638 rock.matches = NULL;
5640 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5641 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5642 if (code == 0 && !rock.any) {
5644 thyper.HighPart = 0;
5645 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5646 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5649 if (code == 0 && rock.matches) {
5650 cm_dirEntryList_t * entry;
5652 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5653 osi_Log1(smb_logp, "Removing directory %s",
5654 osi_LogSaveString(smb_logp, entry->name));
5656 code = cm_RemoveDir(dscp, entry->name, userp, &req);
5658 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5659 smb_NotifyChange(FILE_ACTION_REMOVED,
5660 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5661 dscp, entry->name, NULL, TRUE);
5665 cm_DirEntryListFree(&rock.matches);
5667 cm_ReleaseUser(userp);
5669 cm_ReleaseSCache(dscp);
5671 if (code == 0 && !rock.any)
5672 code = CM_ERROR_NOSUCHFILE;
5676 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5686 fid = smb_GetSMBParm(inp, 0);
5688 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5690 fid = smb_ChainFID(fid, inp);
5691 fidp = smb_FindFID(vcp, fid, 0);
5693 return CM_ERROR_BADFD;
5695 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5696 smb_CloseFID(vcp, fidp, NULL, 0);
5697 smb_ReleaseFID(fidp);
5698 return CM_ERROR_NOSUCHFILE;
5701 lock_ObtainMutex(&fidp->mx);
5702 if (fidp->flags & SMB_FID_IOCTL) {
5703 lock_ReleaseMutex(&fidp->mx);
5704 smb_ReleaseFID(fidp);
5705 return CM_ERROR_BADFD;
5707 lock_ReleaseMutex(&fidp->mx);
5709 userp = smb_GetUserFromVCP(vcp, inp);
5711 lock_ObtainMutex(&fidp->mx);
5712 if (fidp->flags & SMB_FID_OPENWRITE) {
5713 cm_scache_t * scp = fidp->scp;
5715 lock_ReleaseMutex(&fidp->mx);
5716 code = cm_FSync(scp, userp, &req);
5717 cm_ReleaseSCache(scp);
5720 lock_ReleaseMutex(&fidp->mx);
5723 smb_ReleaseFID(fidp);
5725 cm_ReleaseUser(userp);
5730 struct smb_FullNameRock {
5736 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5740 struct smb_FullNameRock *vrockp;
5742 vrockp = (struct smb_FullNameRock *)rockp;
5744 if (!cm_Is8Dot3(dep->name)) {
5745 cm_Gen8Dot3Name(dep, shortName, NULL);
5747 if (cm_stricmp(shortName, vrockp->name) == 0) {
5748 vrockp->fullName = strdup(dep->name);
5749 return CM_ERROR_STOPNOW;
5752 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5753 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5754 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5755 vrockp->fullName = strdup(dep->name);
5756 return CM_ERROR_STOPNOW;
5761 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5762 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5764 struct smb_FullNameRock rock;
5770 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5771 if (code == CM_ERROR_STOPNOW)
5772 *newPathp = rock.fullName;
5774 *newPathp = strdup(pathp);
5777 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5778 afs_uint32 dosTime) {
5781 cm_scache_t *dscp = NULL;
5783 cm_scache_t * scp = NULL;
5784 cm_scache_t *delscp = NULL;
5786 int nullcreator = 0;
5788 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5789 fidp, fidp->fid, scp, vcp);
5792 lock_ObtainMutex(&fidp->mx);
5793 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5794 lock_ReleaseMutex(&fidp->mx);
5795 osi_Log0(smb_logp, " No user specified. Not closing fid");
5796 return CM_ERROR_BADFD;
5799 userp = fidp->userp; /* no hold required since fidp is held
5800 throughout the function */
5801 lock_ReleaseMutex(&fidp->mx);
5806 lock_ObtainWrite(&smb_rctLock);
5808 osi_Log0(smb_logp, " Fid already closed.");
5809 lock_ReleaseWrite(&smb_rctLock);
5810 return CM_ERROR_BADFD;
5813 lock_ReleaseWrite(&smb_rctLock);
5815 lock_ObtainMutex(&fidp->mx);
5816 if (fidp->NTopen_dscp) {
5817 dscp = fidp->NTopen_dscp;
5818 cm_HoldSCache(dscp);
5821 if (fidp->NTopen_pathp) {
5822 pathp = strdup(fidp->NTopen_pathp);
5830 /* Don't jump the gun on an async raw write */
5831 while (fidp->raw_writers) {
5832 lock_ReleaseMutex(&fidp->mx);
5833 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5834 lock_ObtainMutex(&fidp->mx);
5837 /* watch for ioctl closes, and read-only opens */
5839 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5840 == SMB_FID_OPENWRITE) {
5841 if (dosTime != 0 && dosTime != -1) {
5842 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5843 /* This fixes defect 10958 */
5844 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5845 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5847 lock_ReleaseMutex(&fidp->mx);
5848 code = cm_FSync(scp, userp, &req);
5849 lock_ObtainMutex(&fidp->mx);
5854 /* unlock any pending locks */
5855 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5856 scp->fileType == CM_SCACHETYPE_FILE) {
5860 lock_ReleaseMutex(&fidp->mx);
5862 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5864 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5865 lock_ObtainMutex(&scp->mx);
5867 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5868 CM_SCACHESYNC_NEEDCALLBACK
5869 | CM_SCACHESYNC_GETSTATUS
5870 | CM_SCACHESYNC_LOCK);
5874 "smb CoreClose SyncOp failure code 0x%x", tcode);
5875 goto post_syncopdone;
5878 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5880 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5884 lock_ReleaseMutex(&scp->mx);
5885 lock_ObtainMutex(&fidp->mx);
5888 if (fidp->flags & SMB_FID_DELONCLOSE) {
5891 lock_ReleaseMutex(&fidp->mx);
5893 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
5898 smb_FullName(dscp, delscp, pathp, &fullPathp, userp, &req);
5899 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5900 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5903 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5904 smb_NotifyChange(FILE_ACTION_REMOVED,
5905 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5906 dscp, fullPathp, NULL, TRUE);
5909 code = cm_Unlink(dscp, fullPathp, userp, &req);
5912 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5913 smb_NotifyChange(FILE_ACTION_REMOVED,
5914 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5915 dscp, fullPathp, NULL, TRUE);
5919 lock_ObtainMutex(&fidp->mx);
5920 fidp->flags &= ~SMB_FID_DELONCLOSE;
5923 /* if this was a newly created file, then clear the creator
5924 * in the stat cache entry. */
5925 if (fidp->flags & SMB_FID_CREATED) {
5927 fidp->flags &= ~SMB_FID_CREATED;
5930 if (fidp->flags & SMB_FID_NTOPEN) {
5931 cm_ReleaseSCache(fidp->NTopen_dscp);
5932 fidp->NTopen_dscp = NULL;
5933 free(fidp->NTopen_pathp);
5934 fidp->NTopen_pathp = NULL;
5935 fidp->flags &= ~SMB_FID_NTOPEN;
5937 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
5938 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
5941 if (fidp->NTopen_wholepathp) {
5942 free(fidp->NTopen_wholepathp);
5943 fidp->NTopen_wholepathp = NULL;
5947 cm_ReleaseSCache(fidp->scp);
5950 lock_ReleaseMutex(&fidp->mx);
5953 cm_ReleaseSCache(dscp);
5957 lock_ObtainMutex(&delscp->mx);
5959 delscp->flags |= CM_SCACHEFLAG_DELETED;
5960 lock_ReleaseMutex(&delscp->mx);
5962 cm_ReleaseSCache(delscp);
5966 lock_ObtainMutex(&scp->mx);
5967 if (nullcreator && scp->creator == userp)
5968 scp->creator = NULL;
5969 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5970 lock_ReleaseMutex(&scp->mx);
5971 cm_ReleaseSCache(scp);
5980 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5988 fid = smb_GetSMBParm(inp, 0);
5989 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5991 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5993 fid = smb_ChainFID(fid, inp);
5994 fidp = smb_FindFID(vcp, fid, 0);
5996 return CM_ERROR_BADFD;
5999 userp = smb_GetUserFromVCP(vcp, inp);
6001 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6003 smb_ReleaseFID(fidp);
6004 cm_ReleaseUser(userp);
6009 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6011 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6012 cm_user_t *userp, long *readp)
6018 osi_hyper_t fileLength;
6020 osi_hyper_t lastByte;
6021 osi_hyper_t bufferOffset;
6022 long bufIndex, nbytes;
6024 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6032 lock_ObtainMutex(&fidp->mx);
6035 lock_ObtainMutex(&scp->mx);
6037 if (offset.HighPart == 0) {
6038 chunk = offset.LowPart >> cm_logChunkSize;
6039 if (chunk != fidp->curr_chunk) {
6040 fidp->prev_chunk = fidp->curr_chunk;
6041 fidp->curr_chunk = chunk;
6043 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6046 lock_ReleaseMutex(&fidp->mx);
6048 /* start by looking up the file's end */
6049 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6050 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6054 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6056 /* now we have the entry locked, look up the length */
6057 fileLength = scp->length;
6059 /* adjust count down so that it won't go past EOF */
6060 thyper.LowPart = count;
6061 thyper.HighPart = 0;
6062 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6064 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6065 /* we'd read past EOF, so just stop at fileLength bytes.
6066 * Start by computing how many bytes remain in the file.
6068 thyper = LargeIntegerSubtract(fileLength, offset);
6070 /* if we are past EOF, read 0 bytes */
6071 if (LargeIntegerLessThanZero(thyper))
6074 count = thyper.LowPart;
6079 /* now, copy the data one buffer at a time,
6080 * until we've filled the request packet
6083 /* if we've copied all the data requested, we're done */
6084 if (count <= 0) break;
6086 /* otherwise, load up a buffer of data */
6087 thyper.HighPart = offset.HighPart;
6088 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6089 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6092 buf_Release(bufferp);
6095 lock_ReleaseMutex(&scp->mx);
6097 lock_ObtainRead(&scp->bufCreateLock);
6098 code = buf_Get(scp, &thyper, &bufferp);
6099 lock_ReleaseRead(&scp->bufCreateLock);
6101 lock_ObtainMutex(&scp->mx);
6102 if (code) goto done;
6103 bufferOffset = thyper;
6105 /* now get the data in the cache */
6107 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6108 CM_SCACHESYNC_NEEDCALLBACK |
6109 CM_SCACHESYNC_READ);
6113 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6115 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6117 /* otherwise, load the buffer and try again */
6118 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6122 buf_Release(bufferp);
6126 } /* if (wrong buffer) ... */
6128 /* now we have the right buffer loaded. Copy out the
6129 * data from here to the user's buffer.
6131 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6133 /* and figure out how many bytes we want from this buffer */
6134 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6135 if (nbytes > count) nbytes = count; /* don't go past EOF */
6137 /* now copy the data */
6138 memcpy(op, bufferp->datap + bufIndex, nbytes);
6140 /* adjust counters, pointers, etc. */
6143 thyper.LowPart = nbytes;
6144 thyper.HighPart = 0;
6145 offset = LargeIntegerAdd(thyper, offset);
6149 lock_ReleaseMutex(&scp->mx);
6151 buf_Release(bufferp);
6153 if (code == 0 && sequential)
6154 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6156 cm_ReleaseSCache(scp);
6162 * smb_WriteData -- common code for Write and Raw Write
6164 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6165 cm_user_t *userp, long *writtenp)
6171 osi_hyper_t fileLength; /* file's length at start of write */
6172 osi_hyper_t minLength; /* don't read past this */
6173 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6175 osi_hyper_t thyper; /* hyper tmp variable */
6176 osi_hyper_t bufferOffset;
6177 afs_uint32 bufIndex; /* index in buffer where our data is */
6179 osi_hyper_t writeBackOffset;/* offset of region to write back when
6184 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6185 fidp->fid, offsetp->LowPart, count);
6195 lock_ObtainMutex(&fidp->mx);
6196 /* make sure we have a writable FD */
6197 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6198 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6199 fidp->fid, fidp->flags);
6200 lock_ReleaseMutex(&fidp->mx);
6201 code = CM_ERROR_BADFDOP;
6207 lock_ReleaseMutex(&fidp->mx);
6209 lock_ObtainMutex(&scp->mx);
6210 /* start by looking up the file's end */
6211 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6212 CM_SCACHESYNC_NEEDCALLBACK
6213 | CM_SCACHESYNC_SETSTATUS
6214 | CM_SCACHESYNC_GETSTATUS);
6218 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6220 /* now we have the entry locked, look up the length */
6221 fileLength = scp->length;
6222 minLength = fileLength;
6223 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6224 minLength = scp->serverLength;
6226 /* adjust file length if we extend past EOF */
6227 thyper.LowPart = count;
6228 thyper.HighPart = 0;
6229 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6230 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6231 /* we'd write past EOF, so extend the file */
6232 scp->mask |= CM_SCACHEMASK_LENGTH;
6233 scp->length = thyper;
6234 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6236 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6238 /* now, if the new position (thyper) and the old (offset) are in
6239 * different storeback windows, remember to store back the previous
6240 * storeback window when we're done with the write.
6242 if ((thyper.LowPart & (-cm_chunkSize)) !=
6243 (offset.LowPart & (-cm_chunkSize))) {
6244 /* they're different */
6246 writeBackOffset.HighPart = offset.HighPart;
6247 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6252 /* now, copy the data one buffer at a time, until we've filled the
6255 /* if we've copied all the data requested, we're done */
6259 /* handle over quota or out of space */
6260 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6261 *writtenp = written;
6262 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6266 /* otherwise, load up a buffer of data */
6267 thyper.HighPart = offset.HighPart;
6268 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6269 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6272 lock_ReleaseMutex(&bufferp->mx);
6273 buf_Release(bufferp);
6276 lock_ReleaseMutex(&scp->mx);
6278 lock_ObtainRead(&scp->bufCreateLock);
6279 code = buf_Get(scp, &thyper, &bufferp);
6280 lock_ReleaseRead(&scp->bufCreateLock);
6282 lock_ObtainMutex(&bufferp->mx);
6283 lock_ObtainMutex(&scp->mx);
6284 if (code) goto done;
6286 bufferOffset = thyper;
6288 /* now get the data in the cache */
6290 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6291 CM_SCACHESYNC_NEEDCALLBACK
6292 | CM_SCACHESYNC_WRITE
6293 | CM_SCACHESYNC_BUFLOCKED);
6297 cm_SyncOpDone(scp, bufferp,
6298 CM_SCACHESYNC_NEEDCALLBACK
6299 | CM_SCACHESYNC_WRITE
6300 | CM_SCACHESYNC_BUFLOCKED);
6302 /* If we're overwriting the entire buffer, or
6303 * if we're writing at or past EOF, mark the
6304 * buffer as current so we don't call
6305 * cm_GetBuffer. This skips the fetch from the
6306 * server in those cases where we're going to
6307 * obliterate all the data in the buffer anyway,
6308 * or in those cases where there is no useful
6309 * data at the server to start with.
6311 * Use minLength instead of scp->length, since
6312 * the latter has already been updated by this
6315 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6316 || LargeIntegerEqualTo(offset, bufferp->offset)
6317 && (count >= cm_data.buf_blockSize
6318 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6319 ConvertLongToLargeInteger(count)),
6321 if (count < cm_data.buf_blockSize
6322 && bufferp->dataVersion == -1)
6323 memset(bufferp->datap, 0,
6324 cm_data.buf_blockSize);
6325 bufferp->dataVersion = scp->dataVersion;
6328 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6330 /* otherwise, load the buffer and try again */
6331 lock_ReleaseMutex(&bufferp->mx);
6332 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6334 lock_ReleaseMutex(&scp->mx);
6335 lock_ObtainMutex(&bufferp->mx);
6336 lock_ObtainMutex(&scp->mx);
6340 lock_ReleaseMutex(&bufferp->mx);
6341 buf_Release(bufferp);
6345 } /* if (wrong buffer) ... */
6347 /* now we have the right buffer loaded. Copy out the
6348 * data from here to the user's buffer.
6350 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6352 /* and figure out how many bytes we want from this buffer */
6353 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6355 nbytes = count; /* don't go past end of request */
6357 /* now copy the data */
6358 memcpy(bufferp->datap + bufIndex, op, nbytes);
6359 buf_SetDirty(bufferp, bufIndex, nbytes);
6361 /* and record the last writer */
6362 if (bufferp->userp != userp) {
6365 cm_ReleaseUser(bufferp->userp);
6366 bufferp->userp = userp;
6369 /* adjust counters, pointers, etc. */
6373 thyper.LowPart = nbytes;
6374 thyper.HighPart = 0;
6375 offset = LargeIntegerAdd(thyper, offset);
6379 lock_ReleaseMutex(&scp->mx);
6382 lock_ReleaseMutex(&bufferp->mx);
6383 buf_Release(bufferp);
6386 lock_ObtainMutex(&fidp->mx);
6387 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6388 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6389 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6390 fidp->NTopen_dscp, fidp->NTopen_pathp,
6393 lock_ReleaseMutex(&fidp->mx);
6395 if (code == 0 && doWriteBack) {
6397 lock_ObtainMutex(&scp->mx);
6398 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6400 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6401 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6403 lock_ReleaseMutex(&scp->mx);
6404 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6405 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6406 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6409 cm_ReleaseSCache(scp);
6411 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6412 fidp->fid, code, *writtenp);
6416 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6419 unsigned short count;
6421 unsigned short hint;
6422 long written = 0, total_written = 0;
6427 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6429 int inDataBlockCount;
6431 fd = smb_GetSMBParm(inp, 0);
6432 count = smb_GetSMBParm(inp, 1);
6433 offset.HighPart = 0; /* too bad */
6434 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6435 hint = smb_GetSMBParm(inp, 4);
6437 op = smb_GetSMBData(inp, NULL);
6438 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6440 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6441 fd, offset.LowPart, count);
6443 fd = smb_ChainFID(fd, inp);
6444 fidp = smb_FindFID(vcp, fd, 0);
6446 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6447 return CM_ERROR_BADFD;
6450 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6451 smb_CloseFID(vcp, fidp, NULL, 0);
6452 smb_ReleaseFID(fidp);
6453 return CM_ERROR_NOSUCHFILE;
6456 lock_ObtainMutex(&fidp->mx);
6457 if (fidp->flags & SMB_FID_IOCTL) {
6458 lock_ReleaseMutex(&fidp->mx);
6459 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6460 smb_ReleaseFID(fidp);
6461 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6464 lock_ReleaseMutex(&fidp->mx);
6465 userp = smb_GetUserFromVCP(vcp, inp);
6469 LARGE_INTEGER LOffset;
6470 LARGE_INTEGER LLength;
6472 pid = ((smb_t *) inp)->pid;
6473 key = cm_GenerateKey(vcp->vcID, pid, fd);
6475 LOffset.HighPart = offset.HighPart;
6476 LOffset.LowPart = offset.LowPart;
6477 LLength.HighPart = 0;
6478 LLength.LowPart = count;
6480 lock_ObtainMutex(&fidp->scp->mx);
6481 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6482 lock_ReleaseMutex(&fidp->scp->mx);
6485 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6490 /* special case: 0 bytes transferred means truncate to this position */
6494 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6498 truncAttr.mask = CM_ATTRMASK_LENGTH;
6499 truncAttr.length.LowPart = offset.LowPart;
6500 truncAttr.length.HighPart = 0;
6501 lock_ObtainMutex(&fidp->mx);
6502 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6503 fidp->flags |= SMB_FID_LENGTHSETDONE;
6504 lock_ReleaseMutex(&fidp->mx);
6505 smb_SetSMBParm(outp, 0, 0 /* count */);
6506 smb_SetSMBDataLength(outp, 0);
6511 * Work around bug in NT client
6513 * When copying a file, the NT client should first copy the data,
6514 * then copy the last write time. But sometimes the NT client does
6515 * these in the wrong order, so the data copies would inadvertently
6516 * cause the last write time to be overwritten. We try to detect this,
6517 * and don't set client mod time if we think that would go against the
6520 lock_ObtainMutex(&fidp->mx);
6521 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6522 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6523 fidp->scp->clientModTime = time(NULL);
6525 lock_ReleaseMutex(&fidp->mx);
6528 while ( code == 0 && count > 0 ) {
6529 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6530 if (code == 0 && written == 0)
6531 code = CM_ERROR_PARTIALWRITE;
6533 offset = LargeIntegerAdd(offset,
6534 ConvertLongToLargeInteger(written));
6535 count -= (unsigned short)written;
6536 total_written += written;
6540 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6541 total_written, code);
6543 /* set the packet data length to 3 bytes for the data block header,
6544 * plus the size of the data.
6546 smb_SetSMBParm(outp, 0, total_written);
6547 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6548 smb_SetSMBParm(outp, 3, hint);
6549 smb_SetSMBDataLength(outp, 0);
6552 smb_ReleaseFID(fidp);
6553 cm_ReleaseUser(userp);
6558 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6559 NCB *ncbp, raw_write_cont_t *rwcp)
6568 fd = smb_GetSMBParm(inp, 0);
6569 fidp = smb_FindFID(vcp, fd, 0);
6571 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6572 smb_CloseFID(vcp, fidp, NULL, 0);
6573 smb_ReleaseFID(fidp);
6577 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6578 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6580 userp = smb_GetUserFromVCP(vcp, inp);
6583 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6585 if (rwcp->writeMode & 0x1) { /* synchronous */
6588 smb_FormatResponsePacket(vcp, inp, outp);
6589 op = (smb_t *) outp;
6590 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6591 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6592 smb_SetSMBDataLength(outp, 0);
6593 smb_SendPacket(vcp, outp);
6594 smb_FreePacket(outp);
6596 else { /* asynchronous */
6597 lock_ObtainMutex(&fidp->mx);
6598 fidp->raw_writers--;
6599 if (fidp->raw_writers == 0)
6600 thrd_SetEvent(fidp->raw_write_event);
6601 lock_ReleaseMutex(&fidp->mx);
6604 /* Give back raw buffer */
6605 lock_ObtainMutex(&smb_RawBufLock);
6606 *((char **)rawBuf) = smb_RawBufs;
6607 smb_RawBufs = rawBuf;
6608 lock_ReleaseMutex(&smb_RawBufLock);
6610 smb_ReleaseFID(fidp);
6611 cm_ReleaseUser(userp);
6614 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6619 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6622 long count, written = 0, total_written = 0;
6629 unsigned short writeMode;
6631 fd = smb_GetSMBParm(inp, 0);
6632 totalCount = smb_GetSMBParm(inp, 1);
6633 count = smb_GetSMBParm(inp, 10);
6634 writeMode = smb_GetSMBParm(inp, 7);
6636 op = (char *) inp->data;
6637 op += smb_GetSMBParm(inp, 11);
6639 offset.HighPart = 0;
6640 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6642 if (*inp->wctp == 14) {
6643 /* we received a 64-bit file offset */
6644 #ifdef AFS_LARGEFILES
6645 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6647 if (LargeIntegerLessThanZero(offset)) {
6649 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6650 offset.HighPart, offset.LowPart);
6651 return CM_ERROR_BADSMB;
6654 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6656 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6657 return CM_ERROR_BADSMB;
6660 offset.HighPart = 0;
6663 offset.HighPart = 0; /* 32-bit file offset */
6667 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6668 fd, offset.HighPart, offset.LowPart, count);
6670 " WriteRaw WriteMode 0x%x",
6673 fd = smb_ChainFID(fd, inp);
6674 fidp = smb_FindFID(vcp, fd, 0);
6676 return CM_ERROR_BADFD;
6679 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6680 smb_CloseFID(vcp, fidp, NULL, 0);
6681 smb_ReleaseFID(fidp);
6682 return CM_ERROR_NOSUCHFILE;
6688 LARGE_INTEGER LOffset;
6689 LARGE_INTEGER LLength;
6691 pid = ((smb_t *) inp)->pid;
6692 key = cm_GenerateKey(vcp->vcID, pid, fd);
6694 LOffset.HighPart = offset.HighPart;
6695 LOffset.LowPart = offset.LowPart;
6696 LLength.HighPart = 0;
6697 LLength.LowPart = count;
6699 lock_ObtainMutex(&fidp->scp->mx);
6700 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6701 lock_ReleaseMutex(&fidp->scp->mx);
6704 smb_ReleaseFID(fidp);
6709 userp = smb_GetUserFromVCP(vcp, inp);
6712 * Work around bug in NT client
6714 * When copying a file, the NT client should first copy the data,
6715 * then copy the last write time. But sometimes the NT client does
6716 * these in the wrong order, so the data copies would inadvertently
6717 * cause the last write time to be overwritten. We try to detect this,
6718 * and don't set client mod time if we think that would go against the
6721 lock_ObtainMutex(&fidp->mx);
6722 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6723 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6724 fidp->scp->clientModTime = time(NULL);
6726 lock_ReleaseMutex(&fidp->mx);
6729 while ( code == 0 && count > 0 ) {
6730 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6731 if (code == 0 && written == 0)
6732 code = CM_ERROR_PARTIALWRITE;
6734 offset = LargeIntegerAdd(offset,
6735 ConvertLongToLargeInteger(written));
6738 total_written += written;
6742 /* Get a raw buffer */
6745 lock_ObtainMutex(&smb_RawBufLock);
6747 /* Get a raw buf, from head of list */
6748 rawBuf = smb_RawBufs;
6749 smb_RawBufs = *(char **)smb_RawBufs;
6752 code = CM_ERROR_USESTD;
6754 lock_ReleaseMutex(&smb_RawBufLock);
6757 /* Don't allow a premature Close */
6758 if (code == 0 && (writeMode & 1) == 0) {
6759 lock_ObtainMutex(&fidp->mx);
6760 fidp->raw_writers++;
6761 thrd_ResetEvent(fidp->raw_write_event);
6762 lock_ReleaseMutex(&fidp->mx);
6765 smb_ReleaseFID(fidp);
6766 cm_ReleaseUser(userp);
6769 smb_SetSMBParm(outp, 0, total_written);
6770 smb_SetSMBDataLength(outp, 0);
6771 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6776 offset = LargeIntegerAdd(offset,
6777 ConvertLongToLargeInteger(count));
6781 rwcp->offset.HighPart = offset.HighPart;
6782 rwcp->offset.LowPart = offset.LowPart;
6783 rwcp->count = totalCount - count;
6784 rwcp->writeMode = writeMode;
6785 rwcp->alreadyWritten = total_written;
6787 /* set the packet data length to 3 bytes for the data block header,
6788 * plus the size of the data.
6790 smb_SetSMBParm(outp, 0, 0xffff);
6791 smb_SetSMBDataLength(outp, 0);
6796 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6799 long count, finalCount;
6807 fd = smb_GetSMBParm(inp, 0);
6808 count = smb_GetSMBParm(inp, 1);
6809 offset.HighPart = 0; /* too bad */
6810 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6812 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6813 fd, offset.LowPart, count);
6815 fd = smb_ChainFID(fd, inp);
6816 fidp = smb_FindFID(vcp, fd, 0);
6818 return CM_ERROR_BADFD;
6820 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6821 smb_CloseFID(vcp, fidp, NULL, 0);
6822 smb_ReleaseFID(fidp);
6823 return CM_ERROR_NOSUCHFILE;
6826 lock_ObtainMutex(&fidp->mx);
6827 if (fidp->flags & SMB_FID_IOCTL) {
6828 lock_ReleaseMutex(&fidp->mx);
6829 code = smb_IoctlRead(fidp, vcp, inp, outp);
6830 smb_ReleaseFID(fidp);
6833 lock_ReleaseMutex(&fidp->mx);
6836 LARGE_INTEGER LOffset, LLength;
6839 pid = ((smb_t *) inp)->pid;
6840 key = cm_GenerateKey(vcp->vcID, pid, fd);
6842 LOffset.HighPart = 0;
6843 LOffset.LowPart = offset.LowPart;
6844 LLength.HighPart = 0;
6845 LLength.LowPart = count;
6847 lock_ObtainMutex(&fidp->scp->mx);
6848 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6849 lock_ReleaseMutex(&fidp->scp->mx);
6852 smb_ReleaseFID(fidp);
6856 userp = smb_GetUserFromVCP(vcp, inp);
6858 /* remember this for final results */
6859 smb_SetSMBParm(outp, 0, count);
6860 smb_SetSMBParm(outp, 1, 0);
6861 smb_SetSMBParm(outp, 2, 0);
6862 smb_SetSMBParm(outp, 3, 0);
6863 smb_SetSMBParm(outp, 4, 0);
6865 /* set the packet data length to 3 bytes for the data block header,
6866 * plus the size of the data.
6868 smb_SetSMBDataLength(outp, count+3);
6870 /* get op ptr after putting in the parms, since otherwise we don't
6871 * know where the data really is.
6873 op = smb_GetSMBData(outp, NULL);
6875 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6876 *op++ = 1; /* data block marker */
6877 *op++ = (unsigned char) (count & 0xff);
6878 *op++ = (unsigned char) ((count >> 8) & 0xff);
6880 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6882 /* fix some things up */
6883 smb_SetSMBParm(outp, 0, finalCount);
6884 smb_SetSMBDataLength(outp, finalCount+3);
6886 smb_ReleaseFID(fidp);
6888 cm_ReleaseUser(userp);
6892 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6899 cm_scache_t *dscp; /* dir we're dealing with */
6900 cm_scache_t *scp; /* file we're creating */
6902 int initialModeBits;
6912 /* compute initial mode bits based on read-only flag in attributes */
6913 initialModeBits = 0777;
6915 tp = smb_GetSMBData(inp, NULL);
6916 pathp = smb_ParseASCIIBlock(tp, &tp);
6917 if (smb_StoreAnsiFilenames)
6918 OemToChar(pathp,pathp);
6920 if (strcmp(pathp, "\\") == 0)
6921 return CM_ERROR_EXISTS;
6923 spacep = inp->spacep;
6924 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6926 userp = smb_GetUserFromVCP(vcp, inp);
6928 caseFold = CM_FLAG_CASEFOLD;
6930 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6932 cm_ReleaseUser(userp);
6933 return CM_ERROR_NOSUCHPATH;
6936 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6937 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6938 userp, tidPathp, &req, &dscp);
6941 cm_ReleaseUser(userp);
6946 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6947 cm_ReleaseSCache(dscp);
6948 cm_ReleaseUser(userp);
6949 if ( WANTS_DFS_PATHNAMES(inp) )
6950 return CM_ERROR_PATH_NOT_COVERED;
6952 return CM_ERROR_BADSHARENAME;
6954 #endif /* DFS_SUPPORT */
6956 /* otherwise, scp points to the parent directory. Do a lookup, and
6957 * fail if we find it. Otherwise, we do the create.
6963 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6964 if (scp) cm_ReleaseSCache(scp);
6965 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6966 if (code == 0) code = CM_ERROR_EXISTS;
6967 cm_ReleaseSCache(dscp);
6968 cm_ReleaseUser(userp);
6972 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6973 setAttr.clientModTime = time(NULL);
6974 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6975 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6976 smb_NotifyChange(FILE_ACTION_ADDED,
6977 FILE_NOTIFY_CHANGE_DIR_NAME,
6978 dscp, lastNamep, NULL, TRUE);
6980 /* we don't need this any longer */
6981 cm_ReleaseSCache(dscp);
6984 /* something went wrong creating or truncating the file */
6985 cm_ReleaseUser(userp);
6989 /* otherwise we succeeded */
6990 smb_SetSMBDataLength(outp, 0);
6991 cm_ReleaseUser(userp);
6996 BOOL smb_IsLegalFilename(char *filename)
6999 * Find the longest substring of filename that does not contain
7000 * any of the chars in illegalChars. If that substring is less
7001 * than the length of the whole string, then one or more of the
7002 * illegal chars is in filename.
7004 if (strcspn(filename, illegalChars) < strlen(filename))
7010 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7018 cm_scache_t *dscp; /* dir we're dealing with */
7019 cm_scache_t *scp; /* file we're creating */
7021 int initialModeBits;
7029 int created = 0; /* the file was new */
7034 excl = (inp->inCom == 0x03)? 0 : 1;
7036 attributes = smb_GetSMBParm(inp, 0);
7037 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7039 /* compute initial mode bits based on read-only flag in attributes */
7040 initialModeBits = 0666;
7041 if (attributes & SMB_ATTR_READONLY)
7042 initialModeBits &= ~0222;
7044 tp = smb_GetSMBData(inp, NULL);
7045 pathp = smb_ParseASCIIBlock(tp, &tp);
7046 if (smb_StoreAnsiFilenames)
7047 OemToChar(pathp,pathp);
7049 spacep = inp->spacep;
7050 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7052 userp = smb_GetUserFromVCP(vcp, inp);
7054 caseFold = CM_FLAG_CASEFOLD;
7056 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7058 cm_ReleaseUser(userp);
7059 return CM_ERROR_NOSUCHPATH;
7061 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
7062 userp, tidPathp, &req, &dscp);
7065 cm_ReleaseUser(userp);
7070 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7071 cm_ReleaseSCache(dscp);
7072 cm_ReleaseUser(userp);
7073 if ( WANTS_DFS_PATHNAMES(inp) )
7074 return CM_ERROR_PATH_NOT_COVERED;
7076 return CM_ERROR_BADSHARENAME;
7078 #endif /* DFS_SUPPORT */
7080 /* otherwise, scp points to the parent directory. Do a lookup, and
7081 * truncate the file if we find it, otherwise we create the file.
7088 if (!smb_IsLegalFilename(lastNamep))
7089 return CM_ERROR_BADNTFILENAME;
7091 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7092 #ifdef DEBUG_VERBOSE
7095 hexp = osi_HexifyString( lastNamep );
7096 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7101 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7102 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7103 cm_ReleaseSCache(dscp);
7104 cm_ReleaseUser(userp);
7108 /* if we get here, if code is 0, the file exists and is represented by
7109 * scp. Otherwise, we have to create it.
7113 /* oops, file shouldn't be there */
7114 cm_ReleaseSCache(dscp);
7115 cm_ReleaseSCache(scp);
7116 cm_ReleaseUser(userp);
7117 return CM_ERROR_EXISTS;
7120 setAttr.mask = CM_ATTRMASK_LENGTH;
7121 setAttr.length.LowPart = 0;
7122 setAttr.length.HighPart = 0;
7123 code = cm_SetAttr(scp, &setAttr, userp, &req);
7126 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7127 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7128 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7132 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7133 smb_NotifyChange(FILE_ACTION_ADDED,
7134 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7135 dscp, lastNamep, NULL, TRUE);
7136 } else if (!excl && code == CM_ERROR_EXISTS) {
7137 /* not an exclusive create, and someone else tried
7138 * creating it already, then we open it anyway. We
7139 * don't bother retrying after this, since if this next
7140 * fails, that means that the file was deleted after
7141 * we started this call.
7143 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7146 setAttr.mask = CM_ATTRMASK_LENGTH;
7147 setAttr.length.LowPart = 0;
7148 setAttr.length.HighPart = 0;
7149 code = cm_SetAttr(scp, &setAttr, userp, &req);
7154 /* we don't need this any longer */
7155 cm_ReleaseSCache(dscp);
7158 /* something went wrong creating or truncating the file */
7159 if (scp) cm_ReleaseSCache(scp);
7160 cm_ReleaseUser(userp);
7164 /* make sure we only open files */
7165 if (scp->fileType != CM_SCACHETYPE_FILE) {
7166 cm_ReleaseSCache(scp);
7167 cm_ReleaseUser(userp);
7168 return CM_ERROR_ISDIR;
7171 /* now all we have to do is open the file itself */
7172 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7173 osi_assertx(fidp, "null smb_fid_t");
7177 lock_ObtainMutex(&fidp->mx);
7178 /* always create it open for read/write */
7179 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7181 /* remember that the file was newly created */
7183 fidp->flags |= SMB_FID_CREATED;
7185 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7187 /* save a pointer to the vnode */
7189 lock_ObtainMutex(&scp->mx);
7190 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7191 lock_ReleaseMutex(&scp->mx);
7194 fidp->userp = userp;
7195 lock_ReleaseMutex(&fidp->mx);
7197 smb_SetSMBParm(outp, 0, fidp->fid);
7198 smb_SetSMBDataLength(outp, 0);
7200 cm_Open(scp, 0, userp);
7202 smb_ReleaseFID(fidp);
7203 cm_ReleaseUser(userp);
7204 /* leave scp held since we put it in fidp->scp */
7208 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7211 osi_hyper_t new_offset;
7222 fd = smb_GetSMBParm(inp, 0);
7223 whence = smb_GetSMBParm(inp, 1);
7224 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7226 /* try to find the file descriptor */
7227 fd = smb_ChainFID(fd, inp);
7228 fidp = smb_FindFID(vcp, fd, 0);
7230 return CM_ERROR_BADFD;
7232 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7233 smb_CloseFID(vcp, fidp, NULL, 0);
7234 smb_ReleaseFID(fidp);
7235 return CM_ERROR_NOSUCHFILE;
7238 lock_ObtainMutex(&fidp->mx);
7239 if (fidp->flags & SMB_FID_IOCTL) {
7240 lock_ReleaseMutex(&fidp->mx);
7241 smb_ReleaseFID(fidp);
7242 return CM_ERROR_BADFD;
7244 lock_ReleaseMutex(&fidp->mx);
7246 userp = smb_GetUserFromVCP(vcp, inp);
7248 lock_ObtainMutex(&fidp->mx);
7251 lock_ReleaseMutex(&fidp->mx);
7252 lock_ObtainMutex(&scp->mx);
7253 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7254 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7256 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7258 /* offset from current offset */
7259 new_offset = LargeIntegerAdd(fidp->offset,
7260 ConvertLongToLargeInteger(offset));
7262 else if (whence == 2) {
7263 /* offset from current EOF */
7264 new_offset = LargeIntegerAdd(scp->length,
7265 ConvertLongToLargeInteger(offset));
7267 new_offset = ConvertLongToLargeInteger(offset);
7270 fidp->offset = new_offset;
7271 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7272 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7273 smb_SetSMBDataLength(outp, 0);
7275 lock_ReleaseMutex(&scp->mx);
7276 smb_ReleaseFID(fidp);
7277 cm_ReleaseSCache(scp);
7278 cm_ReleaseUser(userp);
7282 /* dispatch all of the requests received in a packet. Due to chaining, this may
7283 * be more than one request.
7285 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7286 NCB *ncbp, raw_write_cont_t *rwcp)
7290 unsigned long code = 0;
7291 unsigned char *outWctp;
7292 int nparms; /* # of bytes of parameters */
7294 int nbytes; /* bytes of data, excluding count */
7297 unsigned short errCode;
7298 unsigned long NTStatus;
7300 unsigned char errClass;
7301 unsigned int oldGen;
7302 DWORD oldTime, newTime;
7304 /* get easy pointer to the data */
7305 smbp = (smb_t *) inp->data;
7307 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7308 /* setup the basic parms for the initial request in the packet */
7309 inp->inCom = smbp->com;
7310 inp->wctp = &smbp->wct;
7312 inp->ncb_length = ncbp->ncb_length;
7317 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7318 /* log it and discard it */
7319 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7320 __FILE__, __LINE__, ncbp->ncb_length);
7321 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7325 /* We are an ongoing op */
7326 thrd_Increment(&ongoingOps);
7328 /* set up response packet for receiving output */
7329 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7330 smb_FormatResponsePacket(vcp, inp, outp);
7331 outWctp = outp->wctp;
7333 /* Remember session generation number and time */
7334 oldGen = sessionGen;
7335 oldTime = GetTickCount();
7337 while (inp->inCom != 0xff) {
7338 dp = &smb_dispatchTable[inp->inCom];
7340 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7341 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7342 code = outp->resumeCode;
7346 /* process each request in the packet; inCom, wctp and inCount
7347 * are already set up.
7349 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7352 /* now do the dispatch */
7353 /* start by formatting the response record a little, as a default */
7354 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7356 outWctp[1] = 0xff; /* no operation */
7357 outWctp[2] = 0; /* padding */
7362 /* not a chained request, this is a more reasonable default */
7363 outWctp[0] = 0; /* wct of zero */
7364 outWctp[1] = 0; /* and bcc (word) of zero */
7368 /* once set, stays set. Doesn't matter, since we never chain
7369 * "no response" calls.
7371 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7375 /* we have a recognized operation */
7377 if (inp->inCom == 0x1d)
7379 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7381 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7382 code = (*(dp->procp)) (vcp, inp, outp);
7383 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7385 if ( code == CM_ERROR_BADSMB ||
7386 code == CM_ERROR_BADOP )
7388 #endif /* LOG_PACKET */
7391 if (oldGen != sessionGen) {
7392 newTime = GetTickCount();
7393 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7394 newTime - oldTime, ncbp->ncb_length);
7395 osi_Log2(smb_logp, "Pkt straddled session startup, "
7396 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7400 /* bad opcode, fail the request, after displaying it */
7401 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7404 #endif /* LOG_PACKET */
7407 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7408 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7409 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7410 if (code == IDCANCEL)
7413 code = CM_ERROR_BADOP;
7416 /* catastrophic failure: log as much as possible */
7417 if (code == CM_ERROR_BADSMB) {
7418 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7422 #endif /* LOG_PACKET */
7423 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7426 code = CM_ERROR_INVAL;
7429 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7430 thrd_Decrement(&ongoingOps);
7435 /* now, if we failed, turn the current response into an empty
7436 * one, and fill in the response packet's error code.
7439 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7440 smb_MapNTError(code, &NTStatus);
7441 outWctp = outp->wctp;
7442 smbp = (smb_t *) &outp->data;
7443 if (code != CM_ERROR_PARTIALWRITE
7444 && code != CM_ERROR_BUFFERTOOSMALL
7445 && code != CM_ERROR_GSSCONTINUE) {
7446 /* nuke wct and bcc. For a partial
7447 * write or an in-process authentication handshake,
7448 * assume they're OK.
7454 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7455 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7456 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7457 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7458 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7462 smb_MapCoreError(code, vcp, &errCode, &errClass);
7463 outWctp = outp->wctp;
7464 smbp = (smb_t *) &outp->data;
7465 if (code != CM_ERROR_PARTIALWRITE) {
7466 /* nuke wct and bcc. For a partial
7467 * write, assume they're OK.
7473 smbp->errLow = (unsigned char) (errCode & 0xff);
7474 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7475 smbp->rcls = errClass;
7478 } /* error occurred */
7480 /* if we're here, we've finished one request. Look to see if
7481 * this is a chained opcode. If it is, setup things to process
7482 * the chained request, and setup the output buffer to hold the
7483 * chained response. Start by finding the next input record.
7485 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7486 break; /* not a chained req */
7487 tp = inp->wctp; /* points to start of last request */
7488 /* in a chained request, the first two
7489 * parm fields are required, and are
7490 * AndXCommand/AndXReserved and
7492 if (tp[0] < 2) break;
7493 if (tp[1] == 0xff) break; /* no more chained opcodes */
7495 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7498 /* and now append the next output request to the end of this
7499 * last request. Begin by finding out where the last response
7500 * ends, since that's where we'll put our new response.
7502 outWctp = outp->wctp; /* ptr to out parameters */
7503 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7504 nparms = outWctp[0] << 1;
7505 tp = outWctp + nparms + 1; /* now points to bcc field */
7506 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7507 tp += 2 /* for the count itself */ + nbytes;
7508 /* tp now points to the new output record; go back and patch the
7509 * second parameter (off2) to point to the new record.
7511 temp = (unsigned int)(tp - outp->data);
7512 outWctp[3] = (unsigned char) (temp & 0xff);
7513 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7514 outWctp[2] = 0; /* padding */
7515 outWctp[1] = inp->inCom; /* next opcode */
7517 /* finally, setup for the next iteration */
7520 } /* while loop over all requests in the packet */
7522 /* now send the output packet, and return */
7524 smb_SendPacket(vcp, outp);
7525 thrd_Decrement(&ongoingOps);
7530 /* Wait for Netbios() calls to return, and make the results available to server
7531 * threads. Note that server threads can't wait on the NCBevents array
7532 * themselves, because NCB events are manual-reset, and the servers would race
7533 * each other to reset them.
7535 void smb_ClientWaiter(void *parmp)
7540 while (smbShutdownFlag == 0) {
7541 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7543 if (code == WAIT_OBJECT_0)
7546 /* error checking */
7547 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7549 int abandonIdx = code - WAIT_ABANDONED_0;
7550 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7553 if (code == WAIT_IO_COMPLETION)
7555 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7559 if (code == WAIT_TIMEOUT)
7561 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7564 if (code == WAIT_FAILED)
7566 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7569 idx = code - WAIT_OBJECT_0;
7571 /* check idx range! */
7572 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7574 /* this is fatal - log as much as possible */
7575 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7576 osi_assertx(0, "invalid index");
7579 thrd_ResetEvent(NCBevents[idx]);
7580 thrd_SetEvent(NCBreturns[0][idx]);
7585 * Try to have one NCBRECV request waiting for every live session. Not more
7586 * than one, because if there is more than one, it's hard to handle Write Raw.
7588 void smb_ServerWaiter(void *parmp)
7591 int idx_session, idx_NCB;
7594 while (smbShutdownFlag == 0) {
7596 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7598 if (code == WAIT_OBJECT_0)
7601 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7603 int abandonIdx = code - WAIT_ABANDONED_0;
7604 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7607 if (code == WAIT_IO_COMPLETION)
7609 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7613 if (code == WAIT_TIMEOUT)
7615 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7618 if (code == WAIT_FAILED)
7620 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7623 idx_session = code - WAIT_OBJECT_0;
7625 /* check idx range! */
7626 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7628 /* this is fatal - log as much as possible */
7629 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7630 osi_assertx(0, "invalid index");
7635 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7637 if (code == WAIT_OBJECT_0) {
7638 if (smbShutdownFlag == 1)
7644 /* error checking */
7645 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7647 int abandonIdx = code - WAIT_ABANDONED_0;
7648 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7651 if (code == WAIT_IO_COMPLETION)
7653 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7657 if (code == WAIT_TIMEOUT)
7659 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7662 if (code == WAIT_FAILED)
7664 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7667 idx_NCB = code - WAIT_OBJECT_0;
7669 /* check idx range! */
7670 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7672 /* this is fatal - log as much as possible */
7673 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7674 osi_assertx(0, "invalid index");
7677 /* Link them together */
7678 NCBsessions[idx_NCB] = idx_session;
7681 ncbp = NCBs[idx_NCB];
7682 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7683 ncbp->ncb_command = NCBRECV | ASYNCH;
7684 ncbp->ncb_lana_num = lanas[idx_session];
7685 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7686 ncbp->ncb_event = NCBevents[idx_NCB];
7687 ncbp->ncb_length = SMB_PACKETSIZE;
7693 * The top level loop for handling SMB request messages. Each server thread
7694 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7695 * NCB and buffer for the incoming request are loaned to us.
7697 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7698 * to immediately send a request for the rest of the data. This must come
7699 * before any other traffic for that session, so we delay setting the session
7700 * event until that data has come in.
7702 void smb_Server(VOID *parmp)
7704 INT_PTR myIdx = (INT_PTR) parmp;
7708 smb_packet_t *outbufp;
7710 int idx_NCB, idx_session;
7712 smb_vc_t *vcp = NULL;
7715 rx_StartClientThread();
7718 outbufp = GetPacket();
7719 outbufp->ncbp = outncbp;
7727 smb_ResetServerPriority();
7729 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7732 /* terminate silently if shutdown flag is set */
7733 if (code == WAIT_OBJECT_0) {
7734 if (smbShutdownFlag == 1) {
7735 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7741 /* error checking */
7742 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7744 int abandonIdx = code - WAIT_ABANDONED_0;
7745 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7748 if (code == WAIT_IO_COMPLETION)
7750 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7754 if (code == WAIT_TIMEOUT)
7756 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7759 if (code == WAIT_FAILED)
7761 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7764 idx_NCB = code - WAIT_OBJECT_0;
7766 /* check idx range! */
7767 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7769 /* this is fatal - log as much as possible */
7770 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7771 osi_assertx(0, "invalid index");
7774 ncbp = NCBs[idx_NCB];
7775 idx_session = NCBsessions[idx_NCB];
7776 rc = ncbp->ncb_retcode;
7778 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7779 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7783 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7787 /* Can this happen? Or is it just my UNIX paranoia? */
7788 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7793 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7796 /* Client closed session */
7797 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7799 lock_ObtainMutex(&vcp->mx);
7800 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7801 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7803 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7804 lock_ReleaseMutex(&vcp->mx);
7805 lock_ObtainWrite(&smb_globalLock);
7806 dead_sessions[vcp->session] = TRUE;
7807 lock_ReleaseWrite(&smb_globalLock);
7808 smb_CleanupDeadVC(vcp);
7812 lock_ReleaseMutex(&vcp->mx);
7818 /* Treat as transient error */
7819 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7822 "dispatch smb recv failed, message incomplete, ncb_length %d",
7825 "SMB message incomplete, "
7826 "length %d", ncbp->ncb_length);
7829 * We used to discard the packet.
7830 * Instead, try handling it normally.
7834 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7838 /* A weird error code. Log it, sleep, and continue. */
7839 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7841 lock_ObtainMutex(&vcp->mx);
7842 if (vcp && vcp->errorCount++ > 3) {
7843 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7844 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7845 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7847 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7848 lock_ReleaseMutex(&vcp->mx);
7849 lock_ObtainWrite(&smb_globalLock);
7850 dead_sessions[vcp->session] = TRUE;
7851 lock_ReleaseWrite(&smb_globalLock);
7852 smb_CleanupDeadVC(vcp);
7856 lock_ReleaseMutex(&vcp->mx);
7862 lock_ReleaseMutex(&vcp->mx);
7864 thrd_SetEvent(SessionEvents[idx_session]);
7869 /* Success, so now dispatch on all the data in the packet */
7871 smb_concurrentCalls++;
7872 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7873 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7876 * If at this point vcp is NULL (implies that packet was invalid)
7877 * then we are in big trouble. This means either :
7878 * a) we have the wrong NCB.
7879 * b) Netbios screwed up the call.
7880 * c) The VC was already marked dead before we were able to
7882 * Obviously this implies that
7883 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7884 * lanas[idx_session] != ncbp->ncb_lana_num )
7885 * Either way, we can't do anything with this packet.
7886 * Log, sleep and resume.
7889 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7893 ncbp->ncb_lana_num);
7895 /* Also log in the trace log. */
7896 osi_Log4(smb_logp, "Server: VCP does not exist!"
7897 "LSNs[idx_session]=[%d],"
7898 "lanas[idx_session]=[%d],"
7899 "ncbp->ncb_lsn=[%d],"
7900 "ncbp->ncb_lana_num=[%d]",
7904 ncbp->ncb_lana_num);
7906 /* thrd_Sleep(1000); Don't bother sleeping */
7907 thrd_SetEvent(SessionEvents[idx_session]);
7908 smb_concurrentCalls--;
7912 smb_SetRequestStartTime();
7914 vcp->errorCount = 0;
7915 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7916 smbp = (smb_t *)bufp->data;
7921 if (smbp->com == 0x1d) {
7922 /* Special handling for Write Raw */
7923 raw_write_cont_t rwc;
7924 EVENT_HANDLE rwevent;
7925 char eventName[MAX_PATH];
7927 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7928 if (rwc.code == 0) {
7929 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7930 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7931 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7932 ncbp->ncb_command = NCBRECV | ASYNCH;
7933 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7934 ncbp->ncb_lana_num = vcp->lana;
7935 ncbp->ncb_buffer = rwc.buf;
7936 ncbp->ncb_length = 65535;
7937 ncbp->ncb_event = rwevent;
7939 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7940 thrd_CloseHandle(rwevent);
7942 thrd_SetEvent(SessionEvents[idx_session]);
7944 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7946 else if (smbp->com == 0xa0) {
7948 * Serialize the handling for NT Transact
7951 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7952 thrd_SetEvent(SessionEvents[idx_session]);
7954 thrd_SetEvent(SessionEvents[idx_session]);
7955 /* TODO: what else needs to be serialized? */
7956 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7959 __except( smb_ServerExceptionFilter() ) {
7962 smb_concurrentCalls--;
7965 thrd_SetEvent(NCBavails[idx_NCB]);
7972 * Exception filter for the server threads. If an exception occurs in the
7973 * dispatch routines, which is where exceptions are most common, then do a
7974 * force trace and give control to upstream exception handlers. Useful for
7977 DWORD smb_ServerExceptionFilter(void) {
7978 /* While this is not the best time to do a trace, if it succeeds, then
7979 * we have a trace (assuming tracing was enabled). Otherwise, this should
7980 * throw a second exception.
7982 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7983 afsd_ForceTrace(TRUE);
7984 buf_ForceTrace(TRUE);
7985 return EXCEPTION_CONTINUE_SEARCH;
7989 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7990 * If the number of server threads is M, and the number of live sessions is
7991 * N, then the number of NCB's in use at any time either waiting for, or
7992 * holding, received messages is M + N, so that is how many NCB's get created.
7994 void InitNCBslot(int idx)
7996 struct smb_packet *bufp;
7997 EVENT_HANDLE retHandle;
7999 char eventName[MAX_PATH];
8001 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8003 NCBs[idx] = GetNCB();
8004 sprintf(eventName,"NCBavails[%d]", idx);
8005 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8006 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8007 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8008 sprintf(eventName,"NCBevents[%d]", idx);
8009 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8010 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8011 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8012 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8013 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8014 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8015 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8016 for (i=0; i<smb_NumServerThreads; i++)
8017 NCBreturns[i][idx] = retHandle;
8019 bufp->spacep = cm_GetSpace();
8023 /* listen for new connections */
8024 void smb_Listener(void *parmp)
8030 int session, thread;
8031 smb_vc_t *vcp = NULL;
8033 char rname[NCBNAMSZ+1];
8034 char cname[MAX_COMPUTERNAME_LENGTH+1];
8035 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8036 INT_PTR lana = (INT_PTR) parmp;
8040 /* retrieve computer name */
8041 GetComputerName(cname, &cnamelen);
8044 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8045 memset(ncbp, 0, sizeof(NCB));
8048 ncbp->ncb_command = NCBLISTEN;
8049 ncbp->ncb_rto = 0; /* No receive timeout */
8050 ncbp->ncb_sto = 0; /* No send timeout */
8052 /* pad out with spaces instead of null termination */
8053 len = (long)strlen(smb_localNamep);
8054 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8055 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8057 strcpy(ncbp->ncb_callname, "*");
8058 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8060 ncbp->ncb_lana_num = (UCHAR)lana;
8062 code = Netbios(ncbp);
8064 if (code == NRC_BRIDGE) {
8065 int lanaRemaining = 0;
8067 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
8072 "NCBLISTEN lana=%d failed with NRC_BRIDGE. Listener thread exiting.",
8073 ncbp->ncb_lana_num, code);
8075 for (i = 0; i < lana_list.length; i++) {
8076 if (lana_list.lana[i] == ncbp->ncb_lana_num) {
8077 smb_StopListener(ncbp, lana_list.lana[i]);
8078 lana_list.lana[i] = 255;
8080 if (lana_list.lana[i] != 255)
8084 if (lanaRemaining == 0) {
8085 cm_VolStatus_Network_Stopped(cm_NetbiosName
8090 smb_ListenerState = SMB_LISTENER_STOPPED;
8091 smb_LANadapter = -1;
8092 lana_list.length = 0;
8096 } else if (code != 0) {
8097 char tbuffer[AFSPATHMAX];
8099 /* terminate silently if shutdown flag is set */
8100 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
8105 "NCBLISTEN lana=%d failed with code %d",
8106 ncbp->ncb_lana_num, code);
8108 "Client exiting due to network failure. Please restart client.\n");
8111 "Client exiting due to network failure. Please restart client.\n"
8112 "NCBLISTEN lana=%d failed with code %d",
8113 ncbp->ncb_lana_num, code);
8115 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8116 MB_OK|MB_SERVICE_NOTIFICATION);
8117 osi_panic(tbuffer, __FILE__, __LINE__);
8120 /* check for remote conns */
8121 /* first get remote name and insert null terminator */
8122 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8123 for (i=NCBNAMSZ; i>0; i--) {
8124 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8130 /* compare with local name */
8132 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8133 flags |= SMB_VCFLAG_REMOTECONN;
8136 lock_ObtainMutex(&smb_ListenerLock);
8138 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8139 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8141 /* now ncbp->ncb_lsn is the connection ID */
8142 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8143 if (vcp->session == 0) {
8144 /* New generation */
8145 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8148 /* Log session startup */
8150 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8151 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8152 #endif /* NOTSERVICE */
8153 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8154 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8156 if (reportSessionStartups) {
8157 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8160 lock_ObtainMutex(&vcp->mx);
8161 strcpy(vcp->rname, rname);
8162 vcp->flags |= flags;
8163 lock_ReleaseMutex(&vcp->mx);
8165 /* Allocate slot in session arrays */
8166 /* Re-use dead session if possible, otherwise add one more */
8167 /* But don't look at session[0], it is reserved */
8168 lock_ObtainWrite(&smb_globalLock);
8169 for (session = 1; session < numSessions; session++) {
8170 if (dead_sessions[session]) {
8171 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8172 dead_sessions[session] = FALSE;
8176 lock_ReleaseWrite(&smb_globalLock);
8178 /* We are re-using an existing VC because the lsn and lana
8180 session = vcp->session;
8182 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8184 /* Log session startup */
8186 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8187 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8188 #endif /* NOTSERVICE */
8189 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8190 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8192 if (reportSessionStartups) {
8193 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8197 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8198 unsigned long code = CM_ERROR_ALLBUSY;
8199 smb_packet_t * outp = GetPacket();
8200 unsigned char *outWctp;
8203 smb_FormatResponsePacket(vcp, NULL, outp);
8206 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8207 unsigned long NTStatus;
8208 smb_MapNTError(code, &NTStatus);
8209 outWctp = outp->wctp;
8210 smbp = (smb_t *) &outp->data;
8214 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8215 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8216 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8217 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8218 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8220 unsigned short errCode;
8221 unsigned char errClass;
8222 smb_MapCoreError(code, vcp, &errCode, &errClass);
8223 outWctp = outp->wctp;
8224 smbp = (smb_t *) &outp->data;
8228 smbp->errLow = (unsigned char) (errCode & 0xff);
8229 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8230 smbp->rcls = errClass;
8232 smb_SendPacket(vcp, outp);
8233 smb_FreePacket(outp);
8235 lock_ObtainMutex(&vcp->mx);
8236 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8237 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8239 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8240 lock_ReleaseMutex(&vcp->mx);
8241 lock_ObtainWrite(&smb_globalLock);
8242 dead_sessions[vcp->session] = TRUE;
8243 lock_ReleaseWrite(&smb_globalLock);
8244 smb_CleanupDeadVC(vcp);
8246 lock_ReleaseMutex(&vcp->mx);
8249 /* assert that we do not exceed the maximum number of sessions or NCBs.
8250 * we should probably want to wait for a session to be freed in case
8253 osi_assertx(session < SESSION_MAX - 1, "invalid session");
8254 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
8256 lock_ObtainMutex(&vcp->mx);
8257 vcp->session = session;
8258 lock_ReleaseMutex(&vcp->mx);
8259 lock_ObtainWrite(&smb_globalLock);
8260 LSNs[session] = ncbp->ncb_lsn;
8261 lanas[session] = ncbp->ncb_lana_num;
8262 lock_ReleaseWrite(&smb_globalLock);
8264 if (session == numSessions) {
8265 /* Add new NCB for new session */
8266 char eventName[MAX_PATH];
8268 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8270 InitNCBslot(numNCBs);
8271 lock_ObtainWrite(&smb_globalLock);
8273 lock_ReleaseWrite(&smb_globalLock);
8274 thrd_SetEvent(NCBavails[0]);
8275 thrd_SetEvent(NCBevents[0]);
8276 for (thread = 0; thread < smb_NumServerThreads; thread++)
8277 thrd_SetEvent(NCBreturns[thread][0]);
8278 /* Also add new session event */
8279 sprintf(eventName, "SessionEvents[%d]", session);
8280 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8281 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8282 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8283 lock_ObtainWrite(&smb_globalLock);
8285 lock_ReleaseWrite(&smb_globalLock);
8286 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8287 thrd_SetEvent(SessionEvents[0]);
8289 thrd_SetEvent(SessionEvents[session]);
8295 lock_ReleaseMutex(&smb_ListenerLock);
8296 } /* dispatch while loop */
8301 /* initialize Netbios */
8302 int smb_NetbiosInit(void)
8305 int i, lana, code, l;
8307 int delname_tried=0;
8310 lana_number_t lanaNum;
8312 /* setup the NCB system */
8315 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8316 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8317 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8319 if (smb_LANadapter != -1)
8320 afsi_log("LAN adapter number %d", smb_LANadapter);
8322 afsi_log("LAN adapter number not determined");
8325 afsi_log("Set for gateway service");
8327 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8329 /* something went horribly wrong. We can't proceed without a netbios name */
8331 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8332 osi_panic(buf, __FILE__, __LINE__);
8335 /* remember the name */
8336 len = (int)strlen(cm_NetbiosName);
8338 free(smb_localNamep);
8339 smb_localNamep = malloc(len+1);
8340 strcpy(smb_localNamep, cm_NetbiosName);
8341 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8344 if (smb_LANadapter == -1) {
8345 ncbp->ncb_command = NCBENUM;
8346 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8347 ncbp->ncb_length = sizeof(lana_list);
8348 code = Netbios(ncbp);
8350 afsi_log("Netbios NCBENUM error code %d", code);
8351 osi_panic(s, __FILE__, __LINE__);
8355 lana_list.length = 1;
8356 lana_list.lana[0] = smb_LANadapter;
8359 for (i = 0; i < lana_list.length; i++) {
8360 /* reset the adaptor: in Win32, this is required for every process, and
8361 * acts as an init call, not as a real hardware reset.
8363 ncbp->ncb_command = NCBRESET;
8364 ncbp->ncb_callname[0] = 100;
8365 ncbp->ncb_callname[2] = 100;
8366 ncbp->ncb_lana_num = lana_list.lana[i];
8367 code = Netbios(ncbp);
8369 code = ncbp->ncb_retcode;
8371 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8372 lana_list.lana[i] = 255; /* invalid lana */
8374 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8378 /* and declare our name so we can receive connections */
8379 memset(ncbp, 0, sizeof(*ncbp));
8380 len=lstrlen(smb_localNamep);
8381 memset(smb_sharename,' ',NCBNAMSZ);
8382 memcpy(smb_sharename,smb_localNamep,len);
8383 afsi_log("lana_list.length %d", lana_list.length);
8385 /* Keep the name so we can unregister it later */
8386 for (l = 0; l < lana_list.length; l++) {
8387 lana = lana_list.lana[l];
8389 ncbp->ncb_command = NCBADDNAME;
8390 ncbp->ncb_lana_num = lana;
8391 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8392 code = Netbios(ncbp);
8394 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8395 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8397 char name[NCBNAMSZ+1];
8399 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8400 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8404 code = ncbp->ncb_retcode;
8407 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8410 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8411 if (code == NRC_BRIDGE) { /* invalid LANA num */
8412 lana_list.lana[l] = 255;
8415 else if (code == NRC_DUPNAME) {
8416 afsi_log("Name already exists; try to delete it");
8417 memset(ncbp, 0, sizeof(*ncbp));
8418 ncbp->ncb_command = NCBDELNAME;
8419 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8420 ncbp->ncb_lana_num = lana;
8421 code = Netbios(ncbp);
8423 code = ncbp->ncb_retcode;
8425 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8427 if (code != 0 || delname_tried) {
8428 lana_list.lana[l] = 255;
8430 else if (code == 0) {
8431 if (!delname_tried) {
8439 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8440 lana_list.lana[l] = 255; /* invalid lana */
8444 lana_found = 1; /* at least one worked */
8448 osi_assertx(lana_list.length >= 0, "empty lana list");
8450 afsi_log("No valid LANA numbers found!");
8451 lana_list.length = 0;
8452 smb_LANadapter = -1;
8453 smb_ListenerState = SMB_LISTENER_STOPPED;
8454 cm_VolStatus_Network_Stopped(cm_NetbiosName
8461 /* we're done with the NCB now */
8464 return (lana_list.length > 0 ? 1 : 0);
8467 void smb_StartListeners()
8473 if (smb_ListenerState == SMB_LISTENER_STARTED)
8476 smb_ListenerState = SMB_LISTENER_STARTED;
8477 cm_VolStatus_Network_Started(cm_NetbiosName
8483 for (i = 0; i < lana_list.length; i++) {
8484 if (lana_list.lana[i] == 255)
8486 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8487 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8488 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
8489 thrd_CloseHandle(phandle);
8493 void smb_RestartListeners()
8495 if (!powerStateSuspended && smb_ListenerState == SMB_LISTENER_STOPPED) {
8496 if (smb_NetbiosInit())
8497 smb_StartListeners();
8501 void smb_StopListener(NCB *ncbp, int lana)
8505 memset(ncbp, 0, sizeof(*ncbp));
8506 ncbp->ncb_command = NCBDELNAME;
8507 ncbp->ncb_lana_num = lana;
8508 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8509 code = Netbios(ncbp);
8511 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8512 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8514 /* and then reset the LANA; this will cause the listener threads to exit */
8515 ncbp->ncb_command = NCBRESET;
8516 ncbp->ncb_callname[0] = 100;
8517 ncbp->ncb_callname[2] = 100;
8518 ncbp->ncb_lana_num = lana;
8519 code = Netbios(ncbp);
8521 code = ncbp->ncb_retcode;
8523 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8525 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8529 void smb_StopListeners(void)
8534 if (smb_ListenerState == SMB_LISTENER_STOPPED)
8537 smb_ListenerState = SMB_LISTENER_STOPPED;
8538 cm_VolStatus_Network_Stopped(cm_NetbiosName
8546 /* Unregister the SMB name */
8547 for (l = 0; l < lana_list.length; l++) {
8548 lana = lana_list.lana[l];
8551 smb_StopListener(ncbp, lana);
8553 /* mark the adapter invalid */
8554 lana_list.lana[l] = 255; /* invalid lana */
8558 /* force a re-evaluation of the network adapters */
8559 lana_list.length = 0;
8560 smb_LANadapter = -1;
8562 Sleep(1000); /* give the listener threads a chance to exit */
8565 void smb_Init(osi_log_t *logp, int useV3,
8575 EVENT_HANDLE retHandle;
8576 char eventName[MAX_PATH];
8578 smb_TlsRequestSlot = TlsAlloc();
8580 smb_MBfunc = aMBfunc;
8584 /* Initialize smb_localZero */
8585 myTime.tm_isdst = -1; /* compute whether on DST or not */
8586 myTime.tm_year = 70;
8592 smb_localZero = mktime(&myTime);
8594 #ifndef USE_NUMERIC_TIME_CONV
8595 /* Initialize kludge-GMT */
8596 smb_CalculateNowTZ();
8597 #endif /* USE_NUMERIC_TIME_CONV */
8598 #ifdef AFS_FREELANCE_CLIENT
8599 /* Make sure the root.afs volume has the correct time */
8600 cm_noteLocalMountPointChange();
8603 /* initialize the remote debugging log */
8606 /* and the global lock */
8607 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8608 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8610 /* Raw I/O data structures */
8611 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8613 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8615 /* 4 Raw I/O buffers */
8616 smb_RawBufs = calloc(65536,1);
8617 *((char **)smb_RawBufs) = NULL;
8618 for (i=0; i<3; i++) {
8619 char *rawBuf = calloc(65536,1);
8620 *((char **)rawBuf) = smb_RawBufs;
8621 smb_RawBufs = rawBuf;
8624 /* global free lists */
8625 smb_ncbFreeListp = NULL;
8626 smb_packetFreeListp = NULL;
8630 /* Initialize listener and server structures */
8632 memset(dead_sessions, 0, sizeof(dead_sessions));
8633 sprintf(eventName, "SessionEvents[0]");
8634 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8635 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8636 afsi_log("Event Object Already Exists: %s", eventName);
8638 smb_NumServerThreads = nThreads;
8639 sprintf(eventName, "NCBavails[0]");
8640 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8641 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8642 afsi_log("Event Object Already Exists: %s", eventName);
8643 sprintf(eventName, "NCBevents[0]");
8644 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8645 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8646 afsi_log("Event Object Already Exists: %s", eventName);
8647 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8648 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8649 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8650 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8651 afsi_log("Event Object Already Exists: %s", eventName);
8652 for (i = 0; i < smb_NumServerThreads; i++) {
8653 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8654 NCBreturns[i][0] = retHandle;
8657 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8658 for (i = 0; i < smb_NumServerThreads; i++) {
8659 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8660 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8661 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8662 afsi_log("Event Object Already Exists: %s", eventName);
8663 InitNCBslot((int)(i+1));
8665 numNCBs = smb_NumServerThreads + 1;
8667 /* Initialize dispatch table */
8668 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8669 /* Prepare the table for unknown operations */
8670 for(i=0; i<= SMB_NOPCODES; i++) {
8671 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8673 /* Fill in the ones we do know */
8674 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8675 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8676 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8677 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8678 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8679 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8680 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8681 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8682 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8683 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8684 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8685 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8686 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8687 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8688 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8689 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8690 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8691 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8692 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8693 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8694 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8695 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8696 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8697 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8698 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8699 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8700 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8701 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8702 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8703 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8704 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8705 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8706 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8707 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8708 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8709 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8710 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8711 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8712 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8713 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8714 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8715 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8716 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8717 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8718 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8719 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8720 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8721 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8722 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8723 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8724 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8725 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8726 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8727 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8728 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8729 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8730 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8731 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8732 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8733 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8734 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8735 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8736 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8737 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8738 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8739 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8740 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8741 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8742 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8743 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8744 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8745 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8746 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8747 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8749 /* setup tran 2 dispatch table */
8750 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8751 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8752 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8753 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8754 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8755 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8756 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8757 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8758 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8759 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8760 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8761 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8762 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8763 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8764 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8765 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8766 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8767 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8769 /* setup the rap dispatch table */
8770 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8771 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8772 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8773 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8774 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8778 /* if we are doing SMB authentication we have register outselves as a logon process */
8779 if (smb_authType != SMB_AUTH_NONE) {
8780 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8781 LSA_STRING afsProcessName;
8782 LSA_OPERATIONAL_MODE dummy; /*junk*/
8784 afsProcessName.Buffer = "OpenAFSClientDaemon";
8785 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8786 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8788 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8790 if (nts == STATUS_SUCCESS) {
8791 LSA_STRING packageName;
8792 /* we are registered. Find out the security package id */
8793 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8794 packageName.Length = (USHORT)strlen(packageName.Buffer);
8795 packageName.MaximumLength = packageName.Length + 1;
8796 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8797 if (nts == STATUS_SUCCESS) {
8799 * This code forces Windows to authenticate against the Logon Cache
8800 * first instead of attempting to authenticate against the Domain
8801 * Controller. When the Windows logon cache is enabled this improves
8802 * performance by removing the network access and works around a bug
8803 * seen at sites which are using a MIT Kerberos principal to login
8804 * to machines joined to a non-root domain in a multi-domain forest.
8805 * MsV1_0SetProcessOption was added in Windows XP.
8807 PVOID pResponse = NULL;
8808 ULONG cbResponse = 0;
8809 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8811 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8812 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8813 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8814 OptionsRequest.DisableOptions = FALSE;
8816 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8819 sizeof(OptionsRequest),
8825 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8826 char message[AFSPATHMAX];
8827 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8829 OutputDebugString(message);
8832 OutputDebugString("MsV1_0SetProcessOption success");
8833 afsi_log("MsV1_0SetProcessOption success");
8835 /* END - code from Larry */
8837 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8838 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8839 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8841 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8843 /* something went wrong. We report the error and revert back to no authentication
8844 because we can't perform any auth requests without a successful lsa handle
8845 or sec package id. */
8846 afsi_log("Reverting to NO SMB AUTH");
8847 smb_authType = SMB_AUTH_NONE;
8850 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8852 /* something went wrong. We report the error and revert back to no authentication
8853 because we can't perform any auth requests without a successful lsa handle
8854 or sec package id. */
8855 afsi_log("Reverting to NO SMB AUTH");
8856 smb_authType = SMB_AUTH_NONE;
8860 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8861 * time prevents the failure of authentication when logged into Windows with an
8862 * external Kerberos principal mapped to a local account.
8864 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8865 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8866 * then the only option is NTLMSSP anyway; so just fallback.
8871 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8872 if (secBlobLength == 0) {
8873 smb_authType = SMB_AUTH_NTLM;
8874 afsi_log("Reverting to SMB AUTH NTLM");
8883 /* Now get ourselves a domain name. */
8884 /* For now we are using the local computer name as the domain name.
8885 * It is actually the domain for local logins, and we are acting as
8886 * a local SMB server.
8888 bufsize = sizeof(smb_ServerDomainName) - 1;
8889 GetComputerName(smb_ServerDomainName, &bufsize);
8890 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8891 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8894 /* Start listeners, waiters, servers, and daemons */
8896 smb_StartListeners();
8898 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8899 NULL, 0, &lpid, "smb_ClientWaiter");
8900 osi_assertx(phandle != NULL, , "smb_ClientWaiter thread creation failure");
8901 thrd_CloseHandle(phandle);
8903 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8904 NULL, 0, &lpid, "smb_ServerWaiter");
8905 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
8906 thrd_CloseHandle(phandle);
8908 for (i=0; i<smb_NumServerThreads; i++) {
8909 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8910 (void *) i, 0, &lpid, "smb_Server");
8911 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
8912 thrd_CloseHandle(phandle);
8915 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8916 NULL, 0, &lpid, "smb_Daemon");
8917 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
8918 thrd_CloseHandle(phandle);
8920 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8921 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8922 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
8923 thrd_CloseHandle(phandle);
8928 void smb_Shutdown(void)
8935 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8937 /* setup the NCB system */
8940 /* Block new sessions by setting shutdown flag */
8941 smbShutdownFlag = 1;
8943 /* Hang up all sessions */
8944 memset((char *)ncbp, 0, sizeof(NCB));
8945 for (i = 1; i < numSessions; i++)
8947 if (dead_sessions[i])
8950 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8951 ncbp->ncb_command = NCBHANGUP;
8952 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8953 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8954 code = Netbios(ncbp);
8955 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8956 if (code == 0) code = ncbp->ncb_retcode;
8958 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8959 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8963 /* Trigger the shutdown of all SMB threads */
8964 for (i = 0; i < smb_NumServerThreads; i++)
8965 thrd_SetEvent(NCBreturns[i][0]);
8967 thrd_SetEvent(NCBevents[0]);
8968 thrd_SetEvent(SessionEvents[0]);
8969 thrd_SetEvent(NCBavails[0]);
8971 for (i = 0;i < smb_NumServerThreads; i++) {
8972 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8973 if (code == WAIT_OBJECT_0) {
8976 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8977 thrd_SetEvent(NCBreturns[i--][0]);
8981 /* Delete Netbios name */
8982 memset((char *)ncbp, 0, sizeof(NCB));
8983 for (i = 0; i < lana_list.length; i++) {
8984 if (lana_list.lana[i] == 255) continue;
8985 ncbp->ncb_command = NCBDELNAME;
8986 ncbp->ncb_lana_num = lana_list.lana[i];
8987 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8988 code = Netbios(ncbp);
8990 code = ncbp->ncb_retcode;
8992 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8993 ncbp->ncb_lana_num, code);
8998 /* Release the reference counts held by the VCs */
8999 lock_ObtainWrite(&smb_rctLock);
9000 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9005 if (vcp->magic != SMB_VC_MAGIC)
9006 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9007 __FILE__, __LINE__);
9009 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9011 if (fidp->scp != NULL) {
9014 lock_ObtainMutex(&fidp->mx);
9015 if (fidp->scp != NULL) {
9018 lock_ObtainMutex(&scp->mx);
9019 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9020 lock_ReleaseMutex(&scp->mx);
9021 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9022 cm_ReleaseSCache(scp);
9024 lock_ReleaseMutex(&fidp->mx);
9028 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9030 smb_ReleaseVCNoLock(tidp->vcp);
9032 cm_user_t *userp = tidp->userp;
9034 lock_ReleaseWrite(&smb_rctLock);
9035 cm_ReleaseUser(userp);
9036 lock_ObtainWrite(&smb_rctLock);
9040 lock_ReleaseWrite(&smb_rctLock);
9042 TlsFree(smb_TlsRequestSlot);
9045 /* Get the UNC \\<servername>\<sharename> prefix. */
9046 char *smb_GetSharename()
9050 /* Make sure we have been properly initialized. */
9051 if (smb_localNamep == NULL)
9054 /* Allocate space for \\<servername>\<sharename>, plus the
9057 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
9058 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
9064 void smb_LogPacket(smb_packet_t *packet)
9067 unsigned length, paramlen, datalen, i, j;
9069 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9071 if (!packet) return;
9073 osi_Log0(smb_logp, "*** SMB packet dump ***");
9075 vp = (BYTE *) packet->data;
9077 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
9078 length = paramlen + 2 + datalen;
9081 for (i=0;i < length; i+=16)
9083 memset( buf, ' ', 80 );
9088 buf[strlen(buf)] = ' ';
9090 cp = (BYTE*) buf + 7;
9092 for (j=0;j < 16 && (i+j)<length; j++)
9094 *(cp++) = hex[vp[i+j] >> 4];
9095 *(cp++) = hex[vp[i+j] & 0xf];
9105 for (j=0;j < 16 && (i+j)<length;j++)
9107 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9118 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9121 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9123 #endif /* LOG_PACKET */
9126 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9134 lock_ObtainRead(&smb_rctLock);
9136 sprintf(output, "begin dumping smb_vc_t\r\n");
9137 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9139 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9143 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9144 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9145 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9147 sprintf(output, "begin dumping smb_fid_t\r\n");
9148 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9150 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9152 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n",
9153 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9154 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9155 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9156 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9159 sprintf(output, "done dumping smb_fid_t\r\n");
9160 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9163 sprintf(output, "done dumping smb_vc_t\r\n");
9164 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9166 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9167 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9169 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9173 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9174 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9175 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9177 sprintf(output, "begin dumping smb_fid_t\r\n");
9178 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9180 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9182 sprintf(output, "%s -- smb_fidp=0x%p, refCount=%d, fid=%d, vcp=0x%p, scp=0x%p, ioctlp=0x%p, NTopen_pathp=%s, NTopen_wholepathp=%s\r\n",
9183 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9184 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9185 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9186 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9189 sprintf(output, "done dumping smb_fid_t\r\n");
9190 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9193 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9194 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9197 lock_ReleaseRead(&smb_rctLock);
9201 long smb_IsNetworkStarted(void)
9203 return (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);