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;
844 ULONG lsaRespSize = 0;
846 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
848 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
855 if (nts != 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 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
860 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
861 LsaFreeReturnBuffer(lsaResp);
864 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
866 if (numVCs >= CM_SESSION_RESERVED) {
868 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
871 lock_ReleaseWrite(&smb_rctLock);
872 lock_ReleaseWrite(&smb_globalLock);
876 int smb_IsStarMask(char *maskp)
881 for(i=0; i<11; i++) {
883 if (tc == '?' || tc == '*' || tc == '>')
889 void smb_ReleaseVCInternal(smb_vc_t *vcp)
896 if (vcp->refCount == 0) {
897 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
898 /* remove VCP from smb_deadVCsp */
899 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
905 lock_FinalizeMutex(&vcp->mx);
906 memset(vcp,0,sizeof(smb_vc_t));
909 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
913 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
914 avcp?"not ":"",vcp, vcp->refCount);
916 GenerateMiniDump(NULL);
918 /* This is a wrong. However, I suspect that there is an undercount
919 * and I don't want to release 1.4.1 in a state that will allow
920 * smb_vc_t objects to be deallocated while still in the
921 * smb_allVCsp list. The list is supposed to keep a reference
922 * to the smb_vc_t. Put it back.
929 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
931 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
932 smb_ReleaseVCInternal(vcp);
935 void smb_ReleaseVC(smb_vc_t *vcp)
937 lock_ObtainWrite(&smb_rctLock);
938 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
939 smb_ReleaseVCInternal(vcp);
940 lock_ReleaseWrite(&smb_rctLock);
943 void smb_HoldVCNoLock(smb_vc_t *vcp)
946 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
949 void smb_HoldVC(smb_vc_t *vcp)
951 lock_ObtainWrite(&smb_rctLock);
953 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
954 lock_ReleaseWrite(&smb_rctLock);
957 void smb_CleanupDeadVC(smb_vc_t *vcp)
965 smb_user_t *uidpIter;
966 smb_user_t *uidpNext;
970 lock_ObtainMutex(&vcp->mx);
971 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
972 lock_ReleaseMutex(&vcp->mx);
973 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
976 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
977 lock_ReleaseMutex(&vcp->mx);
978 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
980 lock_ObtainWrite(&smb_rctLock);
981 /* remove VCP from smb_allVCsp */
982 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
983 if ((*vcpp)->magic != SMB_VC_MAGIC)
984 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
988 vcp->nextp = smb_deadVCsp;
990 /* Hold onto the reference until we are done with this function */
995 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
996 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
998 if (fidpIter->delete)
1001 fid = fidpIter->fid;
1002 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1004 smb_HoldFIDNoLock(fidpIter);
1005 lock_ReleaseWrite(&smb_rctLock);
1007 smb_CloseFID(vcp, fidpIter, NULL, 0);
1008 smb_ReleaseFID(fidpIter);
1010 lock_ObtainWrite(&smb_rctLock);
1011 fidpNext = vcp->fidsp;
1014 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1015 tidpNext = tidpIter->nextp;
1016 if (tidpIter->delete)
1018 tidpIter->delete = 1;
1020 tid = tidpIter->tid;
1021 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1023 smb_HoldTIDNoLock(tidpIter);
1024 lock_ReleaseWrite(&smb_rctLock);
1026 smb_ReleaseTID(tidpIter);
1028 lock_ObtainWrite(&smb_rctLock);
1029 tidpNext = vcp->tidsp;
1032 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1033 uidpNext = uidpIter->nextp;
1034 if (uidpIter->delete)
1036 uidpIter->delete = 1;
1038 /* do not add an additional reference count for the smb_user_t
1039 * as the smb_vc_t already is holding a reference */
1040 lock_ReleaseWrite(&smb_rctLock);
1042 smb_ReleaseUID(uidpIter);
1044 lock_ObtainWrite(&smb_rctLock);
1045 uidpNext = vcp->usersp;
1048 /* The vcp is now on the deadVCsp list. We intentionally drop the
1049 * reference so that the refcount can reach 0 and we can delete it */
1050 smb_ReleaseVCNoLock(vcp);
1052 lock_ReleaseWrite(&smb_rctLock);
1053 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1056 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1060 lock_ObtainWrite(&smb_rctLock);
1062 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1063 if (tidp->refCount == 0 && tidp->delete) {
1065 lock_ReleaseWrite(&smb_rctLock);
1066 smb_ReleaseTID(tidp);
1067 lock_ObtainWrite(&smb_rctLock);
1071 if (tid == tidp->tid) {
1076 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1077 tidp = malloc(sizeof(*tidp));
1078 memset(tidp, 0, sizeof(*tidp));
1079 tidp->nextp = vcp->tidsp;
1082 smb_HoldVCNoLock(vcp);
1084 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1087 lock_ReleaseWrite(&smb_rctLock);
1091 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1096 void smb_ReleaseTID(smb_tid_t *tidp)
1103 lock_ObtainWrite(&smb_rctLock);
1104 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1105 if (tidp->refCount == 0 && (tidp->delete)) {
1106 ltpp = &tidp->vcp->tidsp;
1107 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1111 osi_assertx(tp != NULL, "null smb_tid_t");
1113 lock_FinalizeMutex(&tidp->mx);
1114 userp = tidp->userp; /* remember to drop ref later */
1116 smb_ReleaseVCNoLock(tidp->vcp);
1119 lock_ReleaseWrite(&smb_rctLock);
1121 cm_ReleaseUser(userp);
1124 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1126 smb_user_t *uidp = NULL;
1128 lock_ObtainWrite(&smb_rctLock);
1129 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1130 if (uid == uidp->userID) {
1132 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1134 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1138 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1139 uidp = malloc(sizeof(*uidp));
1140 memset(uidp, 0, sizeof(*uidp));
1141 uidp->nextp = vcp->usersp;
1142 uidp->refCount = 2; /* one for the vcp and one for the caller */
1144 smb_HoldVCNoLock(vcp);
1146 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1148 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1150 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1152 lock_ReleaseWrite(&smb_rctLock);
1156 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1158 smb_username_t *unp= NULL;
1160 lock_ObtainWrite(&smb_rctLock);
1161 for(unp = usernamesp; unp; unp = unp->nextp) {
1162 if (stricmp(unp->name, usern) == 0 &&
1163 stricmp(unp->machine, machine) == 0) {
1168 if (!unp && (flags & SMB_FLAG_CREATE)) {
1169 unp = malloc(sizeof(*unp));
1170 memset(unp, 0, sizeof(*unp));
1172 unp->nextp = usernamesp;
1173 unp->name = strdup(usern);
1174 unp->machine = strdup(machine);
1176 lock_InitializeMutex(&unp->mx, "username_t mutex");
1177 if (flags & SMB_FLAG_AFSLOGON)
1178 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1181 lock_ReleaseWrite(&smb_rctLock);
1185 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1187 smb_user_t *uidp= NULL;
1189 lock_ObtainWrite(&smb_rctLock);
1190 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1193 if (stricmp(uidp->unp->name, usern) == 0) {
1195 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1196 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1201 lock_ReleaseWrite(&smb_rctLock);
1205 void smb_ReleaseUsername(smb_username_t *unp)
1208 smb_username_t **lupp;
1209 cm_user_t *userp = NULL;
1210 time_t now = osi_Time();
1212 lock_ObtainWrite(&smb_rctLock);
1213 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1214 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1215 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1217 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1221 osi_assertx(up != NULL, "null smb_username_t");
1223 up->nextp = NULL; /* do not remove this */
1224 lock_FinalizeMutex(&unp->mx);
1230 lock_ReleaseWrite(&smb_rctLock);
1233 cm_ReleaseUser(userp);
1237 void smb_HoldUIDNoLock(smb_user_t *uidp)
1242 void smb_ReleaseUID(smb_user_t *uidp)
1246 smb_username_t *unp = NULL;
1248 lock_ObtainWrite(&smb_rctLock);
1249 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1250 if (uidp->refCount == 0) {
1251 lupp = &uidp->vcp->usersp;
1252 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1256 osi_assertx(up != NULL, "null smb_user_t");
1258 lock_FinalizeMutex(&uidp->mx);
1260 smb_ReleaseVCNoLock(uidp->vcp);
1264 lock_ReleaseWrite(&smb_rctLock);
1268 cm_ReleaseUserVCRef(unp->userp);
1269 smb_ReleaseUsername(unp);
1273 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1275 cm_user_t *up = NULL;
1280 lock_ObtainMutex(&uidp->mx);
1282 up = uidp->unp->userp;
1285 lock_ReleaseMutex(&uidp->mx);
1291 /* retrieve a held reference to a user structure corresponding to an incoming
1293 * corresponding release function is cm_ReleaseUser.
1295 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1298 cm_user_t *up = NULL;
1301 smbp = (smb_t *) inp;
1302 uidp = smb_FindUID(vcp, smbp->uid, 0);
1306 up = smb_GetUserFromUID(uidp);
1308 smb_ReleaseUID(uidp);
1313 * Return a pointer to a pathname extracted from a TID structure. The
1314 * TID structure is not held; assume it won't go away.
1316 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1321 tidp = smb_FindTID(vcp, tid, 0);
1325 if (tidp->flags & SMB_TIDFLAG_IPC) {
1326 code = CM_ERROR_TIDIPC;
1327 /* tidp->pathname would be NULL, but that's fine */
1329 *treepath = tidp->pathname;
1330 smb_ReleaseTID(tidp);
1335 /* check to see if we have a chained fid, that is, a fid that comes from an
1336 * OpenAndX message that ran earlier in this packet. In this case, the fid
1337 * field in a read, for example, request, isn't set, since the value is
1338 * supposed to be inherited from the openAndX call.
1340 int smb_ChainFID(int fid, smb_packet_t *inp)
1342 if (inp->fid == 0 || inp->inCount == 0)
1348 /* are we a priv'd user? What does this mean on NT? */
1349 int smb_SUser(cm_user_t *userp)
1354 /* find a file ID. If we pass in 0 we select an unused File ID.
1355 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1356 * smb_fid_t data structure if desired File ID cannot be found.
1358 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1363 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1366 lock_ObtainWrite(&smb_rctLock);
1367 /* figure out if we need to allocate a new file ID */
1370 fid = vcp->fidCounter;
1374 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1375 if (fidp->refCount == 0 && fidp->delete) {
1377 lock_ReleaseWrite(&smb_rctLock);
1378 smb_ReleaseFID(fidp);
1379 lock_ObtainWrite(&smb_rctLock);
1382 if (fid == fidp->fid) {
1385 if (fid == 0xFFFF) {
1387 "New FID number wraps on vcp 0x%x", vcp);
1397 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1398 char eventName[MAX_PATH];
1400 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1401 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1402 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1403 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1404 thrd_CloseHandle(event);
1406 if (fid == 0xFFFF) {
1407 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1413 fidp = malloc(sizeof(*fidp));
1414 memset(fidp, 0, sizeof(*fidp));
1415 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1418 smb_HoldVCNoLock(vcp);
1419 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1421 fidp->curr_chunk = fidp->prev_chunk = -2;
1422 fidp->raw_write_event = event;
1424 vcp->fidCounter = fid+1;
1425 if (vcp->fidCounter == 0xFFFF) {
1426 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1428 vcp->fidCounter = 1;
1433 lock_ReleaseWrite(&smb_rctLock);
1437 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1439 smb_fid_t *fidp = NULL;
1445 lock_ObtainWrite(&smb_rctLock);
1446 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1447 if (scp == fidp->scp) {
1452 lock_ReleaseWrite(&smb_rctLock);
1456 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1462 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1463 /* the sm_fid_t->mx and smb_rctLock must not be held */
1464 void smb_ReleaseFID(smb_fid_t *fidp)
1466 cm_scache_t *scp = NULL;
1467 cm_user_t *userp = NULL;
1468 smb_vc_t *vcp = NULL;
1469 smb_ioctl_t *ioctlp;
1471 lock_ObtainMutex(&fidp->mx);
1472 lock_ObtainWrite(&smb_rctLock);
1473 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1474 if (fidp->refCount == 0 && (fidp->delete)) {
1477 scp = fidp->scp; /* release after lock is released */
1479 lock_ObtainMutex(&scp->mx);
1480 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1481 lock_ReleaseMutex(&scp->mx);
1482 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1485 userp = fidp->userp;
1489 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1490 thrd_CloseHandle(fidp->raw_write_event);
1492 /* and see if there is ioctl stuff to free */
1493 ioctlp = fidp->ioctlp;
1496 cm_FreeSpace(ioctlp->prefix);
1497 if (ioctlp->inAllocp)
1498 free(ioctlp->inAllocp);
1499 if (ioctlp->outAllocp)
1500 free(ioctlp->outAllocp);
1503 lock_ReleaseMutex(&fidp->mx);
1504 lock_FinalizeMutex(&fidp->mx);
1508 smb_ReleaseVCNoLock(vcp);
1510 lock_ReleaseMutex(&fidp->mx);
1512 lock_ReleaseWrite(&smb_rctLock);
1514 /* now release the scache structure */
1516 cm_ReleaseSCache(scp);
1519 cm_ReleaseUser(userp);
1523 * Case-insensitive search for one string in another;
1524 * used to find variable names in submount pathnames.
1526 static char *smb_stristr(char *str1, char *str2)
1530 for (cursor = str1; *cursor; cursor++)
1531 if (stricmp(cursor, str2) == 0)
1538 * Substitute a variable value for its name in a submount pathname. Variable
1539 * name has been identified by smb_stristr() and is in substr. Variable name
1540 * length (plus one) is in substr_size. Variable value is in newstr.
1542 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1547 strcpy(temp, substr + substr_size - 1);
1548 strcpy(substr, newstr);
1552 char VNUserName[] = "%USERNAME%";
1553 char VNLCUserName[] = "%LCUSERNAME%";
1554 char VNComputerName[] = "%COMPUTERNAME%";
1555 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1558 typedef struct smb_findShare_rock {
1562 } smb_findShare_rock_t;
1564 #define SMB_FINDSHARE_EXACT_MATCH 1
1565 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1567 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1571 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1572 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1573 if(!stricmp(dep->name, vrock->shareName))
1574 matchType = SMB_FINDSHARE_EXACT_MATCH;
1576 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1577 if(vrock->match) free(vrock->match);
1578 vrock->match = strdup(dep->name);
1579 vrock->matchType = matchType;
1581 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1582 return CM_ERROR_STOPNOW;
1588 /* find a shareName in the table of submounts */
1589 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1593 char pathName[1024];
1600 DWORD allSubmount = 1;
1602 /* if allSubmounts == 0, only return the //mountRoot/all share
1603 * if in fact it has been been created in the subMounts table.
1604 * This is to allow sites that want to restrict access to the
1607 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1608 0, KEY_QUERY_VALUE, &parmKey);
1609 if (code == ERROR_SUCCESS) {
1610 len = sizeof(allSubmount);
1611 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1612 (BYTE *) &allSubmount, &len);
1613 if (code != ERROR_SUCCESS) {
1616 RegCloseKey (parmKey);
1619 if (allSubmount && _stricmp(shareName, "all") == 0) {
1624 /* In case, the all share is disabled we need to still be able
1625 * to handle ioctl requests
1627 if (_stricmp(shareName, "ioctl$") == 0) {
1628 *pathNamep = strdup("/.__ioctl__");
1632 if (_stricmp(shareName, "IPC$") == 0 ||
1633 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1634 _stricmp(shareName, "DESKTOP.INI") == 0
1640 /* Check for volume references
1642 * They look like <cell>{%,#}<volume>
1644 if (strchr(shareName, '%') != NULL ||
1645 strchr(shareName, '#') != NULL) {
1646 char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1647 /* make room for '/@vol:' + mountchar + NULL terminator*/
1649 osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1650 osi_LogSaveString(smb_logp, shareName));
1652 snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1653 "/" CM_PREFIX_VOL "%s", shareName);
1654 pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1655 len = strlen(pathstr) + 1;
1657 *pathNamep = malloc(len);
1659 strcpy(*pathNamep, pathstr);
1661 osi_Log1(smb_logp, " returning pathname [%s]",
1662 osi_LogSaveString(smb_logp, *pathNamep));
1670 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1671 0, KEY_QUERY_VALUE, &parmKey);
1672 if (code == ERROR_SUCCESS) {
1673 len = sizeof(pathName);
1674 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1675 (BYTE *) pathName, &len);
1676 if (code != ERROR_SUCCESS)
1678 RegCloseKey (parmKey);
1682 if (len != 0 && len != sizeof(pathName) - 1) {
1683 /* We can accept either unix or PC style AFS pathnames. Convert
1684 * Unix-style to PC style here for internal use.
1687 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1688 p += strlen(cm_mountRoot); /* skip mount path */
1691 if (*q == '/') *q = '\\'; /* change to \ */
1697 if (var = smb_stristr(p, VNUserName)) {
1698 if (uidp && uidp->unp)
1699 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1701 smb_subst(p, var, sizeof(VNUserName)," ");
1703 else if (var = smb_stristr(p, VNLCUserName))
1705 if (uidp && uidp->unp)
1706 strcpy(temp, uidp->unp->name);
1710 smb_subst(p, var, sizeof(VNLCUserName), temp);
1712 else if (var = smb_stristr(p, VNComputerName))
1714 sizeTemp = sizeof(temp);
1715 GetComputerName((LPTSTR)temp, &sizeTemp);
1716 smb_subst(p, var, sizeof(VNComputerName), temp);
1718 else if (var = smb_stristr(p, VNLCComputerName))
1720 sizeTemp = sizeof(temp);
1721 GetComputerName((LPTSTR)temp, &sizeTemp);
1723 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1728 *pathNamep = strdup(p);
1733 /* First lookup shareName in root.afs */
1735 smb_findShare_rock_t vrock;
1737 char * p = shareName;
1740 /* attempt to locate a partial match in root.afs. This is because
1741 when using the ANSI RAP calls, the share name is limited to 13 chars
1742 and hence is truncated. Of course we prefer exact matches. */
1744 thyper.HighPart = 0;
1747 vrock.shareName = shareName;
1749 vrock.matchType = 0;
1751 cm_HoldSCache(cm_data.rootSCachep);
1752 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1753 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1754 cm_ReleaseSCache(cm_data.rootSCachep);
1756 if (vrock.matchType) {
1757 sprintf(pathName,"/%s/",vrock.match);
1758 *pathNamep = strdup(strlwr(pathName));
1763 /* if we get here, there was no match for the share in root.afs */
1764 /* so try to create \\<netbiosName>\<cellname> */
1769 /* Get the full name for this cell */
1770 code = cm_SearchCellFile(p, temp, 0, 0);
1771 #ifdef AFS_AFSDB_ENV
1772 if (code && cm_dnsEnabled) {
1774 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1777 /* construct the path */
1779 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1780 *pathNamep = strdup(strlwr(pathName));
1789 /* Client-side offline caching policy types */
1790 #define CSC_POLICY_MANUAL 0
1791 #define CSC_POLICY_DOCUMENTS 1
1792 #define CSC_POLICY_PROGRAMS 2
1793 #define CSC_POLICY_DISABLE 3
1795 int smb_FindShareCSCPolicy(char *shareName)
1801 int retval = CSC_POLICY_MANUAL;
1803 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1804 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1807 REG_OPTION_NON_VOLATILE,
1813 len = sizeof(policy);
1814 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1816 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1818 else if (stricmp(policy, "documents") == 0)
1820 retval = CSC_POLICY_DOCUMENTS;
1822 else if (stricmp(policy, "programs") == 0)
1824 retval = CSC_POLICY_PROGRAMS;
1826 else if (stricmp(policy, "disable") == 0)
1828 retval = CSC_POLICY_DISABLE;
1831 RegCloseKey(hkCSCPolicy);
1835 /* find a dir search structure by cookie value, and return it held.
1836 * Must be called with smb_globalLock held.
1838 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1840 smb_dirSearch_t *dsp;
1842 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1843 if (dsp->cookie == cookie) {
1844 if (dsp != smb_firstDirSearchp) {
1845 /* move to head of LRU queue, too, if we're not already there */
1846 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1847 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1848 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1849 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1850 if (!smb_lastDirSearchp)
1851 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1853 lock_ObtainMutex(&dsp->mx);
1855 lock_ReleaseMutex(&dsp->mx);
1861 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1862 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1863 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1869 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1871 lock_ObtainWrite(&smb_globalLock);
1872 lock_ObtainMutex(&dsp->mx);
1873 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1874 dsp->cookie, dsp, dsp->scp);
1875 dsp->flags |= SMB_DIRSEARCH_DELETE;
1876 if (dsp->scp != NULL) {
1877 lock_ObtainMutex(&dsp->scp->mx);
1878 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1879 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1880 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1881 dsp->scp->bulkStatProgress = hzero;
1883 lock_ReleaseMutex(&dsp->scp->mx);
1885 lock_ReleaseMutex(&dsp->mx);
1886 lock_ReleaseWrite(&smb_globalLock);
1889 /* Must be called with the smb_globalLock held */
1890 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1892 cm_scache_t *scp = NULL;
1894 lock_ObtainMutex(&dsp->mx);
1895 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1896 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1897 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1898 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1899 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1900 lock_ReleaseMutex(&dsp->mx);
1901 lock_FinalizeMutex(&dsp->mx);
1903 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1904 dsp->cookie, dsp, scp);
1907 lock_ReleaseMutex(&dsp->mx);
1909 /* do this now to avoid spurious locking hierarchy creation */
1911 cm_ReleaseSCache(scp);
1914 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1916 lock_ObtainWrite(&smb_globalLock);
1917 smb_ReleaseDirSearchNoLock(dsp);
1918 lock_ReleaseWrite(&smb_globalLock);
1921 /* find a dir search structure by cookie value, and return it held */
1922 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1924 smb_dirSearch_t *dsp;
1926 lock_ObtainWrite(&smb_globalLock);
1927 dsp = smb_FindDirSearchNoLock(cookie);
1928 lock_ReleaseWrite(&smb_globalLock);
1932 /* GC some dir search entries, in the address space expected by the specific protocol.
1933 * Must be called with smb_globalLock held; release the lock temporarily.
1935 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1936 void smb_GCDirSearches(int isV3)
1938 smb_dirSearch_t *prevp;
1939 smb_dirSearch_t *tp;
1940 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1944 victimCount = 0; /* how many have we got so far */
1945 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1946 /* we'll move tp from queue, so
1949 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1950 /* if no one is using this guy, and we're either in the new protocol,
1951 * or we're in the old one and this is a small enough ID to be useful
1952 * to the old protocol, GC this guy.
1954 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1955 /* hold and delete */
1956 lock_ObtainMutex(&tp->mx);
1957 tp->flags |= SMB_DIRSEARCH_DELETE;
1958 lock_ReleaseMutex(&tp->mx);
1959 victimsp[victimCount++] = tp;
1963 /* don't do more than this */
1964 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1968 /* now release them */
1969 for (i = 0; i < victimCount; i++) {
1970 smb_ReleaseDirSearchNoLock(victimsp[i]);
1974 /* function for allocating a dir search entry. We need these to remember enough context
1975 * since we don't get passed the path from call to call during a directory search.
1977 * Returns a held dir search structure, and bumps the reference count on the vnode,
1978 * since it saves a pointer to the vnode.
1980 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1982 smb_dirSearch_t *dsp;
1988 lock_ObtainWrite(&smb_globalLock);
1991 /* what's the biggest ID allowed in this version of the protocol */
1992 /* TODO: do we really want a non v3 dir search request to wrap
1993 smb_dirSearchCounter? */
1994 maxAllowed = isV3 ? 65535 : 255;
1995 if (smb_dirSearchCounter > maxAllowed)
1996 smb_dirSearchCounter = 1;
1998 start = smb_dirSearchCounter;
2001 /* twice so we have enough tries to find guys we GC after one pass;
2002 * 10 extra is just in case I mis-counted.
2004 if (++counter > 2*maxAllowed+10)
2005 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2007 if (smb_dirSearchCounter > maxAllowed) {
2008 smb_dirSearchCounter = 1;
2010 if (smb_dirSearchCounter == start) {
2012 smb_GCDirSearches(isV3);
2015 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2017 /* don't need to watch for refcount zero and deleted, since
2018 * we haven't dropped the global lock.
2020 lock_ObtainMutex(&dsp->mx);
2022 lock_ReleaseMutex(&dsp->mx);
2023 ++smb_dirSearchCounter;
2027 dsp = malloc(sizeof(*dsp));
2028 memset(dsp, 0, sizeof(*dsp));
2029 dsp->cookie = smb_dirSearchCounter;
2030 ++smb_dirSearchCounter;
2032 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2033 dsp->lastTime = osi_Time();
2034 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2035 if (!smb_lastDirSearchp)
2036 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2038 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2042 lock_ReleaseWrite(&smb_globalLock);
2046 static smb_packet_t *GetPacket(void)
2050 lock_ObtainWrite(&smb_globalLock);
2051 tbp = smb_packetFreeListp;
2053 smb_packetFreeListp = tbp->nextp;
2054 lock_ReleaseWrite(&smb_globalLock);
2056 tbp = calloc(65540,1);
2057 tbp->magic = SMB_PACKETMAGIC;
2060 tbp->resumeCode = 0;
2066 tbp->ncb_length = 0;
2071 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2076 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2080 memcpy(tbp, pkt, sizeof(smb_packet_t));
2081 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2083 smb_HoldVC(tbp->vcp);
2087 static NCB *GetNCB(void)
2092 lock_ObtainWrite(&smb_globalLock);
2093 tbp = smb_ncbFreeListp;
2095 smb_ncbFreeListp = tbp->nextp;
2096 lock_ReleaseWrite(&smb_globalLock);
2098 tbp = calloc(sizeof(*tbp),1);
2099 tbp->magic = SMB_NCBMAGIC;
2102 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2104 memset(&tbp->ncb, 0, sizeof(NCB));
2109 void smb_FreePacket(smb_packet_t *tbp)
2111 smb_vc_t * vcp = NULL;
2112 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2114 lock_ObtainWrite(&smb_globalLock);
2115 tbp->nextp = smb_packetFreeListp;
2116 smb_packetFreeListp = tbp;
2117 tbp->magic = SMB_PACKETMAGIC;
2121 tbp->resumeCode = 0;
2127 tbp->ncb_length = 0;
2129 lock_ReleaseWrite(&smb_globalLock);
2135 static void FreeNCB(NCB *bufferp)
2139 tbp = (smb_ncb_t *) bufferp;
2140 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2142 lock_ObtainWrite(&smb_globalLock);
2143 tbp->nextp = smb_ncbFreeListp;
2144 smb_ncbFreeListp = tbp;
2145 lock_ReleaseWrite(&smb_globalLock);
2148 /* get a ptr to the data part of a packet, and its count */
2149 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2153 unsigned char *afterParmsp;
2155 parmBytes = *smbp->wctp << 1;
2156 afterParmsp = smbp->wctp + parmBytes + 1;
2158 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2159 if (nbytesp) *nbytesp = dataBytes;
2161 /* don't forget to skip the data byte count, since it follows
2162 * the parameters; that's where the "2" comes from below.
2164 return (unsigned char *) (afterParmsp + 2);
2167 /* must set all the returned parameters before playing around with the
2168 * data region, since the data region is located past the end of the
2169 * variable number of parameters.
2171 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2173 unsigned char *afterParmsp;
2175 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2177 *afterParmsp++ = dsize & 0xff;
2178 *afterParmsp = (dsize>>8) & 0xff;
2181 /* return the parm'th parameter in the smbp packet */
2182 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2185 unsigned char *parmDatap;
2187 parmCount = *smbp->wctp;
2189 if (parm >= parmCount) {
2192 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2193 parm, parmCount, smbp->ncb_length);
2194 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2195 parm, parmCount, smbp->ncb_length);
2196 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2197 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2198 osi_panic(s, __FILE__, __LINE__);
2200 parmDatap = smbp->wctp + (2*parm) + 1;
2202 return parmDatap[0] + (parmDatap[1] << 8);
2205 /* return the parm'th parameter in the smbp packet */
2206 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2209 unsigned char *parmDatap;
2211 parmCount = *smbp->wctp;
2213 if (parm >= parmCount) {
2216 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2217 parm, parmCount, smbp->ncb_length);
2218 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2219 parm, parmCount, smbp->ncb_length);
2220 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2221 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2222 osi_panic(s, __FILE__, __LINE__);
2224 parmDatap = smbp->wctp + (2*parm) + 1;
2226 return parmDatap[0];
2229 /* return the parm'th parameter in the smbp packet */
2230 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2233 unsigned char *parmDatap;
2235 parmCount = *smbp->wctp;
2237 if (parm + 1 >= parmCount) {
2240 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2241 parm, parmCount, smbp->ncb_length);
2242 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2243 parm, parmCount, smbp->ncb_length);
2244 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2245 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2246 osi_panic(s, __FILE__, __LINE__);
2248 parmDatap = smbp->wctp + (2*parm) + 1;
2250 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2253 /* return the parm'th parameter in the smbp packet */
2254 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2257 unsigned char *parmDatap;
2259 parmCount = *smbp->wctp;
2261 if (parm * 2 + offset >= parmCount * 2) {
2264 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2265 parm, offset, parmCount, smbp->ncb_length);
2266 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2267 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2268 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2269 parm, offset, parmCount, smbp->ncb_length);
2270 osi_panic(s, __FILE__, __LINE__);
2272 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2274 return parmDatap[0] + (parmDatap[1] << 8);
2277 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2281 /* make sure we have enough slots */
2282 if (*smbp->wctp <= slot)
2283 *smbp->wctp = slot+1;
2285 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2286 *parmDatap++ = parmValue & 0xff;
2287 *parmDatap = (parmValue>>8) & 0xff;
2290 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2294 /* make sure we have enough slots */
2295 if (*smbp->wctp <= slot)
2296 *smbp->wctp = slot+2;
2298 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2299 *parmDatap++ = parmValue & 0xff;
2300 *parmDatap++ = (parmValue>>8) & 0xff;
2301 *parmDatap++ = (parmValue>>16) & 0xff;
2302 *parmDatap = (parmValue>>24) & 0xff;
2305 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2310 /* make sure we have enough slots */
2311 if (*smbp->wctp <= slot)
2312 *smbp->wctp = slot+4;
2314 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2316 *parmDatap++ = *parmValuep++;
2319 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2323 /* make sure we have enough slots */
2324 if (*smbp->wctp <= slot) {
2325 if (smbp->oddByte) {
2327 *smbp->wctp = slot+1;
2332 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2333 *parmDatap++ = parmValue & 0xff;
2336 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2340 lastSlashp = strrchr(inPathp, '\\');
2342 *lastComponentp = lastSlashp;
2345 if (inPathp == lastSlashp)
2347 *outPathp++ = *inPathp++;
2356 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
2361 *chainpp = inp + strlen(inp) + 1; /* skip over null-terminated string */
2366 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2372 tlen = inp[0] + (inp[1]<<8);
2373 inp += 2; /* skip length field */
2376 *chainpp = inp + tlen;
2385 /* format a packet as a response */
2386 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2391 outp = (smb_t *) op;
2393 /* zero the basic structure through the smb_wct field, and zero the data
2394 * size field, assuming that wct stays zero; otherwise, you have to
2395 * explicitly set the data size field, too.
2397 inSmbp = (smb_t *) inp;
2398 memset(outp, 0, sizeof(smb_t)+2);
2404 outp->com = inSmbp->com;
2405 outp->tid = inSmbp->tid;
2406 outp->pid = inSmbp->pid;
2407 outp->uid = inSmbp->uid;
2408 outp->mid = inSmbp->mid;
2409 outp->res[0] = inSmbp->res[0];
2410 outp->res[1] = inSmbp->res[1];
2411 op->inCom = inSmbp->com;
2413 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2414 #ifdef SEND_CANONICAL_PATHNAMES
2415 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2417 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2419 /* copy fields in generic packet area */
2420 op->wctp = &outp->wct;
2423 /* send a (probably response) packet; vcp tells us to whom to send it.
2424 * we compute the length by looking at wct and bcc fields.
2426 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2440 memset((char *)ncbp, 0, sizeof(NCB));
2442 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2443 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2444 extra += tp[0] + (tp[1]<<8);
2445 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2446 extra += 3; /* wct and length fields */
2448 ncbp->ncb_length = extra; /* bytes to send */
2449 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2450 ncbp->ncb_lana_num = vcp->lana;
2451 ncbp->ncb_command = NCBSEND; /* op means send data */
2452 ncbp->ncb_buffer = (char *) inp;/* packet */
2453 code = Netbios(ncbp);
2456 const char * s = ncb_error_string(code);
2457 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2458 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2460 lock_ObtainMutex(&vcp->mx);
2461 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2462 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2464 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2465 lock_ReleaseMutex(&vcp->mx);
2466 lock_ObtainWrite(&smb_globalLock);
2467 dead_sessions[vcp->session] = TRUE;
2468 lock_ReleaseWrite(&smb_globalLock);
2469 smb_CleanupDeadVC(vcp);
2471 lock_ReleaseMutex(&vcp->mx);
2479 void smb_MapNTError(long code, unsigned long *NTStatusp)
2481 unsigned long NTStatus;
2483 /* map CM_ERROR_* errors to NT 32-bit status codes */
2484 /* NT Status codes are listed in ntstatus.h not winerror.h */
2485 if (code == CM_ERROR_NOSUCHCELL) {
2486 NTStatus = 0xC000000FL; /* No such file */
2488 else if (code == CM_ERROR_NOSUCHVOLUME) {
2489 NTStatus = 0xC000000FL; /* No such file */
2491 else if (code == CM_ERROR_TIMEDOUT) {
2493 NTStatus = 0xC00000CFL; /* Sharing Paused */
2495 NTStatus = 0x00000102L; /* Timeout */
2498 else if (code == CM_ERROR_RETRY) {
2499 NTStatus = 0xC000022DL; /* Retry */
2501 else if (code == CM_ERROR_NOACCESS) {
2502 NTStatus = 0xC0000022L; /* Access denied */
2504 else if (code == CM_ERROR_READONLY) {
2505 NTStatus = 0xC00000A2L; /* Write protected */
2507 else if (code == CM_ERROR_NOSUCHFILE ||
2508 code == CM_ERROR_BPLUS_NOMATCH) {
2509 NTStatus = 0xC000000FL; /* No such file */
2511 else if (code == CM_ERROR_NOSUCHPATH) {
2512 NTStatus = 0xC000003AL; /* Object path not found */
2514 else if (code == CM_ERROR_TOOBIG) {
2515 NTStatus = 0xC000007BL; /* Invalid image format */
2517 else if (code == CM_ERROR_INVAL) {
2518 NTStatus = 0xC000000DL; /* Invalid parameter */
2520 else if (code == CM_ERROR_BADFD) {
2521 NTStatus = 0xC0000008L; /* Invalid handle */
2523 else if (code == CM_ERROR_BADFDOP) {
2524 NTStatus = 0xC0000022L; /* Access denied */
2526 else if (code == CM_ERROR_EXISTS) {
2527 NTStatus = 0xC0000035L; /* Object name collision */
2529 else if (code == CM_ERROR_NOTEMPTY) {
2530 NTStatus = 0xC0000101L; /* Directory not empty */
2532 else if (code == CM_ERROR_CROSSDEVLINK) {
2533 NTStatus = 0xC00000D4L; /* Not same device */
2535 else if (code == CM_ERROR_NOTDIR) {
2536 NTStatus = 0xC0000103L; /* Not a directory */
2538 else if (code == CM_ERROR_ISDIR) {
2539 NTStatus = 0xC00000BAL; /* File is a directory */
2541 else if (code == CM_ERROR_BADOP) {
2543 /* I have no idea where this comes from */
2544 NTStatus = 0xC09820FFL; /* SMB no support */
2546 NTStatus = 0xC00000BBL; /* Not supported */
2547 #endif /* COMMENT */
2549 else if (code == CM_ERROR_BADSHARENAME) {
2550 NTStatus = 0xC00000CCL; /* Bad network name */
2552 else if (code == CM_ERROR_NOIPC) {
2554 NTStatus = 0xC0000022L; /* Access Denied */
2556 NTStatus = 0xC000013DL; /* Remote Resources */
2559 else if (code == CM_ERROR_CLOCKSKEW) {
2560 NTStatus = 0xC0000133L; /* Time difference at DC */
2562 else if (code == CM_ERROR_BADTID) {
2563 NTStatus = 0xC0982005L; /* SMB bad TID */
2565 else if (code == CM_ERROR_USESTD) {
2566 NTStatus = 0xC09820FBL; /* SMB use standard */
2568 else if (code == CM_ERROR_QUOTA) {
2570 NTStatus = 0xC0000044L; /* Quota exceeded */
2572 NTStatus = 0xC000007FL; /* Disk full */
2575 else if (code == CM_ERROR_SPACE) {
2576 NTStatus = 0xC000007FL; /* Disk full */
2578 else if (code == CM_ERROR_ATSYS) {
2579 NTStatus = 0xC0000033L; /* Object name invalid */
2581 else if (code == CM_ERROR_BADNTFILENAME) {
2582 NTStatus = 0xC0000033L; /* Object name invalid */
2584 else if (code == CM_ERROR_WOULDBLOCK) {
2585 NTStatus = 0xC0000055L; /* Lock not granted */
2587 else if (code == CM_ERROR_SHARING_VIOLATION) {
2588 NTStatus = 0xC0000043L; /* Sharing violation */
2590 else if (code == CM_ERROR_LOCK_CONFLICT) {
2591 NTStatus = 0xC0000054L; /* Lock conflict */
2593 else if (code == CM_ERROR_PARTIALWRITE) {
2594 NTStatus = 0xC000007FL; /* Disk full */
2596 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2597 NTStatus = 0xC0000023L; /* Buffer too small */
2599 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2600 NTStatus = 0xC0000035L; /* Object name collision */
2602 else if (code == CM_ERROR_BADPASSWORD) {
2603 NTStatus = 0xC000006DL; /* unknown username or bad password */
2605 else if (code == CM_ERROR_BADLOGONTYPE) {
2606 NTStatus = 0xC000015BL; /* logon type not granted */
2608 else if (code == CM_ERROR_GSSCONTINUE) {
2609 NTStatus = 0xC0000016L; /* more processing required */
2611 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2613 NTStatus = 0xC0000280L; /* reparse point not resolved */
2615 NTStatus = 0xC0000022L; /* Access Denied */
2618 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2619 NTStatus = 0xC0000257L; /* Path Not Covered */
2622 else if (code == CM_ERROR_ALLBUSY) {
2623 NTStatus = 0xC00000BFL; /* Network Busy */
2625 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2626 NTStatus = 0xC0000350L; /* Remote Host Down */
2629 /* we do not want to be telling the SMB/CIFS client that
2630 * the AFS Client Service is busy or down.
2632 else if (code == CM_ERROR_ALLBUSY ||
2633 code == CM_ERROR_ALLOFFLINE ||
2634 code == CM_ERROR_ALLDOWN) {
2635 NTStatus = 0xC00000BEL; /* Bad Network Path */
2638 else if (code == RXKADUNKNOWNKEY) {
2639 NTStatus = 0xC0000322L; /* Bad Kerberos key */
2641 else if (code == CM_ERROR_BAD_LEVEL) {
2642 NTStatus = 0xC0000148L; /* Invalid Level */
2644 NTStatus = 0xC0982001L; /* SMB non-specific error */
2647 *NTStatusp = NTStatus;
2648 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2651 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2652 unsigned char *classp)
2654 unsigned char class;
2655 unsigned short error;
2657 /* map CM_ERROR_* errors to SMB errors */
2658 if (code == CM_ERROR_NOSUCHCELL) {
2660 error = 3; /* bad path */
2662 else if (code == CM_ERROR_NOSUCHVOLUME) {
2664 error = 3; /* bad path */
2666 else if (code == CM_ERROR_TIMEDOUT) {
2668 error = 81; /* server is paused */
2670 else if (code == CM_ERROR_RETRY) {
2671 class = 2; /* shouldn't happen */
2674 else if (code == CM_ERROR_NOACCESS) {
2676 error = 4; /* bad access */
2678 else if (code == CM_ERROR_READONLY) {
2680 error = 19; /* read only */
2682 else if (code == CM_ERROR_NOSUCHFILE ||
2683 code == CM_ERROR_BPLUS_NOMATCH) {
2685 error = 2; /* ENOENT! */
2687 else if (code == CM_ERROR_NOSUCHPATH) {
2689 error = 3; /* Bad path */
2691 else if (code == CM_ERROR_TOOBIG) {
2693 error = 11; /* bad format */
2695 else if (code == CM_ERROR_INVAL) {
2696 class = 2; /* server non-specific error code */
2699 else if (code == CM_ERROR_BADFD) {
2701 error = 6; /* invalid file handle */
2703 else if (code == CM_ERROR_BADFDOP) {
2704 class = 1; /* invalid op on FD */
2707 else if (code == CM_ERROR_EXISTS) {
2709 error = 80; /* file already exists */
2711 else if (code == CM_ERROR_NOTEMPTY) {
2713 error = 5; /* delete directory not empty */
2715 else if (code == CM_ERROR_CROSSDEVLINK) {
2717 error = 17; /* EXDEV */
2719 else if (code == CM_ERROR_NOTDIR) {
2720 class = 1; /* bad path */
2723 else if (code == CM_ERROR_ISDIR) {
2724 class = 1; /* access denied; DOS doesn't have a good match */
2727 else if (code == CM_ERROR_BADOP) {
2731 else if (code == CM_ERROR_BADSHARENAME) {
2735 else if (code == CM_ERROR_NOIPC) {
2737 error = 4; /* bad access */
2739 else if (code == CM_ERROR_CLOCKSKEW) {
2740 class = 1; /* invalid function */
2743 else if (code == CM_ERROR_BADTID) {
2747 else if (code == CM_ERROR_USESTD) {
2751 else if (code == CM_ERROR_REMOTECONN) {
2755 else if (code == CM_ERROR_QUOTA) {
2756 if (vcp->flags & SMB_VCFLAG_USEV3) {
2758 error = 39; /* disk full */
2762 error = 5; /* access denied */
2765 else if (code == CM_ERROR_SPACE) {
2766 if (vcp->flags & SMB_VCFLAG_USEV3) {
2768 error = 39; /* disk full */
2772 error = 5; /* access denied */
2775 else if (code == CM_ERROR_PARTIALWRITE) {
2777 error = 39; /* disk full */
2779 else if (code == CM_ERROR_ATSYS) {
2781 error = 2; /* ENOENT */
2783 else if (code == CM_ERROR_WOULDBLOCK) {
2785 error = 33; /* lock conflict */
2787 else if (code == CM_ERROR_LOCK_CONFLICT) {
2789 error = 33; /* lock conflict */
2791 else if (code == CM_ERROR_SHARING_VIOLATION) {
2793 error = 33; /* lock conflict */
2795 else if (code == CM_ERROR_NOFILES) {
2797 error = 18; /* no files in search */
2799 else if (code == CM_ERROR_RENAME_IDENTICAL) {
2801 error = 183; /* Samba uses this */
2803 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
2804 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
2806 error = 2; /* bad password */
2808 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2810 error = 3; /* bad path */
2819 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
2822 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2824 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
2825 return CM_ERROR_BADOP;
2828 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2830 unsigned short EchoCount, i;
2831 char *data, *outdata;
2834 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2836 for (i=1; i<=EchoCount; i++) {
2837 data = smb_GetSMBData(inp, &dataSize);
2838 smb_SetSMBParm(outp, 0, i);
2839 smb_SetSMBDataLength(outp, dataSize);
2840 outdata = smb_GetSMBData(outp, NULL);
2841 memcpy(outdata, data, dataSize);
2842 smb_SendPacket(vcp, outp);
2848 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2851 long count, minCount, finalCount;
2856 cm_user_t *userp = NULL;
2859 char *rawBuf = NULL;
2864 fd = smb_GetSMBParm(inp, 0);
2865 count = smb_GetSMBParm(inp, 3);
2866 minCount = smb_GetSMBParm(inp, 4);
2867 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2869 if (*inp->wctp == 10) {
2870 /* we were sent a request with 64-bit file offsets */
2871 #ifdef AFS_LARGEFILES
2872 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
2874 if (LargeIntegerLessThanZero(offset)) {
2875 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
2879 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
2880 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
2883 offset.HighPart = 0;
2887 /* we were sent a request with 32-bit file offsets */
2888 offset.HighPart = 0;
2891 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
2892 fd, offset.HighPart, offset.LowPart, count);
2894 fidp = smb_FindFID(vcp, fd, 0);
2898 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
2899 smb_CloseFID(vcp, fidp, NULL, 0);
2900 code = CM_ERROR_NOSUCHFILE;
2905 pid = ((smb_t *) inp)->pid;
2907 LARGE_INTEGER LOffset, LLength;
2910 key = cm_GenerateKey(vcp->vcID, pid, fd);
2912 LOffset.HighPart = offset.HighPart;
2913 LOffset.LowPart = offset.LowPart;
2914 LLength.HighPart = 0;
2915 LLength.LowPart = count;
2917 lock_ObtainMutex(&fidp->scp->mx);
2918 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
2919 lock_ReleaseMutex(&fidp->scp->mx);
2925 lock_ObtainMutex(&smb_RawBufLock);
2927 /* Get a raw buf, from head of list */
2928 rawBuf = smb_RawBufs;
2929 smb_RawBufs = *(char **)smb_RawBufs;
2931 lock_ReleaseMutex(&smb_RawBufLock);
2935 lock_ObtainMutex(&fidp->mx);
2936 if (fidp->flags & SMB_FID_IOCTL)
2938 lock_ReleaseMutex(&fidp->mx);
2939 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2941 /* Give back raw buffer */
2942 lock_ObtainMutex(&smb_RawBufLock);
2943 *((char **) rawBuf) = smb_RawBufs;
2945 smb_RawBufs = rawBuf;
2946 lock_ReleaseMutex(&smb_RawBufLock);
2949 smb_ReleaseFID(fidp);
2952 lock_ReleaseMutex(&fidp->mx);
2954 userp = smb_GetUserFromVCP(vcp, inp);
2956 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2962 cm_ReleaseUser(userp);
2965 smb_ReleaseFID(fidp);
2969 memset((char *)ncbp, 0, sizeof(NCB));
2971 ncbp->ncb_length = (unsigned short) finalCount;
2972 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2973 ncbp->ncb_lana_num = vcp->lana;
2974 ncbp->ncb_command = NCBSEND;
2975 ncbp->ncb_buffer = rawBuf;
2977 code = Netbios(ncbp);
2979 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2982 /* Give back raw buffer */
2983 lock_ObtainMutex(&smb_RawBufLock);
2984 *((char **) rawBuf) = smb_RawBufs;
2986 smb_RawBufs = rawBuf;
2987 lock_ReleaseMutex(&smb_RawBufLock);
2993 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2995 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3000 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3002 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3007 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3014 int VistaProtoIndex;
3015 int protoIndex; /* index we're using */
3020 char protocol_array[10][1024]; /* protocol signature of the client */
3021 int caps; /* capabilities */
3024 TIME_ZONE_INFORMATION tzi;
3026 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3029 namep = smb_GetSMBData(inp, &dbytes);
3032 coreProtoIndex = -1; /* not found */
3035 VistaProtoIndex = -1;
3036 while(namex < dbytes) {
3037 osi_Log1(smb_logp, "Protocol %s",
3038 osi_LogSaveString(smb_logp, namep+1));
3039 strcpy(protocol_array[tcounter], namep+1);
3041 /* namep points at the first protocol, or really, a 0x02
3042 * byte preceding the null-terminated ASCII name.
3044 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3045 coreProtoIndex = tcounter;
3047 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3048 v3ProtoIndex = tcounter;
3050 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3051 NTProtoIndex = tcounter;
3053 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3054 VistaProtoIndex = tcounter;
3057 /* compute size of protocol entry */
3058 entryLength = (int)strlen(namep+1);
3059 entryLength += 2; /* 0x02 bytes and null termination */
3061 /* advance over this protocol entry */
3062 namex += entryLength;
3063 namep += entryLength;
3064 tcounter++; /* which proto entry we're looking at */
3067 lock_ObtainMutex(&vcp->mx);
3069 if (VistaProtoIndex != -1) {
3070 protoIndex = VistaProtoIndex;
3071 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3074 if (NTProtoIndex != -1) {
3075 protoIndex = NTProtoIndex;
3076 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3078 else if (v3ProtoIndex != -1) {
3079 protoIndex = v3ProtoIndex;
3080 vcp->flags |= SMB_VCFLAG_USEV3;
3082 else if (coreProtoIndex != -1) {
3083 protoIndex = coreProtoIndex;
3084 vcp->flags |= SMB_VCFLAG_USECORE;
3086 else protoIndex = -1;
3087 lock_ReleaseMutex(&vcp->mx);
3089 if (protoIndex == -1)
3090 return CM_ERROR_INVAL;
3091 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3092 smb_SetSMBParm(outp, 0, protoIndex);
3093 if (smb_authType != SMB_AUTH_NONE) {
3094 smb_SetSMBParmByte(outp, 1,
3095 NEGOTIATE_SECURITY_USER_LEVEL |
3096 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3098 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3100 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3101 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3102 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3103 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3104 /* The session key is not a well documented field however most clients
3105 * will echo back the session key to the server. Currently we are using
3106 * the same value for all sessions. We should generate a random value
3107 * and store it into the vcp
3109 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3110 smb_SetSMBParm(outp, 8, 1);
3112 * Tried changing the capabilities to support for W2K - defect 117695
3113 * Maybe something else needs to be changed here?
3117 smb_SetSMBParmLong(outp, 9, 0x43fd);
3119 smb_SetSMBParmLong(outp, 9, 0x251);
3122 * 32-bit error codes *
3127 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3129 NTNEGOTIATE_CAPABILITY_DFS |
3131 #ifdef AFS_LARGEFILES
3132 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3134 NTNEGOTIATE_CAPABILITY_NTFIND |
3135 NTNEGOTIATE_CAPABILITY_RAWMODE |
3136 NTNEGOTIATE_CAPABILITY_NTSMB;
3138 if ( smb_authType == SMB_AUTH_EXTENDED )
3139 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3141 smb_SetSMBParmLong(outp, 9, caps);
3143 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3144 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3145 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3147 GetTimeZoneInformation(&tzi);
3148 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3150 if (smb_authType == SMB_AUTH_NTLM) {
3151 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3152 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3153 /* paste in encryption key */
3154 datap = smb_GetSMBData(outp, NULL);
3155 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3156 /* and the faux domain name */
3157 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3158 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3162 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3164 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3166 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3168 datap = smb_GetSMBData(outp, NULL);
3169 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3172 datap += sizeof(smb_ServerGUID);
3173 memcpy(datap, secBlob, secBlobLength);
3177 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3178 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3181 else if (v3ProtoIndex != -1) {
3182 smb_SetSMBParm(outp, 0, protoIndex);
3184 /* NOTE: Extended authentication cannot be negotiated with v3
3185 * therefore we fail over to NTLM
3187 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3188 smb_SetSMBParm(outp, 1,
3189 NEGOTIATE_SECURITY_USER_LEVEL |
3190 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3192 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3194 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3195 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3196 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3197 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3198 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3199 smb_SetSMBParm(outp, 7, 1);
3201 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3202 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3203 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3205 GetTimeZoneInformation(&tzi);
3206 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3208 /* NOTE: Extended authentication cannot be negotiated with v3
3209 * therefore we fail over to NTLM
3211 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3212 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3213 smb_SetSMBParm(outp, 12, 0); /* resvd */
3214 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3215 datap = smb_GetSMBData(outp, NULL);
3216 /* paste in a new encryption key */
3217 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3218 /* and the faux domain name */
3219 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3221 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3222 smb_SetSMBParm(outp, 12, 0); /* resvd */
3223 smb_SetSMBDataLength(outp, 0);
3226 else if (coreProtoIndex != -1) { /* not really supported anymore */
3227 smb_SetSMBParm(outp, 0, protoIndex);
3228 smb_SetSMBDataLength(outp, 0);
3233 void smb_CheckVCs(void)
3235 smb_vc_t * vcp, *nextp;
3236 smb_packet_t * outp = GetPacket();
3239 lock_ObtainWrite(&smb_rctLock);
3240 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3242 if (vcp->magic != SMB_VC_MAGIC)
3243 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3244 __FILE__, __LINE__);
3248 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3251 smb_HoldVCNoLock(vcp);
3253 smb_HoldVCNoLock(nextp);
3254 smb_FormatResponsePacket(vcp, NULL, outp);
3255 smbp = (smb_t *)outp;
3256 outp->inCom = smbp->com = 0x2b /* Echo */;
3264 smb_SetSMBParm(outp, 0, 0);
3265 smb_SetSMBDataLength(outp, 0);
3266 lock_ReleaseWrite(&smb_rctLock);
3268 smb_SendPacket(vcp, outp);
3270 lock_ObtainWrite(&smb_rctLock);
3271 smb_ReleaseVCNoLock(vcp);
3273 smb_ReleaseVCNoLock(nextp);
3275 lock_ReleaseWrite(&smb_rctLock);
3276 smb_FreePacket(outp);
3279 void smb_Daemon(void *parmp)
3281 afs_uint32 count = 0;
3282 smb_username_t **unpp;
3285 while(smbShutdownFlag == 0) {
3289 if (smbShutdownFlag == 1)
3292 if ((count % 72) == 0) { /* every five minutes */
3294 time_t old_localZero = smb_localZero;
3296 /* Initialize smb_localZero */
3297 myTime.tm_isdst = -1; /* compute whether on DST or not */
3298 myTime.tm_year = 70;
3304 smb_localZero = mktime(&myTime);
3306 #ifndef USE_NUMERIC_TIME_CONV
3307 smb_CalculateNowTZ();
3308 #endif /* USE_NUMERIC_TIME_CONV */
3309 #ifdef AFS_FREELANCE
3310 if ( smb_localZero != old_localZero )
3311 cm_noteLocalMountPointChange();
3317 /* GC smb_username_t objects that will no longer be used */
3319 lock_ObtainWrite(&smb_rctLock);
3320 for ( unpp=&usernamesp; *unpp; ) {
3322 smb_username_t *unp;
3324 lock_ObtainMutex(&(*unpp)->mx);
3325 if ( (*unpp)->refCount > 0 ||
3326 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3327 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3329 else if (!smb_LogoffTokenTransfer ||
3330 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3332 lock_ReleaseMutex(&(*unpp)->mx);
3340 lock_FinalizeMutex(&unp->mx);
3346 lock_ReleaseWrite(&smb_rctLock);
3347 cm_ReleaseUser(userp);
3348 lock_ObtainWrite(&smb_rctLock);
3351 unpp = &(*unpp)->nextp;
3354 lock_ReleaseWrite(&smb_rctLock);
3356 /* XXX GC dir search entries */
3360 void smb_WaitingLocksDaemon()
3362 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3363 smb_waitingLock_t *wl, *wlNext;
3366 smb_packet_t *inp, *outp;
3370 while (smbShutdownFlag == 0) {
3371 lock_ObtainWrite(&smb_globalLock);
3372 nwlRequest = smb_allWaitingLocks;
3373 if (nwlRequest == NULL) {
3374 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3379 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3386 lock_ObtainWrite(&smb_globalLock);
3388 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3390 wlRequest = nwlRequest;
3391 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3392 lock_ReleaseWrite(&smb_globalLock);
3396 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3397 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3400 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3402 /* wl->state is either _DONE or _WAITING. _ERROR
3403 would no longer be on the queue. */
3404 code = cm_RetryLock( wl->lockp,
3405 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3408 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3409 } else if (code != CM_ERROR_WOULDBLOCK) {
3410 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3415 if (code == CM_ERROR_WOULDBLOCK) {
3418 if (wlRequest->timeRemaining != 0xffffffff
3419 && (wlRequest->timeRemaining -= 1000) < 0)
3431 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3434 scp = wlRequest->scp;
3435 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3439 lock_ObtainMutex(&scp->mx);
3441 for (wl = wlRequest->locks; wl; wl = wlNext) {
3442 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3444 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3445 wl->LLength, wl->key, NULL, &req);
3447 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3452 lock_ReleaseMutex(&scp->mx);
3456 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3459 for (wl = wlRequest->locks; wl; wl = wlNext) {
3460 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3461 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3466 vcp = wlRequest->vcp;
3467 inp = wlRequest->inp;
3468 outp = wlRequest->outp;
3470 ncbp->ncb_length = inp->ncb_length;
3471 inp->spacep = cm_GetSpace();
3473 /* Remove waitingLock from list */
3474 lock_ObtainWrite(&smb_globalLock);
3475 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3477 lock_ReleaseWrite(&smb_globalLock);
3479 /* Resume packet processing */
3481 smb_SetSMBDataLength(outp, 0);
3482 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3483 outp->resumeCode = code;
3485 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3488 cm_FreeSpace(inp->spacep);
3489 smb_FreePacket(inp);
3490 smb_FreePacket(outp);
3492 cm_ReleaseSCache(wlRequest->scp);
3495 } while (nwlRequest && smbShutdownFlag == 0);
3500 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3502 osi_Log0(smb_logp, "SMB receive get disk attributes");
3504 smb_SetSMBParm(outp, 0, 32000);
3505 smb_SetSMBParm(outp, 1, 64);
3506 smb_SetSMBParm(outp, 2, 1024);
3507 smb_SetSMBParm(outp, 3, 30000);
3508 smb_SetSMBParm(outp, 4, 0);
3509 smb_SetSMBDataLength(outp, 0);
3513 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3517 unsigned short newTid;
3518 char shareName[AFSPATHMAX];
3526 osi_Log0(smb_logp, "SMB receive tree connect");
3528 /* parse input parameters */
3529 tp = smb_GetSMBData(inp, NULL);
3530 pathp = smb_ParseASCIIBlock(tp, &tp);
3531 if (smb_StoreAnsiFilenames)
3532 OemToChar(pathp,pathp);
3533 passwordp = smb_ParseASCIIBlock(tp, &tp);
3534 tp = strrchr(pathp, '\\');
3536 return CM_ERROR_BADSMB;
3537 strcpy(shareName, tp+1);
3539 lock_ObtainMutex(&vcp->mx);
3540 newTid = vcp->tidCounter++;
3541 lock_ReleaseMutex(&vcp->mx);
3543 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3544 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3545 userp = smb_GetUserFromUID(uidp);
3546 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3548 smb_ReleaseUID(uidp);
3550 smb_ReleaseTID(tidp);
3551 return CM_ERROR_BADSHARENAME;
3553 lock_ObtainMutex(&tidp->mx);
3554 tidp->userp = userp;
3555 tidp->pathname = sharePath;
3556 lock_ReleaseMutex(&tidp->mx);
3557 smb_ReleaseTID(tidp);
3559 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3560 smb_SetSMBParm(rsp, 1, newTid);
3561 smb_SetSMBDataLength(rsp, 0);
3563 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3567 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
3571 if (*inp++ != 0x1) return NULL;
3572 tlen = inp[0] + (inp[1]<<8);
3573 inp += 2; /* skip length field */
3576 *chainpp = inp + tlen;
3579 if (lengthp) *lengthp = tlen;
3584 /* set maskp to the mask part of the incoming path.
3585 * Mask is 11 bytes long (8.3 with the dot elided).
3586 * Returns true if succeeds with a valid name, otherwise it does
3587 * its best, but returns false.
3589 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3597 /* starts off valid */
3600 /* mask starts out all blanks */
3601 memset(maskp, ' ', 11);
3603 /* find last backslash, or use whole thing if there is none */
3604 tp = strrchr(pathp, '\\');
3605 if (!tp) tp = pathp;
3606 else tp++; /* skip slash */
3610 /* names starting with a dot are illegal */
3611 if (*tp == '.') valid8Dot3 = 0;
3615 if (tc == 0) return valid8Dot3;
3616 if (tc == '.' || tc == '"') break;
3617 if (i < 8) *up++ = tc;
3618 else valid8Dot3 = 0;
3621 /* if we get here, tp point after the dot */
3622 up = maskp+8; /* ext goes here */
3629 if (tc == '.' || tc == '"')
3632 /* copy extension if not too long */
3642 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3652 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3654 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3658 /* otherwise, we have a valid 8.3 name; see if we have a match,
3659 * treating '?' as a wildcard in maskp (but not in the file name).
3661 tp1 = umask; /* real name, in mask format */
3662 tp2 = maskp; /* mask, in mask format */
3663 for(i=0; i<11; i++) {
3664 tc1 = *tp1++; /* char from real name */
3665 tc2 = *tp2++; /* char from mask */
3666 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3667 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3670 if (tc2 == '?' && tc1 != ' ')
3677 /* we got a match */
3681 char *smb_FindMask(char *pathp)
3685 tp = strrchr(pathp, '\\'); /* find last slash */
3688 return tp+1; /* skip the slash */
3690 return pathp; /* no slash, return the entire path */
3693 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3695 unsigned char *pathp;
3697 unsigned char mask[11];
3698 unsigned char *statBlockp;
3699 unsigned char initStatBlock[21];
3702 osi_Log0(smb_logp, "SMB receive search volume");
3704 /* pull pathname and stat block out of request */
3705 tp = smb_GetSMBData(inp, NULL);
3706 pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
3707 osi_assertx(pathp != NULL, "null path");
3708 if (smb_StoreAnsiFilenames)
3709 OemToChar(pathp,pathp);
3710 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
3711 osi_assertx(statBlockp != NULL, "null statBlock");
3713 statBlockp = initStatBlock;
3717 /* for returning to caller */
3718 smb_Get8Dot3MaskFromPath(mask, pathp);
3720 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
3721 tp = smb_GetSMBData(outp, NULL);
3723 *tp++ = 43; /* bytes in a dir entry */
3724 *tp++ = 0; /* high byte in counter */
3726 /* now marshall the dir entry, starting with the search status */
3727 *tp++ = statBlockp[0]; /* Reserved */
3728 memcpy(tp, mask, 11); tp += 11; /* FileName */
3730 /* now pass back server use info, with 1st byte non-zero */
3732 memset(tp, 0, 4); tp += 4; /* reserved for server use */
3734 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
3736 *tp++ = 0x8; /* attribute: volume */
3746 /* 4 byte file size */
3752 /* finally, null-terminated 8.3 pathname, which we set to AFS */
3753 memset(tp, ' ', 13);
3756 /* set the length of the data part of the packet to 43 + 3, for the dir
3757 * entry plus the 5 and the length fields.
3759 smb_SetSMBDataLength(outp, 46);
3763 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
3764 cm_user_t *userp, cm_req_t *reqp)
3772 smb_dirListPatch_t *patchp;
3773 smb_dirListPatch_t *npatchp;
3775 for (patchp = *dirPatchespp; patchp; patchp =
3776 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
3778 dptr = patchp->dptr;
3780 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
3782 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
3783 *dptr++ = SMB_ATTR_HIDDEN;
3786 lock_ObtainMutex(&scp->mx);
3787 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
3788 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3790 lock_ReleaseMutex(&scp->mx);
3791 cm_ReleaseSCache(scp);
3792 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3793 *dptr++ = SMB_ATTR_HIDDEN;
3797 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3799 attr = smb_Attributes(scp);
3800 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
3801 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
3802 attr |= SMB_ATTR_HIDDEN;
3806 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
3809 shortTemp = (unsigned short) (dosTime & 0xffff);
3810 *((u_short *)dptr) = shortTemp;
3813 /* and copy out date */
3814 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
3815 *((u_short *)dptr) = shortTemp;
3818 /* copy out file length */
3819 *((u_long *)dptr) = scp->length.LowPart;
3821 lock_ReleaseMutex(&scp->mx);
3822 cm_ReleaseSCache(scp);
3825 /* now free the patches */
3826 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
3827 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
3831 /* and mark the list as empty */
3832 *dirPatchespp = NULL;
3837 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3846 smb_dirListPatch_t *dirListPatchesp;
3847 smb_dirListPatch_t *curPatchp;
3851 osi_hyper_t dirLength;
3852 osi_hyper_t bufferOffset;
3853 osi_hyper_t curOffset;
3855 unsigned char *inCookiep;
3856 smb_dirSearch_t *dsp;
3860 unsigned long clientCookie;
3861 cm_pageHeader_t *pageHeaderp;
3862 cm_user_t *userp = NULL;
3869 long nextEntryCookie;
3870 int numDirChunks; /* # of 32 byte dir chunks in this entry */
3871 char resByte; /* reserved byte from the cookie */
3872 char *op; /* output data ptr */
3873 char *origOp; /* original value of op */
3874 cm_space_t *spacep; /* for pathname buffer */
3885 maxCount = smb_GetSMBParm(inp, 0);
3887 dirListPatchesp = NULL;
3889 caseFold = CM_FLAG_CASEFOLD;
3891 tp = smb_GetSMBData(inp, NULL);
3892 pathp = smb_ParseASCIIBlock(tp, &tp);
3893 if (smb_StoreAnsiFilenames)
3894 OemToChar(pathp,pathp);
3895 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
3897 /* bail out if request looks bad */
3898 if (!tp || !pathp) {
3899 return CM_ERROR_BADSMB;
3902 /* We can handle long names */
3903 if (vcp->flags & SMB_VCFLAG_USENT)
3904 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
3906 /* make sure we got a whole search status */
3907 if (dataLength < 21) {
3908 nextCookie = 0; /* start at the beginning of the dir */
3911 attribute = smb_GetSMBParm(inp, 1);
3913 /* handle volume info in another function */
3914 if (attribute & 0x8)
3915 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
3917 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
3918 maxCount, osi_LogSaveString(smb_logp, pathp));
3920 if (*pathp == 0) { /* null pathp, treat as root dir */
3921 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
3922 return CM_ERROR_NOFILES;
3926 dsp = smb_NewDirSearch(0);
3927 dsp->attribute = attribute;
3928 smb_Get8Dot3MaskFromPath(mask, pathp);
3929 memcpy(dsp->mask, mask, 11);
3931 /* track if this is likely to match a lot of entries */
3932 if (smb_IsStarMask(mask))
3937 /* pull the next cookie value out of the search status block */
3938 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3939 + (inCookiep[16]<<24);
3940 dsp = smb_FindDirSearch(inCookiep[12]);
3942 /* can't find dir search status; fatal error */
3943 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
3944 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
3945 return CM_ERROR_BADFD;
3947 attribute = dsp->attribute;
3948 resByte = inCookiep[0];
3950 /* copy out client cookie, in host byte order. Don't bother
3951 * interpreting it, since we're just passing it through, anyway.
3953 memcpy(&clientCookie, &inCookiep[17], 4);
3955 memcpy(mask, dsp->mask, 11);
3957 /* assume we're doing a star match if it has continued for more
3963 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
3964 nextCookie, dsp->cookie, attribute);
3966 userp = smb_GetUserFromVCP(vcp, inp);
3968 /* try to get the vnode for the path name next */
3969 lock_ObtainMutex(&dsp->mx);
3972 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
3976 spacep = inp->spacep;
3977 smb_StripLastComponent(spacep->data, NULL, pathp);
3978 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
3980 lock_ReleaseMutex(&dsp->mx);
3981 cm_ReleaseUser(userp);
3982 smb_DeleteDirSearch(dsp);
3983 smb_ReleaseDirSearch(dsp);
3984 return CM_ERROR_NOFILES;
3986 code = cm_NameI(cm_data.rootSCachep, spacep->data,
3987 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3990 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
3991 cm_ReleaseSCache(scp);
3992 lock_ReleaseMutex(&dsp->mx);
3993 cm_ReleaseUser(userp);
3994 smb_DeleteDirSearch(dsp);
3995 smb_ReleaseDirSearch(dsp);
3996 if ( WANTS_DFS_PATHNAMES(inp) )
3997 return CM_ERROR_PATH_NOT_COVERED;
3999 return CM_ERROR_BADSHARENAME;
4001 #endif /* DFS_SUPPORT */
4004 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4005 /* we need one hold for the entry we just stored into,
4006 * and one for our own processing. When we're done with this
4007 * function, we'll drop the one for our own processing.
4008 * We held it once from the namei call, and so we do another hold
4012 lock_ObtainMutex(&scp->mx);
4013 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4014 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4015 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4016 dsp->flags |= SMB_DIRSEARCH_BULKST;
4017 dsp->scp->bulkStatProgress = hzero;
4019 lock_ReleaseMutex(&scp->mx);
4022 lock_ReleaseMutex(&dsp->mx);
4024 cm_ReleaseUser(userp);
4025 smb_DeleteDirSearch(dsp);
4026 smb_ReleaseDirSearch(dsp);
4030 /* reserves space for parameter; we'll adjust it again later to the
4031 * real count of the # of entries we returned once we've actually
4032 * assembled the directory listing.
4034 smb_SetSMBParm(outp, 0, 0);
4036 /* get the directory size */
4037 lock_ObtainMutex(&scp->mx);
4038 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4039 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4041 lock_ReleaseMutex(&scp->mx);
4042 cm_ReleaseSCache(scp);
4043 cm_ReleaseUser(userp);
4044 smb_DeleteDirSearch(dsp);
4045 smb_ReleaseDirSearch(dsp);
4049 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4051 dirLength = scp->length;
4053 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4054 curOffset.HighPart = 0;
4055 curOffset.LowPart = nextCookie;
4056 origOp = op = smb_GetSMBData(outp, NULL);
4057 /* and write out the basic header */
4058 *op++ = 5; /* variable block */
4059 op += 2; /* skip vbl block length; we'll fill it in later */
4063 /* make sure that curOffset.LowPart doesn't point to the first
4064 * 32 bytes in the 2nd through last dir page, and that it doesn't
4065 * point at the first 13 32-byte chunks in the first dir page,
4066 * since those are dir and page headers, and don't contain useful
4069 temp = curOffset.LowPart & (2048-1);
4070 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4071 /* we're in the first page */
4072 if (temp < 13*32) temp = 13*32;
4075 /* we're in a later dir page */
4076 if (temp < 32) temp = 32;
4079 /* make sure the low order 5 bits are zero */
4082 /* now put temp bits back ito curOffset.LowPart */
4083 curOffset.LowPart &= ~(2048-1);
4084 curOffset.LowPart |= temp;
4086 /* check if we've returned all the names that will fit in the
4089 if (returnedNames >= maxCount) {
4090 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4091 returnedNames, maxCount);
4095 /* check if we've passed the dir's EOF */
4096 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4098 /* see if we can use the bufferp we have now; compute in which page
4099 * the current offset would be, and check whether that's the offset
4100 * of the buffer we have. If not, get the buffer.
4102 thyper.HighPart = curOffset.HighPart;
4103 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4104 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4107 buf_Release(bufferp);
4110 lock_ReleaseMutex(&scp->mx);
4111 lock_ObtainRead(&scp->bufCreateLock);
4112 code = buf_Get(scp, &thyper, &bufferp);
4113 lock_ReleaseRead(&scp->bufCreateLock);
4114 lock_ObtainMutex(&dsp->mx);
4116 /* now, if we're doing a star match, do bulk fetching of all of
4117 * the status info for files in the dir.
4120 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4121 lock_ObtainMutex(&scp->mx);
4122 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4123 LargeIntegerGreaterThanOrEqualTo(thyper,
4124 scp->bulkStatProgress)) {
4125 /* Don't bulk stat if risking timeout */
4126 int now = GetTickCount();
4127 if (now - req.startTime > RDRtimeout * 1000) {
4128 scp->bulkStatProgress = thyper;
4129 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4130 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4131 dsp->scp->bulkStatProgress = hzero;
4133 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4136 lock_ObtainMutex(&scp->mx);
4138 lock_ReleaseMutex(&dsp->mx);
4140 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4144 bufferOffset = thyper;
4146 /* now get the data in the cache */
4148 code = cm_SyncOp(scp, bufferp, userp, &req,
4150 CM_SCACHESYNC_NEEDCALLBACK |
4151 CM_SCACHESYNC_READ);
4153 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4157 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4159 if (cm_HaveBuffer(scp, bufferp, 0)) {
4160 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4164 /* otherwise, load the buffer and try again */
4165 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4167 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4168 scp, bufferp, code);
4173 buf_Release(bufferp);
4177 } /* if (wrong buffer) ... */
4179 /* now we have the buffer containing the entry we're interested in; copy
4180 * it out if it represents a non-deleted entry.
4182 entryInDir = curOffset.LowPart & (2048-1);
4183 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4185 /* page header will help tell us which entries are free. Page header
4186 * can change more often than once per buffer, since AFS 3 dir page size
4187 * may be less than (but not more than a buffer package buffer.
4189 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4190 temp &= ~(2048 - 1); /* turn off intra-page bits */
4191 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4193 /* now determine which entry we're looking at in the page. If it is
4194 * free (there's a free bitmap at the start of the dir), we should
4195 * skip these 32 bytes.
4197 slotInPage = (entryInDir & 0x7e0) >> 5;
4198 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4199 /* this entry is free */
4200 numDirChunks = 1; /* only skip this guy */
4204 tp = bufferp->datap + entryInBuffer;
4205 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4207 /* while we're here, compute the next entry's location, too,
4208 * since we'll need it when writing out the cookie into the dir
4211 * XXXX Probably should do more sanity checking.
4213 numDirChunks = cm_NameEntries(dep->name, NULL);
4215 /* compute the offset of the cookie representing the next entry */
4216 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4218 /* Compute 8.3 name if necessary */
4219 actualName = dep->name;
4220 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4221 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4222 actualName = shortName;
4225 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4226 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4227 osi_LogSaveString(smb_logp, actualName));
4229 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4230 /* this is one of the entries to use: it is not deleted
4231 * and it matches the star pattern we're looking for.
4234 /* Eliminate entries that don't match requested
4237 /* no hidden files */
4238 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4239 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4243 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4245 /* We have already done the cm_TryBulkStat above */
4246 fid.cell = scp->fid.cell;
4247 fid.volume = scp->fid.volume;
4248 fid.vnode = ntohl(dep->fid.vnode);
4249 fid.unique = ntohl(dep->fid.unique);
4250 fileType = cm_FindFileType(&fid);
4251 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4252 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4254 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4255 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4256 fileType == CM_SCACHETYPE_DFSLINK ||
4257 fileType == CM_SCACHETYPE_INVALID)
4258 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4263 memcpy(op, mask, 11); op += 11;
4264 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4265 *op++ = (char)(nextEntryCookie & 0xff);
4266 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4267 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4268 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4269 memcpy(op, &clientCookie, 4); op += 4;
4271 /* now we emit the attribute. This is sort of tricky,
4272 * since we need to really stat the file to find out
4273 * what type of entry we've got. Right now, we're
4274 * copying out data from a buffer, while holding the
4275 * scp locked, so it isn't really convenient to stat
4276 * something now. We'll put in a place holder now,
4277 * and make a second pass before returning this to get
4278 * the real attributes. So, we just skip the data for
4279 * now, and adjust it later. We allocate a patch
4280 * record to make it easy to find this point later.
4281 * The replay will happen at a time when it is safe to
4282 * unlock the directory.
4284 curPatchp = malloc(sizeof(*curPatchp));
4285 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4286 curPatchp->dptr = op;
4287 curPatchp->fid.cell = scp->fid.cell;
4288 curPatchp->fid.volume = scp->fid.volume;
4289 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
4290 curPatchp->fid.unique = ntohl(dep->fid.unique);
4292 /* do hidden attribute here since name won't be around when applying
4296 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4297 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4299 curPatchp->flags = 0;
4301 op += 9; /* skip attr, time, date and size */
4303 /* zero out name area. The spec says to pad with
4304 * spaces, but Samba doesn't, and neither do we.
4308 /* finally, we get to copy out the name; we know that
4309 * it fits in 8.3 or the pattern wouldn't match, but it
4310 * never hurts to be sure.
4312 strncpy(op, actualName, 13);
4313 if (smb_StoreAnsiFilenames)
4316 /* Uppercase if requested by client */
4317 if (!KNOWS_LONG_NAMES(inp))
4322 /* now, adjust the # of entries copied */
4324 } /* if we're including this name */
4327 /* and adjust curOffset to be where the new cookie is */
4328 thyper.HighPart = 0;
4329 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4330 curOffset = LargeIntegerAdd(thyper, curOffset);
4331 } /* while copying data for dir listing */
4333 /* release the mutex */
4334 lock_ReleaseMutex(&scp->mx);
4336 buf_Release(bufferp);
4340 /* apply and free last set of patches; if not doing a star match, this
4341 * will be empty, but better safe (and freeing everything) than sorry.
4343 smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
4345 /* special return code for unsuccessful search */
4346 if (code == 0 && dataLength < 21 && returnedNames == 0)
4347 code = CM_ERROR_NOFILES;
4349 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4350 returnedNames, code);
4353 smb_DeleteDirSearch(dsp);
4354 smb_ReleaseDirSearch(dsp);
4355 cm_ReleaseSCache(scp);
4356 cm_ReleaseUser(userp);
4360 /* finalize the output buffer */
4361 smb_SetSMBParm(outp, 0, returnedNames);
4362 temp = (long) (op - origOp);
4363 smb_SetSMBDataLength(outp, temp);
4365 /* the data area is a variable block, which has a 5 (already there)
4366 * followed by the length of the # of data bytes. We now know this to
4367 * be "temp," although that includes the 3 bytes of vbl block header.
4368 * Deduct for them and fill in the length field.
4370 temp -= 3; /* deduct vbl block info */
4371 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4372 origOp[1] = (char)(temp & 0xff);
4373 origOp[2] = (char)((temp>>8) & 0xff);
4374 if (returnedNames == 0)
4375 smb_DeleteDirSearch(dsp);
4376 smb_ReleaseDirSearch(dsp);
4377 cm_ReleaseSCache(scp);
4378 cm_ReleaseUser(userp);
4382 /* verify that this is a valid path to a directory. I don't know why they
4383 * don't use the get file attributes call.
4385 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4389 cm_scache_t *rootScp;
4390 cm_scache_t *newScp;
4399 pathp = smb_GetSMBData(inp, NULL);
4400 pathp = smb_ParseASCIIBlock(pathp, NULL);
4402 return CM_ERROR_BADFD;
4403 if (smb_StoreAnsiFilenames)
4404 OemToChar(pathp,pathp);
4405 osi_Log1(smb_logp, "SMB receive check path %s",
4406 osi_LogSaveString(smb_logp, pathp));
4408 rootScp = cm_data.rootSCachep;
4410 userp = smb_GetUserFromVCP(vcp, inp);
4412 caseFold = CM_FLAG_CASEFOLD;
4414 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4416 cm_ReleaseUser(userp);
4417 return CM_ERROR_NOSUCHPATH;
4419 code = cm_NameI(rootScp, pathp,
4420 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4421 userp, tidPathp, &req, &newScp);
4424 cm_ReleaseUser(userp);
4429 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4430 cm_ReleaseSCache(newScp);
4431 cm_ReleaseUser(userp);
4432 if ( WANTS_DFS_PATHNAMES(inp) )
4433 return CM_ERROR_PATH_NOT_COVERED;
4435 return CM_ERROR_BADSHARENAME;
4437 #endif /* DFS_SUPPORT */
4439 /* now lock the vnode with a callback; returns with newScp locked */
4440 lock_ObtainMutex(&newScp->mx);
4441 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4442 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4444 if (code != CM_ERROR_NOACCESS) {
4445 lock_ReleaseMutex(&newScp->mx);
4446 cm_ReleaseSCache(newScp);
4447 cm_ReleaseUser(userp);
4451 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4454 attrs = smb_Attributes(newScp);
4456 if (!(attrs & SMB_ATTR_DIRECTORY))
4457 code = CM_ERROR_NOTDIR;
4459 lock_ReleaseMutex(&newScp->mx);
4461 cm_ReleaseSCache(newScp);
4462 cm_ReleaseUser(userp);
4466 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4470 cm_scache_t *rootScp;
4471 unsigned short attribute;
4473 cm_scache_t *newScp;
4482 /* decode basic attributes we're passed */
4483 attribute = smb_GetSMBParm(inp, 0);
4484 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4486 pathp = smb_GetSMBData(inp, NULL);
4487 pathp = smb_ParseASCIIBlock(pathp, NULL);
4489 return CM_ERROR_BADSMB;
4490 if (smb_StoreAnsiFilenames)
4491 OemToChar(pathp,pathp);
4493 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4494 dosTime, attribute);
4496 rootScp = cm_data.rootSCachep;
4498 userp = smb_GetUserFromVCP(vcp, inp);
4500 caseFold = CM_FLAG_CASEFOLD;
4502 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4504 cm_ReleaseUser(userp);
4505 return CM_ERROR_NOSUCHFILE;
4507 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4508 tidPathp, &req, &newScp);
4511 cm_ReleaseUser(userp);
4516 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4517 cm_ReleaseSCache(newScp);
4518 cm_ReleaseUser(userp);
4519 if ( WANTS_DFS_PATHNAMES(inp) )
4520 return CM_ERROR_PATH_NOT_COVERED;
4522 return CM_ERROR_BADSHARENAME;
4524 #endif /* DFS_SUPPORT */
4526 /* now lock the vnode with a callback; returns with newScp locked; we
4527 * need the current status to determine what the new status is, in some
4530 lock_ObtainMutex(&newScp->mx);
4531 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4532 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4534 lock_ReleaseMutex(&newScp->mx);
4535 cm_ReleaseSCache(newScp);
4536 cm_ReleaseUser(userp);
4540 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4542 /* Check for RO volume */
4543 if (newScp->flags & CM_SCACHEFLAG_RO) {
4544 lock_ReleaseMutex(&newScp->mx);
4545 cm_ReleaseSCache(newScp);
4546 cm_ReleaseUser(userp);
4547 return CM_ERROR_READONLY;
4550 /* prepare for setattr call */
4553 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4554 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4556 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4557 /* we're told to make a writable file read-only */
4558 attr.unixModeBits = newScp->unixModeBits & ~0222;
4559 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4561 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4562 /* we're told to make a read-only file writable */
4563 attr.unixModeBits = newScp->unixModeBits | 0222;
4564 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4566 lock_ReleaseMutex(&newScp->mx);
4568 /* now call setattr */
4570 code = cm_SetAttr(newScp, &attr, userp, &req);
4574 cm_ReleaseSCache(newScp);
4575 cm_ReleaseUser(userp);
4580 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4584 cm_scache_t *rootScp;
4585 cm_scache_t *newScp, *dscp;
4597 pathp = smb_GetSMBData(inp, NULL);
4598 pathp = smb_ParseASCIIBlock(pathp, NULL);
4600 return CM_ERROR_BADSMB;
4602 if (*pathp == 0) /* null path */
4605 if (smb_StoreAnsiFilenames)
4606 OemToChar(pathp,pathp);
4608 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4609 osi_LogSaveString(smb_logp, pathp));
4611 rootScp = cm_data.rootSCachep;
4613 userp = smb_GetUserFromVCP(vcp, inp);
4615 /* we shouldn't need this for V3 requests, but we seem to */
4616 caseFold = CM_FLAG_CASEFOLD;
4618 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4620 cm_ReleaseUser(userp);
4621 return CM_ERROR_NOSUCHFILE;
4625 * XXX Strange hack XXX
4627 * As of Patch 5 (16 July 97), we are having the following problem:
4628 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4629 * requests to look up "desktop.ini" in all the subdirectories.
4630 * This can cause zillions of timeouts looking up non-existent cells
4631 * and volumes, especially in the top-level directory.
4633 * We have not found any way to avoid this or work around it except
4634 * to explicitly ignore the requests for mount points that haven't
4635 * yet been evaluated and for directories that haven't yet been
4638 * We should modify this hack to provide a fake desktop.ini file
4639 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4641 spacep = inp->spacep;
4642 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4643 #ifndef SPECIAL_FOLDERS
4644 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4645 code = cm_NameI(rootScp, spacep->data,
4646 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4647 userp, tidPathp, &req, &dscp);
4650 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4651 if ( WANTS_DFS_PATHNAMES(inp) )
4652 return CM_ERROR_PATH_NOT_COVERED;
4654 return CM_ERROR_BADSHARENAME;
4656 #endif /* DFS_SUPPORT */
4657 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4658 code = CM_ERROR_NOSUCHFILE;
4659 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4660 cm_buf_t *bp = buf_Find(dscp, &hzero);
4665 code = CM_ERROR_NOSUCHFILE;
4667 cm_ReleaseSCache(dscp);
4669 cm_ReleaseUser(userp);
4674 #endif /* SPECIAL_FOLDERS */
4676 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4677 tidPathp, &req, &newScp);
4679 cm_ReleaseUser(userp);
4684 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4685 cm_ReleaseSCache(newScp);
4686 cm_ReleaseUser(userp);
4687 if ( WANTS_DFS_PATHNAMES(inp) )
4688 return CM_ERROR_PATH_NOT_COVERED;
4690 return CM_ERROR_BADSHARENAME;
4692 #endif /* DFS_SUPPORT */
4694 /* now lock the vnode with a callback; returns with newScp locked */
4695 lock_ObtainMutex(&newScp->mx);
4696 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4697 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4699 lock_ReleaseMutex(&newScp->mx);
4700 cm_ReleaseSCache(newScp);
4701 cm_ReleaseUser(userp);
4705 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4708 /* use smb_Attributes instead. Also the fact that a file is
4709 * in a readonly volume doesn't mean it shojuld be marked as RO
4711 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
4712 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
4713 newScp->fileType == CM_SCACHETYPE_INVALID)
4714 attrs = SMB_ATTR_DIRECTORY;
4717 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
4718 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
4720 attrs = smb_Attributes(newScp);
4723 smb_SetSMBParm(outp, 0, attrs);
4725 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
4726 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
4727 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
4728 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
4729 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
4730 smb_SetSMBParm(outp, 5, 0);
4731 smb_SetSMBParm(outp, 6, 0);
4732 smb_SetSMBParm(outp, 7, 0);
4733 smb_SetSMBParm(outp, 8, 0);
4734 smb_SetSMBParm(outp, 9, 0);
4735 smb_SetSMBDataLength(outp, 0);
4736 lock_ReleaseMutex(&newScp->mx);
4738 cm_ReleaseSCache(newScp);
4739 cm_ReleaseUser(userp);
4744 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4748 osi_Log0(smb_logp, "SMB receive tree disconnect");
4750 /* find the tree and free it */
4751 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
4753 lock_ObtainWrite(&smb_rctLock);
4755 lock_ReleaseWrite(&smb_rctLock);
4756 smb_ReleaseTID(tidp);
4762 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4780 pathp = smb_GetSMBData(inp, NULL);
4781 pathp = smb_ParseASCIIBlock(pathp, NULL);
4782 if (smb_StoreAnsiFilenames)
4783 OemToChar(pathp,pathp);
4785 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
4787 #ifdef DEBUG_VERBOSE
4791 hexpath = osi_HexifyString( pathp );
4792 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
4797 share = smb_GetSMBParm(inp, 0);
4798 attribute = smb_GetSMBParm(inp, 1);
4800 spacep = inp->spacep;
4801 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4802 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
4803 /* special case magic file name for receiving IOCTL requests
4804 * (since IOCTL calls themselves aren't getting through).
4806 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4807 smb_SetupIoctlFid(fidp, spacep);
4808 smb_SetSMBParm(outp, 0, fidp->fid);
4809 smb_SetSMBParm(outp, 1, 0); /* attrs */
4810 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
4811 smb_SetSMBParm(outp, 3, 0);
4812 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
4813 smb_SetSMBParm(outp, 5, 0x7fff);
4814 /* pass the open mode back */
4815 smb_SetSMBParm(outp, 6, (share & 0xf));
4816 smb_SetSMBDataLength(outp, 0);
4817 smb_ReleaseFID(fidp);
4821 userp = smb_GetUserFromVCP(vcp, inp);
4823 caseFold = CM_FLAG_CASEFOLD;
4825 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4827 cm_ReleaseUser(userp);
4828 return CM_ERROR_NOSUCHPATH;
4830 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4831 tidPathp, &req, &scp);
4834 cm_ReleaseUser(userp);
4839 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4840 cm_ReleaseSCache(scp);
4841 cm_ReleaseUser(userp);
4842 if ( WANTS_DFS_PATHNAMES(inp) )
4843 return CM_ERROR_PATH_NOT_COVERED;
4845 return CM_ERROR_BADSHARENAME;
4847 #endif /* DFS_SUPPORT */
4849 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
4851 cm_ReleaseSCache(scp);
4852 cm_ReleaseUser(userp);
4856 /* don't need callback to check file type, since file types never
4857 * change, and namei and cm_Lookup all stat the object at least once on
4858 * a successful return.
4860 if (scp->fileType != CM_SCACHETYPE_FILE) {
4861 cm_ReleaseSCache(scp);
4862 cm_ReleaseUser(userp);
4863 return CM_ERROR_ISDIR;
4866 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
4867 osi_assertx(fidp, "null smb_fid_t");
4869 /* save a pointer to the vnode */
4871 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
4872 lock_ObtainMutex(&scp->mx);
4873 scp->flags |= CM_SCACHEFLAG_SMB_FID;
4874 lock_ReleaseMutex(&scp->mx);
4878 fidp->userp = userp;
4880 lock_ObtainMutex(&fidp->mx);
4881 if ((share & 0xf) == 0)
4882 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
4883 else if ((share & 0xf) == 1)
4884 fidp->flags |= SMB_FID_OPENWRITE;
4886 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
4887 lock_ReleaseMutex(&fidp->mx);
4889 lock_ObtainMutex(&scp->mx);
4890 smb_SetSMBParm(outp, 0, fidp->fid);
4891 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
4892 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
4893 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
4894 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
4895 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
4896 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
4897 /* pass the open mode back; XXXX add access checks */
4898 smb_SetSMBParm(outp, 6, (share & 0xf));
4899 smb_SetSMBDataLength(outp, 0);
4900 lock_ReleaseMutex(&scp->mx);
4903 cm_Open(scp, 0, userp);
4905 /* send and free packet */
4906 smb_ReleaseFID(fidp);
4907 cm_ReleaseUser(userp);
4908 /* don't release scp, since we've squirreled away the pointer in the fid struct */
4912 typedef struct smb_unlinkRock {
4917 char *maskp; /* pointer to the star pattern */
4920 cm_dirEntryList_t * matches;
4923 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4926 smb_unlinkRock_t *rockp;
4934 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
4935 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
4936 caseFold |= CM_FLAG_8DOT3;
4938 matchName = dep->name;
4939 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
4941 (rockp->flags & SMB_MASKFLAG_TILDE) &&
4942 !cm_Is8Dot3(dep->name)) {
4943 cm_Gen8Dot3Name(dep, shortName, NULL);
4944 matchName = shortName;
4945 /* 8.3 matches are always case insensitive */
4946 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
4949 osi_Log1(smb_logp, "Found match %s",
4950 osi_LogSaveString(smb_logp, matchName));
4952 cm_DirEntryListAdd(dep->name, &rockp->matches);
4956 /* If we made a case sensitive exact match, we might as well quit now. */
4957 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
4958 code = CM_ERROR_STOPNOW;
4967 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4976 smb_unlinkRock_t rock;
4985 attribute = smb_GetSMBParm(inp, 0);
4987 tp = smb_GetSMBData(inp, NULL);
4988 pathp = smb_ParseASCIIBlock(tp, &tp);
4989 if (smb_StoreAnsiFilenames)
4990 OemToChar(pathp,pathp);
4992 osi_Log1(smb_logp, "SMB receive unlink %s",
4993 osi_LogSaveString(smb_logp, pathp));
4995 spacep = inp->spacep;
4996 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4998 userp = smb_GetUserFromVCP(vcp, inp);
5000 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5002 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5004 cm_ReleaseUser(userp);
5005 return CM_ERROR_NOSUCHPATH;
5007 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5010 cm_ReleaseUser(userp);
5015 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5016 cm_ReleaseSCache(dscp);
5017 cm_ReleaseUser(userp);
5018 if ( WANTS_DFS_PATHNAMES(inp) )
5019 return CM_ERROR_PATH_NOT_COVERED;
5021 return CM_ERROR_BADSHARENAME;
5023 #endif /* DFS_SUPPORT */
5025 /* otherwise, scp points to the parent directory. */
5032 rock.maskp = smb_FindMask(pathp);
5033 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5036 thyper.HighPart = 0;
5041 rock.matches = NULL;
5043 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5044 * match. If that fails, we do a case insensitve match.
5046 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5047 !smb_IsStarMask(rock.maskp)) {
5048 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5051 thyper.HighPart = 0;
5052 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5057 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5059 if (code == CM_ERROR_STOPNOW)
5062 if (code == 0 && rock.matches) {
5063 cm_dirEntryList_t * entry;
5065 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5067 osi_Log1(smb_logp, "Unlinking %s",
5068 osi_LogSaveString(smb_logp, entry->name));
5069 code = cm_Unlink(dscp, entry->name, userp, &req);
5071 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5072 smb_NotifyChange(FILE_ACTION_REMOVED,
5073 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5074 dscp, entry->name, NULL, TRUE);
5078 cm_DirEntryListFree(&rock.matches);
5080 cm_ReleaseUser(userp);
5082 cm_ReleaseSCache(dscp);
5084 if (code == 0 && !rock.any)
5085 code = CM_ERROR_NOSUCHFILE;
5089 typedef struct smb_renameRock {
5090 cm_scache_t *odscp; /* old dir */
5091 cm_scache_t *ndscp; /* new dir */
5092 cm_user_t *userp; /* user */
5093 cm_req_t *reqp; /* request struct */
5094 smb_vc_t *vcp; /* virtual circuit */
5095 char *maskp; /* pointer to star pattern of old file name */
5096 int flags; /* tilde, casefold, etc */
5097 char *newNamep; /* ptr to the new file's name */
5098 char oldName[MAX_PATH];
5102 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5105 smb_renameRock_t *rockp;
5108 char shortName[13]="";
5110 rockp = (smb_renameRock_t *) vrockp;
5112 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5113 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5114 caseFold |= CM_FLAG_8DOT3;
5116 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5118 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5119 !cm_Is8Dot3(dep->name)) {
5120 cm_Gen8Dot3Name(dep, shortName, NULL);
5121 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5126 strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
5127 rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
5128 code = CM_ERROR_STOPNOW;
5138 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5141 cm_space_t *spacep = NULL;
5142 smb_renameRock_t rock;
5143 cm_scache_t *oldDscp = NULL;
5144 cm_scache_t *newDscp = NULL;
5145 cm_scache_t *tmpscp= NULL;
5146 cm_scache_t *tmpscp2 = NULL;
5156 userp = smb_GetUserFromVCP(vcp, inp);
5157 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5159 cm_ReleaseUser(userp);
5160 return CM_ERROR_NOSUCHPATH;
5164 spacep = inp->spacep;
5165 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5167 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5168 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5169 userp, tidPathp, &req, &oldDscp);
5171 cm_ReleaseUser(userp);
5176 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5177 cm_ReleaseSCache(oldDscp);
5178 cm_ReleaseUser(userp);
5179 if ( WANTS_DFS_PATHNAMES(inp) )
5180 return CM_ERROR_PATH_NOT_COVERED;
5182 return CM_ERROR_BADSHARENAME;
5184 #endif /* DFS_SUPPORT */
5186 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5187 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5188 userp, tidPathp, &req, &newDscp);
5191 cm_ReleaseSCache(oldDscp);
5192 cm_ReleaseUser(userp);
5197 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5198 cm_ReleaseSCache(oldDscp);
5199 cm_ReleaseSCache(newDscp);
5200 cm_ReleaseUser(userp);
5201 if ( WANTS_DFS_PATHNAMES(inp) )
5202 return CM_ERROR_PATH_NOT_COVERED;
5204 return CM_ERROR_BADSHARENAME;
5206 #endif /* DFS_SUPPORT */
5209 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5210 * next, get the component names, and lower case them.
5213 /* handle the old name first */
5215 oldLastNamep = oldPathp;
5219 /* and handle the new name, too */
5221 newLastNamep = newPathp;
5225 /* TODO: The old name could be a wildcard. The new name must not be */
5227 /* do the vnode call */
5228 rock.odscp = oldDscp;
5229 rock.ndscp = newDscp;
5233 rock.maskp = oldLastNamep;
5234 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5235 rock.newNamep = newLastNamep;
5236 rock.oldName[0] = '\0';
5239 /* Check if the file already exists; if so return error */
5240 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5241 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5242 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5244 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5245 osi_LogSaveString(smb_logp, newLastNamep));
5247 /* Check if the old and the new names differ only in case. If so return
5248 * success, else return CM_ERROR_EXISTS
5250 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5252 /* This would be a success only if the old file is *as same as* the new file */
5253 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5255 if (tmpscp == tmpscp2)
5258 code = CM_ERROR_EXISTS;
5259 cm_ReleaseSCache(tmpscp2);
5262 code = CM_ERROR_NOSUCHFILE;
5265 /* file exist, do not rename, also fixes move */
5266 osi_Log0(smb_logp, "Can't rename. Target already exists");
5267 code = CM_ERROR_EXISTS;
5271 cm_ReleaseSCache(tmpscp);
5272 cm_ReleaseSCache(newDscp);
5273 cm_ReleaseSCache(oldDscp);
5274 cm_ReleaseUser(userp);
5278 /* Now search the directory for the pattern, and do the appropriate rename when found */
5279 thyper.LowPart = 0; /* search dir from here */
5280 thyper.HighPart = 0;
5282 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5283 if (code == 0 && !rock.any) {
5285 thyper.HighPart = 0;
5286 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5287 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5289 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5291 if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
5292 code = cm_Rename(rock.odscp, rock.oldName,
5293 rock.ndscp, rock.newNamep, rock.userp,
5295 /* if the call worked, stop doing the search now, since we
5296 * really only want to rename one file.
5298 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5299 } else if (code == 0) {
5300 code = CM_ERROR_NOSUCHFILE;
5303 /* Handle Change Notification */
5305 * Being lazy, not distinguishing between files and dirs in this
5306 * filter, since we'd have to do a lookup.
5309 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5310 if (oldDscp == newDscp) {
5311 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5312 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5313 filter, oldDscp, oldLastNamep,
5314 newLastNamep, TRUE);
5316 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5317 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5318 filter, oldDscp, oldLastNamep,
5320 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5321 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5322 filter, newDscp, newLastNamep,
5328 cm_ReleaseSCache(tmpscp);
5329 cm_ReleaseUser(userp);
5330 cm_ReleaseSCache(oldDscp);
5331 cm_ReleaseSCache(newDscp);
5336 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5339 cm_space_t *spacep = NULL;
5340 cm_scache_t *oldDscp = NULL;
5341 cm_scache_t *newDscp = NULL;
5342 cm_scache_t *tmpscp= NULL;
5343 cm_scache_t *tmpscp2 = NULL;
5344 cm_scache_t *sscp = NULL;
5353 userp = smb_GetUserFromVCP(vcp, inp);
5355 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5357 cm_ReleaseUser(userp);
5358 return CM_ERROR_NOSUCHPATH;
5363 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5365 spacep = inp->spacep;
5366 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5368 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5369 userp, tidPathp, &req, &oldDscp);
5371 cm_ReleaseUser(userp);
5376 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5377 cm_ReleaseSCache(oldDscp);
5378 cm_ReleaseUser(userp);
5379 if ( WANTS_DFS_PATHNAMES(inp) )
5380 return CM_ERROR_PATH_NOT_COVERED;
5382 return CM_ERROR_BADSHARENAME;
5384 #endif /* DFS_SUPPORT */
5386 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5387 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5388 userp, tidPathp, &req, &newDscp);
5390 cm_ReleaseSCache(oldDscp);
5391 cm_ReleaseUser(userp);
5396 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5397 cm_ReleaseSCache(newDscp);
5398 cm_ReleaseSCache(oldDscp);
5399 cm_ReleaseUser(userp);
5400 if ( WANTS_DFS_PATHNAMES(inp) )
5401 return CM_ERROR_PATH_NOT_COVERED;
5403 return CM_ERROR_BADSHARENAME;
5405 #endif /* DFS_SUPPORT */
5407 /* Now, although we did two lookups for the two directories (because the same
5408 * directory can be referenced through different paths), we only allow hard links
5409 * within the same directory. */
5410 if (oldDscp != newDscp) {
5411 cm_ReleaseSCache(oldDscp);
5412 cm_ReleaseSCache(newDscp);
5413 cm_ReleaseUser(userp);
5414 return CM_ERROR_CROSSDEVLINK;
5417 /* handle the old name first */
5419 oldLastNamep = oldPathp;
5423 /* and handle the new name, too */
5425 newLastNamep = newPathp;
5429 /* now lookup the old name */
5430 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5431 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5433 cm_ReleaseSCache(oldDscp);
5434 cm_ReleaseSCache(newDscp);
5435 cm_ReleaseUser(userp);
5439 /* Check if the file already exists; if so return error */
5440 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5441 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5442 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5444 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5445 osi_LogSaveString(smb_logp, newLastNamep));
5447 /* if the existing link is to the same file, then we return success */
5449 if(sscp == tmpscp) {
5452 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5453 code = CM_ERROR_EXISTS;
5458 cm_ReleaseSCache(tmpscp);
5459 cm_ReleaseSCache(sscp);
5460 cm_ReleaseSCache(newDscp);
5461 cm_ReleaseSCache(oldDscp);
5462 cm_ReleaseUser(userp);
5466 /* now create the hardlink */
5467 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5468 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5469 osi_Log1(smb_logp," Link returns 0x%x", code);
5471 /* Handle Change Notification */
5473 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5474 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5475 smb_NotifyChange(FILE_ACTION_ADDED,
5476 filter, newDscp, newLastNamep,
5481 cm_ReleaseSCache(tmpscp);
5482 cm_ReleaseUser(userp);
5483 cm_ReleaseSCache(sscp);
5484 cm_ReleaseSCache(oldDscp);
5485 cm_ReleaseSCache(newDscp);
5490 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5497 tp = smb_GetSMBData(inp, NULL);
5498 oldPathp = smb_ParseASCIIBlock(tp, &tp);
5499 if (smb_StoreAnsiFilenames)
5500 OemToChar(oldPathp,oldPathp);
5501 newPathp = smb_ParseASCIIBlock(tp, &tp);
5502 if (smb_StoreAnsiFilenames)
5503 OemToChar(newPathp,newPathp);
5505 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5506 osi_LogSaveString(smb_logp, oldPathp),
5507 osi_LogSaveString(smb_logp, newPathp));
5509 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5511 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5517 typedef struct smb_rmdirRock {
5521 char *maskp; /* pointer to the star pattern */
5524 cm_dirEntryList_t * matches;
5527 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5530 smb_rmdirRock_t *rockp;
5535 rockp = (smb_rmdirRock_t *) vrockp;
5537 matchName = dep->name;
5538 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5539 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5541 match = (strcmp(matchName, rockp->maskp) == 0);
5543 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5544 !cm_Is8Dot3(dep->name)) {
5545 cm_Gen8Dot3Name(dep, shortName, NULL);
5546 matchName = shortName;
5547 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5552 cm_DirEntryListAdd(dep->name, &rockp->matches);
5558 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5566 smb_rmdirRock_t rock;
5575 tp = smb_GetSMBData(inp, NULL);
5576 pathp = smb_ParseASCIIBlock(tp, &tp);
5577 if (smb_StoreAnsiFilenames)
5578 OemToChar(pathp,pathp);
5580 spacep = inp->spacep;
5581 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5583 userp = smb_GetUserFromVCP(vcp, inp);
5585 caseFold = CM_FLAG_CASEFOLD;
5587 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5589 cm_ReleaseUser(userp);
5590 return CM_ERROR_NOSUCHPATH;
5592 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5593 userp, tidPathp, &req, &dscp);
5596 cm_ReleaseUser(userp);
5601 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5602 cm_ReleaseSCache(dscp);
5603 cm_ReleaseUser(userp);
5604 if ( WANTS_DFS_PATHNAMES(inp) )
5605 return CM_ERROR_PATH_NOT_COVERED;
5607 return CM_ERROR_BADSHARENAME;
5609 #endif /* DFS_SUPPORT */
5611 /* otherwise, scp points to the parent directory. */
5618 rock.maskp = lastNamep;
5619 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5622 thyper.HighPart = 0;
5626 rock.matches = NULL;
5628 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5629 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5630 if (code == 0 && !rock.any) {
5632 thyper.HighPart = 0;
5633 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5634 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5637 if (code == 0 && rock.matches) {
5638 cm_dirEntryList_t * entry;
5640 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5641 osi_Log1(smb_logp, "Removing directory %s",
5642 osi_LogSaveString(smb_logp, entry->name));
5644 code = cm_RemoveDir(dscp, entry->name, userp, &req);
5646 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5647 smb_NotifyChange(FILE_ACTION_REMOVED,
5648 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5649 dscp, entry->name, NULL, TRUE);
5653 cm_DirEntryListFree(&rock.matches);
5655 cm_ReleaseUser(userp);
5657 cm_ReleaseSCache(dscp);
5659 if (code == 0 && !rock.any)
5660 code = CM_ERROR_NOSUCHFILE;
5664 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5674 fid = smb_GetSMBParm(inp, 0);
5676 osi_Log1(smb_logp, "SMB flush fid %d", fid);
5678 fid = smb_ChainFID(fid, inp);
5679 fidp = smb_FindFID(vcp, fid, 0);
5681 return CM_ERROR_BADFD;
5683 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
5684 smb_CloseFID(vcp, fidp, NULL, 0);
5685 smb_ReleaseFID(fidp);
5686 return CM_ERROR_NOSUCHFILE;
5689 lock_ObtainMutex(&fidp->mx);
5690 if (fidp->flags & SMB_FID_IOCTL) {
5691 lock_ReleaseMutex(&fidp->mx);
5692 smb_ReleaseFID(fidp);
5693 return CM_ERROR_BADFD;
5695 lock_ReleaseMutex(&fidp->mx);
5697 userp = smb_GetUserFromVCP(vcp, inp);
5699 lock_ObtainMutex(&fidp->mx);
5700 if (fidp->flags & SMB_FID_OPENWRITE) {
5701 cm_scache_t * scp = fidp->scp;
5703 lock_ReleaseMutex(&fidp->mx);
5704 code = cm_FSync(scp, userp, &req);
5705 cm_ReleaseSCache(scp);
5708 lock_ReleaseMutex(&fidp->mx);
5711 smb_ReleaseFID(fidp);
5713 cm_ReleaseUser(userp);
5718 struct smb_FullNameRock {
5724 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
5728 struct smb_FullNameRock *vrockp;
5730 vrockp = (struct smb_FullNameRock *)rockp;
5732 if (!cm_Is8Dot3(dep->name)) {
5733 cm_Gen8Dot3Name(dep, shortName, NULL);
5735 if (cm_stricmp(shortName, vrockp->name) == 0) {
5736 vrockp->fullName = strdup(dep->name);
5737 return CM_ERROR_STOPNOW;
5740 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
5741 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
5742 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
5743 vrockp->fullName = strdup(dep->name);
5744 return CM_ERROR_STOPNOW;
5749 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
5750 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
5752 struct smb_FullNameRock rock;
5758 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
5759 if (code == CM_ERROR_STOPNOW)
5760 *newPathp = rock.fullName;
5762 *newPathp = strdup(pathp);
5765 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
5766 afs_uint32 dosTime) {
5769 cm_scache_t *dscp = NULL;
5771 cm_scache_t * scp = NULL;
5772 cm_scache_t *delscp = NULL;
5774 int nullcreator = 0;
5776 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
5777 fidp, fidp->fid, scp, vcp);
5780 lock_ObtainMutex(&fidp->mx);
5781 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
5782 lock_ReleaseMutex(&fidp->mx);
5783 osi_Log0(smb_logp, " No user specified. Not closing fid");
5784 return CM_ERROR_BADFD;
5787 userp = fidp->userp; /* no hold required since fidp is held
5788 throughout the function */
5789 lock_ReleaseMutex(&fidp->mx);
5794 lock_ObtainWrite(&smb_rctLock);
5796 osi_Log0(smb_logp, " Fid already closed.");
5797 lock_ReleaseWrite(&smb_rctLock);
5798 return CM_ERROR_BADFD;
5801 lock_ReleaseWrite(&smb_rctLock);
5803 lock_ObtainMutex(&fidp->mx);
5804 if (fidp->NTopen_dscp) {
5805 dscp = fidp->NTopen_dscp;
5806 cm_HoldSCache(dscp);
5809 if (fidp->NTopen_pathp) {
5810 pathp = strdup(fidp->NTopen_pathp);
5818 /* Don't jump the gun on an async raw write */
5819 while (fidp->raw_writers) {
5820 lock_ReleaseMutex(&fidp->mx);
5821 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
5822 lock_ObtainMutex(&fidp->mx);
5825 /* watch for ioctl closes, and read-only opens */
5827 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
5828 == SMB_FID_OPENWRITE) {
5829 if (dosTime != 0 && dosTime != -1) {
5830 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5831 /* This fixes defect 10958 */
5832 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
5833 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
5835 lock_ReleaseMutex(&fidp->mx);
5836 code = cm_FSync(scp, userp, &req);
5837 lock_ObtainMutex(&fidp->mx);
5842 /* unlock any pending locks */
5843 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
5844 scp->fileType == CM_SCACHETYPE_FILE) {
5848 lock_ReleaseMutex(&fidp->mx);
5850 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
5852 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
5853 lock_ObtainMutex(&scp->mx);
5855 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
5856 CM_SCACHESYNC_NEEDCALLBACK
5857 | CM_SCACHESYNC_GETSTATUS
5858 | CM_SCACHESYNC_LOCK);
5862 "smb CoreClose SyncOp failure code 0x%x", tcode);
5863 goto post_syncopdone;
5866 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
5868 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5872 lock_ReleaseMutex(&scp->mx);
5873 lock_ObtainMutex(&fidp->mx);
5876 if (fidp->flags & SMB_FID_DELONCLOSE) {
5879 lock_ReleaseMutex(&fidp->mx);
5881 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
5886 smb_FullName(dscp, delscp, pathp, &fullPathp, userp, &req);
5887 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5888 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
5891 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5892 smb_NotifyChange(FILE_ACTION_REMOVED,
5893 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5894 dscp, fullPathp, NULL, TRUE);
5897 code = cm_Unlink(dscp, fullPathp, userp, &req);
5900 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
5901 smb_NotifyChange(FILE_ACTION_REMOVED,
5902 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5903 dscp, fullPathp, NULL, TRUE);
5907 lock_ObtainMutex(&fidp->mx);
5908 fidp->flags &= ~SMB_FID_DELONCLOSE;
5911 /* if this was a newly created file, then clear the creator
5912 * in the stat cache entry. */
5913 if (fidp->flags & SMB_FID_CREATED) {
5915 fidp->flags &= ~SMB_FID_CREATED;
5918 if (fidp->flags & SMB_FID_NTOPEN) {
5919 cm_ReleaseSCache(fidp->NTopen_dscp);
5920 fidp->NTopen_dscp = NULL;
5921 free(fidp->NTopen_pathp);
5922 fidp->NTopen_pathp = NULL;
5923 fidp->flags &= ~SMB_FID_NTOPEN;
5925 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
5926 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
5929 if (fidp->NTopen_wholepathp) {
5930 free(fidp->NTopen_wholepathp);
5931 fidp->NTopen_wholepathp = NULL;
5935 cm_ReleaseSCache(fidp->scp);
5938 lock_ReleaseMutex(&fidp->mx);
5941 cm_ReleaseSCache(dscp);
5945 lock_ObtainMutex(&delscp->mx);
5947 delscp->flags |= CM_SCACHEFLAG_DELETED;
5948 lock_ReleaseMutex(&delscp->mx);
5950 cm_ReleaseSCache(delscp);
5954 lock_ObtainMutex(&scp->mx);
5955 if (nullcreator && scp->creator == userp)
5956 scp->creator = NULL;
5957 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
5958 lock_ReleaseMutex(&scp->mx);
5959 cm_ReleaseSCache(scp);
5968 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5976 fid = smb_GetSMBParm(inp, 0);
5977 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5979 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
5981 fid = smb_ChainFID(fid, inp);
5982 fidp = smb_FindFID(vcp, fid, 0);
5984 return CM_ERROR_BADFD;
5987 userp = smb_GetUserFromVCP(vcp, inp);
5989 code = smb_CloseFID(vcp, fidp, userp, dosTime);
5991 smb_ReleaseFID(fidp);
5992 cm_ReleaseUser(userp);
5997 * smb_ReadData -- common code for Read, Read And X, and Raw Read
5999 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6000 cm_user_t *userp, long *readp)
6006 osi_hyper_t fileLength;
6008 osi_hyper_t lastByte;
6009 osi_hyper_t bufferOffset;
6010 long bufIndex, nbytes;
6012 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6020 lock_ObtainMutex(&fidp->mx);
6023 lock_ObtainMutex(&scp->mx);
6025 if (offset.HighPart == 0) {
6026 chunk = offset.LowPart >> cm_logChunkSize;
6027 if (chunk != fidp->curr_chunk) {
6028 fidp->prev_chunk = fidp->curr_chunk;
6029 fidp->curr_chunk = chunk;
6031 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6034 lock_ReleaseMutex(&fidp->mx);
6036 /* start by looking up the file's end */
6037 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6038 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6042 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6044 /* now we have the entry locked, look up the length */
6045 fileLength = scp->length;
6047 /* adjust count down so that it won't go past EOF */
6048 thyper.LowPart = count;
6049 thyper.HighPart = 0;
6050 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6052 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6053 /* we'd read past EOF, so just stop at fileLength bytes.
6054 * Start by computing how many bytes remain in the file.
6056 thyper = LargeIntegerSubtract(fileLength, offset);
6058 /* if we are past EOF, read 0 bytes */
6059 if (LargeIntegerLessThanZero(thyper))
6062 count = thyper.LowPart;
6067 /* now, copy the data one buffer at a time,
6068 * until we've filled the request packet
6071 /* if we've copied all the data requested, we're done */
6072 if (count <= 0) break;
6074 /* otherwise, load up a buffer of data */
6075 thyper.HighPart = offset.HighPart;
6076 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6077 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6080 buf_Release(bufferp);
6083 lock_ReleaseMutex(&scp->mx);
6085 lock_ObtainRead(&scp->bufCreateLock);
6086 code = buf_Get(scp, &thyper, &bufferp);
6087 lock_ReleaseRead(&scp->bufCreateLock);
6089 lock_ObtainMutex(&scp->mx);
6090 if (code) goto done;
6091 bufferOffset = thyper;
6093 /* now get the data in the cache */
6095 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6096 CM_SCACHESYNC_NEEDCALLBACK |
6097 CM_SCACHESYNC_READ);
6101 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6103 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6105 /* otherwise, load the buffer and try again */
6106 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6110 buf_Release(bufferp);
6114 } /* if (wrong buffer) ... */
6116 /* now we have the right buffer loaded. Copy out the
6117 * data from here to the user's buffer.
6119 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6121 /* and figure out how many bytes we want from this buffer */
6122 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6123 if (nbytes > count) nbytes = count; /* don't go past EOF */
6125 /* now copy the data */
6126 memcpy(op, bufferp->datap + bufIndex, nbytes);
6128 /* adjust counters, pointers, etc. */
6131 thyper.LowPart = nbytes;
6132 thyper.HighPart = 0;
6133 offset = LargeIntegerAdd(thyper, offset);
6137 lock_ReleaseMutex(&scp->mx);
6139 buf_Release(bufferp);
6141 if (code == 0 && sequential)
6142 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
6144 cm_ReleaseSCache(scp);
6150 * smb_WriteData -- common code for Write and Raw Write
6152 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
6153 cm_user_t *userp, long *writtenp)
6159 osi_hyper_t fileLength; /* file's length at start of write */
6160 osi_hyper_t minLength; /* don't read past this */
6161 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6163 osi_hyper_t thyper; /* hyper tmp variable */
6164 osi_hyper_t bufferOffset;
6165 afs_uint32 bufIndex; /* index in buffer where our data is */
6167 osi_hyper_t writeBackOffset;/* offset of region to write back when
6172 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6173 fidp->fid, offsetp->LowPart, count);
6183 lock_ObtainMutex(&fidp->mx);
6184 /* make sure we have a writable FD */
6185 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6186 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6187 fidp->fid, fidp->flags);
6188 lock_ReleaseMutex(&fidp->mx);
6189 code = CM_ERROR_BADFDOP;
6195 lock_ReleaseMutex(&fidp->mx);
6197 lock_ObtainMutex(&scp->mx);
6198 /* start by looking up the file's end */
6199 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6200 CM_SCACHESYNC_NEEDCALLBACK
6201 | CM_SCACHESYNC_SETSTATUS
6202 | CM_SCACHESYNC_GETSTATUS);
6206 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6208 /* now we have the entry locked, look up the length */
6209 fileLength = scp->length;
6210 minLength = fileLength;
6211 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6212 minLength = scp->serverLength;
6214 /* adjust file length if we extend past EOF */
6215 thyper.LowPart = count;
6216 thyper.HighPart = 0;
6217 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6218 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6219 /* we'd write past EOF, so extend the file */
6220 scp->mask |= CM_SCACHEMASK_LENGTH;
6221 scp->length = thyper;
6222 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6224 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6226 /* now, if the new position (thyper) and the old (offset) are in
6227 * different storeback windows, remember to store back the previous
6228 * storeback window when we're done with the write.
6230 if ((thyper.LowPart & (-cm_chunkSize)) !=
6231 (offset.LowPart & (-cm_chunkSize))) {
6232 /* they're different */
6234 writeBackOffset.HighPart = offset.HighPart;
6235 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
6240 /* now, copy the data one buffer at a time, until we've filled the
6243 /* if we've copied all the data requested, we're done */
6247 /* handle over quota or out of space */
6248 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6249 *writtenp = written;
6250 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6254 /* otherwise, load up a buffer of data */
6255 thyper.HighPart = offset.HighPart;
6256 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6257 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6260 lock_ReleaseMutex(&bufferp->mx);
6261 buf_Release(bufferp);
6264 lock_ReleaseMutex(&scp->mx);
6266 lock_ObtainRead(&scp->bufCreateLock);
6267 code = buf_Get(scp, &thyper, &bufferp);
6268 lock_ReleaseRead(&scp->bufCreateLock);
6270 lock_ObtainMutex(&bufferp->mx);
6271 lock_ObtainMutex(&scp->mx);
6272 if (code) goto done;
6274 bufferOffset = thyper;
6276 /* now get the data in the cache */
6278 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6279 CM_SCACHESYNC_NEEDCALLBACK
6280 | CM_SCACHESYNC_WRITE
6281 | CM_SCACHESYNC_BUFLOCKED);
6285 cm_SyncOpDone(scp, bufferp,
6286 CM_SCACHESYNC_NEEDCALLBACK
6287 | CM_SCACHESYNC_WRITE
6288 | CM_SCACHESYNC_BUFLOCKED);
6290 /* If we're overwriting the entire buffer, or
6291 * if we're writing at or past EOF, mark the
6292 * buffer as current so we don't call
6293 * cm_GetBuffer. This skips the fetch from the
6294 * server in those cases where we're going to
6295 * obliterate all the data in the buffer anyway,
6296 * or in those cases where there is no useful
6297 * data at the server to start with.
6299 * Use minLength instead of scp->length, since
6300 * the latter has already been updated by this
6303 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6304 || LargeIntegerEqualTo(offset, bufferp->offset)
6305 && (count >= cm_data.buf_blockSize
6306 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6307 ConvertLongToLargeInteger(count)),
6309 if (count < cm_data.buf_blockSize
6310 && bufferp->dataVersion == -1)
6311 memset(bufferp->datap, 0,
6312 cm_data.buf_blockSize);
6313 bufferp->dataVersion = scp->dataVersion;
6316 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6318 /* otherwise, load the buffer and try again */
6319 lock_ReleaseMutex(&bufferp->mx);
6320 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6322 lock_ReleaseMutex(&scp->mx);
6323 lock_ObtainMutex(&bufferp->mx);
6324 lock_ObtainMutex(&scp->mx);
6328 lock_ReleaseMutex(&bufferp->mx);
6329 buf_Release(bufferp);
6333 } /* if (wrong buffer) ... */
6335 /* now we have the right buffer loaded. Copy out the
6336 * data from here to the user's buffer.
6338 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6340 /* and figure out how many bytes we want from this buffer */
6341 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6343 nbytes = count; /* don't go past end of request */
6345 /* now copy the data */
6346 memcpy(bufferp->datap + bufIndex, op, nbytes);
6347 buf_SetDirty(bufferp, bufIndex, nbytes);
6349 /* and record the last writer */
6350 if (bufferp->userp != userp) {
6353 cm_ReleaseUser(bufferp->userp);
6354 bufferp->userp = userp;
6357 /* adjust counters, pointers, etc. */
6361 thyper.LowPart = nbytes;
6362 thyper.HighPart = 0;
6363 offset = LargeIntegerAdd(thyper, offset);
6367 lock_ReleaseMutex(&scp->mx);
6370 lock_ReleaseMutex(&bufferp->mx);
6371 buf_Release(bufferp);
6374 lock_ObtainMutex(&fidp->mx);
6375 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6376 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6377 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6378 fidp->NTopen_dscp, fidp->NTopen_pathp,
6381 lock_ReleaseMutex(&fidp->mx);
6383 if (code == 0 && doWriteBack) {
6385 lock_ObtainMutex(&scp->mx);
6386 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6388 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6389 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6391 lock_ReleaseMutex(&scp->mx);
6392 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6393 writeBackOffset.HighPart, cm_chunkSize, 0, userp);
6394 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6397 cm_ReleaseSCache(scp);
6399 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6400 fidp->fid, code, *writtenp);
6404 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6407 unsigned short count;
6409 unsigned short hint;
6410 long written = 0, total_written = 0;
6415 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6417 int inDataBlockCount;
6419 fd = smb_GetSMBParm(inp, 0);
6420 count = smb_GetSMBParm(inp, 1);
6421 offset.HighPart = 0; /* too bad */
6422 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6423 hint = smb_GetSMBParm(inp, 4);
6425 op = smb_GetSMBData(inp, NULL);
6426 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6428 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6429 fd, offset.LowPart, count);
6431 fd = smb_ChainFID(fd, inp);
6432 fidp = smb_FindFID(vcp, fd, 0);
6434 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6435 return CM_ERROR_BADFD;
6438 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6439 smb_CloseFID(vcp, fidp, NULL, 0);
6440 smb_ReleaseFID(fidp);
6441 return CM_ERROR_NOSUCHFILE;
6444 lock_ObtainMutex(&fidp->mx);
6445 if (fidp->flags & SMB_FID_IOCTL) {
6446 lock_ReleaseMutex(&fidp->mx);
6447 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6448 smb_ReleaseFID(fidp);
6449 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6452 lock_ReleaseMutex(&fidp->mx);
6453 userp = smb_GetUserFromVCP(vcp, inp);
6457 LARGE_INTEGER LOffset;
6458 LARGE_INTEGER LLength;
6460 pid = ((smb_t *) inp)->pid;
6461 key = cm_GenerateKey(vcp->vcID, pid, fd);
6463 LOffset.HighPart = offset.HighPart;
6464 LOffset.LowPart = offset.LowPart;
6465 LLength.HighPart = 0;
6466 LLength.LowPart = count;
6468 lock_ObtainMutex(&fidp->scp->mx);
6469 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6470 lock_ReleaseMutex(&fidp->scp->mx);
6473 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6478 /* special case: 0 bytes transferred means truncate to this position */
6482 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6486 truncAttr.mask = CM_ATTRMASK_LENGTH;
6487 truncAttr.length.LowPart = offset.LowPart;
6488 truncAttr.length.HighPart = 0;
6489 lock_ObtainMutex(&fidp->mx);
6490 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6491 fidp->flags |= SMB_FID_LENGTHSETDONE;
6492 lock_ReleaseMutex(&fidp->mx);
6493 smb_SetSMBParm(outp, 0, 0 /* count */);
6494 smb_SetSMBDataLength(outp, 0);
6499 * Work around bug in NT client
6501 * When copying a file, the NT client should first copy the data,
6502 * then copy the last write time. But sometimes the NT client does
6503 * these in the wrong order, so the data copies would inadvertently
6504 * cause the last write time to be overwritten. We try to detect this,
6505 * and don't set client mod time if we think that would go against the
6508 lock_ObtainMutex(&fidp->mx);
6509 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6510 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6511 fidp->scp->clientModTime = time(NULL);
6513 lock_ReleaseMutex(&fidp->mx);
6516 while ( code == 0 && count > 0 ) {
6517 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6518 if (code == 0 && written == 0)
6519 code = CM_ERROR_PARTIALWRITE;
6521 offset = LargeIntegerAdd(offset,
6522 ConvertLongToLargeInteger(written));
6523 count -= (unsigned short)written;
6524 total_written += written;
6528 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6529 total_written, code);
6531 /* set the packet data length to 3 bytes for the data block header,
6532 * plus the size of the data.
6534 smb_SetSMBParm(outp, 0, total_written);
6535 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6536 smb_SetSMBParm(outp, 3, hint);
6537 smb_SetSMBDataLength(outp, 0);
6540 smb_ReleaseFID(fidp);
6541 cm_ReleaseUser(userp);
6546 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6547 NCB *ncbp, raw_write_cont_t *rwcp)
6556 fd = smb_GetSMBParm(inp, 0);
6557 fidp = smb_FindFID(vcp, fd, 0);
6559 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6560 smb_CloseFID(vcp, fidp, NULL, 0);
6561 smb_ReleaseFID(fidp);
6565 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6566 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6568 userp = smb_GetUserFromVCP(vcp, inp);
6571 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6573 if (rwcp->writeMode & 0x1) { /* synchronous */
6576 smb_FormatResponsePacket(vcp, inp, outp);
6577 op = (smb_t *) outp;
6578 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6579 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6580 smb_SetSMBDataLength(outp, 0);
6581 smb_SendPacket(vcp, outp);
6582 smb_FreePacket(outp);
6584 else { /* asynchronous */
6585 lock_ObtainMutex(&fidp->mx);
6586 fidp->raw_writers--;
6587 if (fidp->raw_writers == 0)
6588 thrd_SetEvent(fidp->raw_write_event);
6589 lock_ReleaseMutex(&fidp->mx);
6592 /* Give back raw buffer */
6593 lock_ObtainMutex(&smb_RawBufLock);
6594 *((char **)rawBuf) = smb_RawBufs;
6595 smb_RawBufs = rawBuf;
6596 lock_ReleaseMutex(&smb_RawBufLock);
6598 smb_ReleaseFID(fidp);
6599 cm_ReleaseUser(userp);
6602 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6607 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6610 long count, written = 0, total_written = 0;
6617 unsigned short writeMode;
6619 fd = smb_GetSMBParm(inp, 0);
6620 totalCount = smb_GetSMBParm(inp, 1);
6621 count = smb_GetSMBParm(inp, 10);
6622 writeMode = smb_GetSMBParm(inp, 7);
6624 op = (char *) inp->data;
6625 op += smb_GetSMBParm(inp, 11);
6627 offset.HighPart = 0;
6628 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
6630 if (*inp->wctp == 14) {
6631 /* we received a 64-bit file offset */
6632 #ifdef AFS_LARGEFILES
6633 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
6635 if (LargeIntegerLessThanZero(offset)) {
6637 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
6638 offset.HighPart, offset.LowPart);
6639 return CM_ERROR_BADSMB;
6642 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
6644 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
6645 return CM_ERROR_BADSMB;
6648 offset.HighPart = 0;
6651 offset.HighPart = 0; /* 32-bit file offset */
6655 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
6656 fd, offset.HighPart, offset.LowPart, count);
6658 " WriteRaw WriteMode 0x%x",
6661 fd = smb_ChainFID(fd, inp);
6662 fidp = smb_FindFID(vcp, fd, 0);
6664 return CM_ERROR_BADFD;
6667 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6668 smb_CloseFID(vcp, fidp, NULL, 0);
6669 smb_ReleaseFID(fidp);
6670 return CM_ERROR_NOSUCHFILE;
6676 LARGE_INTEGER LOffset;
6677 LARGE_INTEGER LLength;
6679 pid = ((smb_t *) inp)->pid;
6680 key = cm_GenerateKey(vcp->vcID, pid, fd);
6682 LOffset.HighPart = offset.HighPart;
6683 LOffset.LowPart = offset.LowPart;
6684 LLength.HighPart = 0;
6685 LLength.LowPart = count;
6687 lock_ObtainMutex(&fidp->scp->mx);
6688 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6689 lock_ReleaseMutex(&fidp->scp->mx);
6692 smb_ReleaseFID(fidp);
6697 userp = smb_GetUserFromVCP(vcp, inp);
6700 * Work around bug in NT client
6702 * When copying a file, the NT client should first copy the data,
6703 * then copy the last write time. But sometimes the NT client does
6704 * these in the wrong order, so the data copies would inadvertently
6705 * cause the last write time to be overwritten. We try to detect this,
6706 * and don't set client mod time if we think that would go against the
6709 lock_ObtainMutex(&fidp->mx);
6710 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
6711 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6712 fidp->scp->clientModTime = time(NULL);
6714 lock_ReleaseMutex(&fidp->mx);
6717 while ( code == 0 && count > 0 ) {
6718 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6719 if (code == 0 && written == 0)
6720 code = CM_ERROR_PARTIALWRITE;
6722 offset = LargeIntegerAdd(offset,
6723 ConvertLongToLargeInteger(written));
6726 total_written += written;
6730 /* Get a raw buffer */
6733 lock_ObtainMutex(&smb_RawBufLock);
6735 /* Get a raw buf, from head of list */
6736 rawBuf = smb_RawBufs;
6737 smb_RawBufs = *(char **)smb_RawBufs;
6740 code = CM_ERROR_USESTD;
6742 lock_ReleaseMutex(&smb_RawBufLock);
6745 /* Don't allow a premature Close */
6746 if (code == 0 && (writeMode & 1) == 0) {
6747 lock_ObtainMutex(&fidp->mx);
6748 fidp->raw_writers++;
6749 thrd_ResetEvent(fidp->raw_write_event);
6750 lock_ReleaseMutex(&fidp->mx);
6753 smb_ReleaseFID(fidp);
6754 cm_ReleaseUser(userp);
6757 smb_SetSMBParm(outp, 0, total_written);
6758 smb_SetSMBDataLength(outp, 0);
6759 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6764 offset = LargeIntegerAdd(offset,
6765 ConvertLongToLargeInteger(count));
6769 rwcp->offset.HighPart = offset.HighPart;
6770 rwcp->offset.LowPart = offset.LowPart;
6771 rwcp->count = totalCount - count;
6772 rwcp->writeMode = writeMode;
6773 rwcp->alreadyWritten = total_written;
6775 /* set the packet data length to 3 bytes for the data block header,
6776 * plus the size of the data.
6778 smb_SetSMBParm(outp, 0, 0xffff);
6779 smb_SetSMBDataLength(outp, 0);
6784 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6787 long count, finalCount;
6795 fd = smb_GetSMBParm(inp, 0);
6796 count = smb_GetSMBParm(inp, 1);
6797 offset.HighPart = 0; /* too bad */
6798 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
6800 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
6801 fd, offset.LowPart, count);
6803 fd = smb_ChainFID(fd, inp);
6804 fidp = smb_FindFID(vcp, fd, 0);
6806 return CM_ERROR_BADFD;
6808 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6809 smb_CloseFID(vcp, fidp, NULL, 0);
6810 smb_ReleaseFID(fidp);
6811 return CM_ERROR_NOSUCHFILE;
6814 lock_ObtainMutex(&fidp->mx);
6815 if (fidp->flags & SMB_FID_IOCTL) {
6816 lock_ReleaseMutex(&fidp->mx);
6817 code = smb_IoctlRead(fidp, vcp, inp, outp);
6818 smb_ReleaseFID(fidp);
6821 lock_ReleaseMutex(&fidp->mx);
6824 LARGE_INTEGER LOffset, LLength;
6827 pid = ((smb_t *) inp)->pid;
6828 key = cm_GenerateKey(vcp->vcID, pid, fd);
6830 LOffset.HighPart = 0;
6831 LOffset.LowPart = offset.LowPart;
6832 LLength.HighPart = 0;
6833 LLength.LowPart = count;
6835 lock_ObtainMutex(&fidp->scp->mx);
6836 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
6837 lock_ReleaseMutex(&fidp->scp->mx);
6840 smb_ReleaseFID(fidp);
6844 userp = smb_GetUserFromVCP(vcp, inp);
6846 /* remember this for final results */
6847 smb_SetSMBParm(outp, 0, count);
6848 smb_SetSMBParm(outp, 1, 0);
6849 smb_SetSMBParm(outp, 2, 0);
6850 smb_SetSMBParm(outp, 3, 0);
6851 smb_SetSMBParm(outp, 4, 0);
6853 /* set the packet data length to 3 bytes for the data block header,
6854 * plus the size of the data.
6856 smb_SetSMBDataLength(outp, count+3);
6858 /* get op ptr after putting in the parms, since otherwise we don't
6859 * know where the data really is.
6861 op = smb_GetSMBData(outp, NULL);
6863 /* now emit the data block header: 1 byte of type and 2 bytes of length */
6864 *op++ = 1; /* data block marker */
6865 *op++ = (unsigned char) (count & 0xff);
6866 *op++ = (unsigned char) ((count >> 8) & 0xff);
6868 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
6870 /* fix some things up */
6871 smb_SetSMBParm(outp, 0, finalCount);
6872 smb_SetSMBDataLength(outp, finalCount+3);
6874 smb_ReleaseFID(fidp);
6876 cm_ReleaseUser(userp);
6880 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6887 cm_scache_t *dscp; /* dir we're dealing with */
6888 cm_scache_t *scp; /* file we're creating */
6890 int initialModeBits;
6900 /* compute initial mode bits based on read-only flag in attributes */
6901 initialModeBits = 0777;
6903 tp = smb_GetSMBData(inp, NULL);
6904 pathp = smb_ParseASCIIBlock(tp, &tp);
6905 if (smb_StoreAnsiFilenames)
6906 OemToChar(pathp,pathp);
6908 if (strcmp(pathp, "\\") == 0)
6909 return CM_ERROR_EXISTS;
6911 spacep = inp->spacep;
6912 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
6914 userp = smb_GetUserFromVCP(vcp, inp);
6916 caseFold = CM_FLAG_CASEFOLD;
6918 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
6920 cm_ReleaseUser(userp);
6921 return CM_ERROR_NOSUCHPATH;
6924 code = cm_NameI(cm_data.rootSCachep, spacep->data,
6925 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
6926 userp, tidPathp, &req, &dscp);
6929 cm_ReleaseUser(userp);
6934 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6935 cm_ReleaseSCache(dscp);
6936 cm_ReleaseUser(userp);
6937 if ( WANTS_DFS_PATHNAMES(inp) )
6938 return CM_ERROR_PATH_NOT_COVERED;
6940 return CM_ERROR_BADSHARENAME;
6942 #endif /* DFS_SUPPORT */
6944 /* otherwise, scp points to the parent directory. Do a lookup, and
6945 * fail if we find it. Otherwise, we do the create.
6951 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
6952 if (scp) cm_ReleaseSCache(scp);
6953 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
6954 if (code == 0) code = CM_ERROR_EXISTS;
6955 cm_ReleaseSCache(dscp);
6956 cm_ReleaseUser(userp);
6960 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
6961 setAttr.clientModTime = time(NULL);
6962 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
6963 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6964 smb_NotifyChange(FILE_ACTION_ADDED,
6965 FILE_NOTIFY_CHANGE_DIR_NAME,
6966 dscp, lastNamep, NULL, TRUE);
6968 /* we don't need this any longer */
6969 cm_ReleaseSCache(dscp);
6972 /* something went wrong creating or truncating the file */
6973 cm_ReleaseUser(userp);
6977 /* otherwise we succeeded */
6978 smb_SetSMBDataLength(outp, 0);
6979 cm_ReleaseUser(userp);
6984 BOOL smb_IsLegalFilename(char *filename)
6987 * Find the longest substring of filename that does not contain
6988 * any of the chars in illegalChars. If that substring is less
6989 * than the length of the whole string, then one or more of the
6990 * illegal chars is in filename.
6992 if (strcspn(filename, illegalChars) < strlen(filename))
6998 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7006 cm_scache_t *dscp; /* dir we're dealing with */
7007 cm_scache_t *scp; /* file we're creating */
7009 int initialModeBits;
7017 int created = 0; /* the file was new */
7022 excl = (inp->inCom == 0x03)? 0 : 1;
7024 attributes = smb_GetSMBParm(inp, 0);
7025 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7027 /* compute initial mode bits based on read-only flag in attributes */
7028 initialModeBits = 0666;
7029 if (attributes & SMB_ATTR_READONLY)
7030 initialModeBits &= ~0222;
7032 tp = smb_GetSMBData(inp, NULL);
7033 pathp = smb_ParseASCIIBlock(tp, &tp);
7034 if (smb_StoreAnsiFilenames)
7035 OemToChar(pathp,pathp);
7037 spacep = inp->spacep;
7038 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7040 userp = smb_GetUserFromVCP(vcp, inp);
7042 caseFold = CM_FLAG_CASEFOLD;
7044 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7046 cm_ReleaseUser(userp);
7047 return CM_ERROR_NOSUCHPATH;
7049 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
7050 userp, tidPathp, &req, &dscp);
7053 cm_ReleaseUser(userp);
7058 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7059 cm_ReleaseSCache(dscp);
7060 cm_ReleaseUser(userp);
7061 if ( WANTS_DFS_PATHNAMES(inp) )
7062 return CM_ERROR_PATH_NOT_COVERED;
7064 return CM_ERROR_BADSHARENAME;
7066 #endif /* DFS_SUPPORT */
7068 /* otherwise, scp points to the parent directory. Do a lookup, and
7069 * truncate the file if we find it, otherwise we create the file.
7076 if (!smb_IsLegalFilename(lastNamep))
7077 return CM_ERROR_BADNTFILENAME;
7079 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7080 #ifdef DEBUG_VERBOSE
7083 hexp = osi_HexifyString( lastNamep );
7084 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7089 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7090 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7091 cm_ReleaseSCache(dscp);
7092 cm_ReleaseUser(userp);
7096 /* if we get here, if code is 0, the file exists and is represented by
7097 * scp. Otherwise, we have to create it.
7101 /* oops, file shouldn't be there */
7102 cm_ReleaseSCache(dscp);
7103 cm_ReleaseSCache(scp);
7104 cm_ReleaseUser(userp);
7105 return CM_ERROR_EXISTS;
7108 setAttr.mask = CM_ATTRMASK_LENGTH;
7109 setAttr.length.LowPart = 0;
7110 setAttr.length.HighPart = 0;
7111 code = cm_SetAttr(scp, &setAttr, userp, &req);
7114 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7115 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7116 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7120 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7121 smb_NotifyChange(FILE_ACTION_ADDED,
7122 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7123 dscp, lastNamep, NULL, TRUE);
7124 } else if (!excl && code == CM_ERROR_EXISTS) {
7125 /* not an exclusive create, and someone else tried
7126 * creating it already, then we open it anyway. We
7127 * don't bother retrying after this, since if this next
7128 * fails, that means that the file was deleted after
7129 * we started this call.
7131 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7134 setAttr.mask = CM_ATTRMASK_LENGTH;
7135 setAttr.length.LowPart = 0;
7136 setAttr.length.HighPart = 0;
7137 code = cm_SetAttr(scp, &setAttr, userp, &req);
7142 /* we don't need this any longer */
7143 cm_ReleaseSCache(dscp);
7146 /* something went wrong creating or truncating the file */
7147 if (scp) cm_ReleaseSCache(scp);
7148 cm_ReleaseUser(userp);
7152 /* make sure we only open files */
7153 if (scp->fileType != CM_SCACHETYPE_FILE) {
7154 cm_ReleaseSCache(scp);
7155 cm_ReleaseUser(userp);
7156 return CM_ERROR_ISDIR;
7159 /* now all we have to do is open the file itself */
7160 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7161 osi_assertx(fidp, "null smb_fid_t");
7165 lock_ObtainMutex(&fidp->mx);
7166 /* always create it open for read/write */
7167 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7169 /* remember that the file was newly created */
7171 fidp->flags |= SMB_FID_CREATED;
7173 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7175 /* save a pointer to the vnode */
7177 lock_ObtainMutex(&scp->mx);
7178 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7179 lock_ReleaseMutex(&scp->mx);
7182 fidp->userp = userp;
7183 lock_ReleaseMutex(&fidp->mx);
7185 smb_SetSMBParm(outp, 0, fidp->fid);
7186 smb_SetSMBDataLength(outp, 0);
7188 cm_Open(scp, 0, userp);
7190 smb_ReleaseFID(fidp);
7191 cm_ReleaseUser(userp);
7192 /* leave scp held since we put it in fidp->scp */
7196 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7199 osi_hyper_t new_offset;
7210 fd = smb_GetSMBParm(inp, 0);
7211 whence = smb_GetSMBParm(inp, 1);
7212 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7214 /* try to find the file descriptor */
7215 fd = smb_ChainFID(fd, inp);
7216 fidp = smb_FindFID(vcp, fd, 0);
7218 return CM_ERROR_BADFD;
7220 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7221 smb_CloseFID(vcp, fidp, NULL, 0);
7222 smb_ReleaseFID(fidp);
7223 return CM_ERROR_NOSUCHFILE;
7226 lock_ObtainMutex(&fidp->mx);
7227 if (fidp->flags & SMB_FID_IOCTL) {
7228 lock_ReleaseMutex(&fidp->mx);
7229 smb_ReleaseFID(fidp);
7230 return CM_ERROR_BADFD;
7232 lock_ReleaseMutex(&fidp->mx);
7234 userp = smb_GetUserFromVCP(vcp, inp);
7236 lock_ObtainMutex(&fidp->mx);
7239 lock_ReleaseMutex(&fidp->mx);
7240 lock_ObtainMutex(&scp->mx);
7241 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7242 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7244 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7246 /* offset from current offset */
7247 new_offset = LargeIntegerAdd(fidp->offset,
7248 ConvertLongToLargeInteger(offset));
7250 else if (whence == 2) {
7251 /* offset from current EOF */
7252 new_offset = LargeIntegerAdd(scp->length,
7253 ConvertLongToLargeInteger(offset));
7255 new_offset = ConvertLongToLargeInteger(offset);
7258 fidp->offset = new_offset;
7259 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7260 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7261 smb_SetSMBDataLength(outp, 0);
7263 lock_ReleaseMutex(&scp->mx);
7264 smb_ReleaseFID(fidp);
7265 cm_ReleaseSCache(scp);
7266 cm_ReleaseUser(userp);
7270 /* dispatch all of the requests received in a packet. Due to chaining, this may
7271 * be more than one request.
7273 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7274 NCB *ncbp, raw_write_cont_t *rwcp)
7278 unsigned long code = 0;
7279 unsigned char *outWctp;
7280 int nparms; /* # of bytes of parameters */
7282 int nbytes; /* bytes of data, excluding count */
7285 unsigned short errCode;
7286 unsigned long NTStatus;
7288 unsigned char errClass;
7289 unsigned int oldGen;
7290 DWORD oldTime, newTime;
7292 /* get easy pointer to the data */
7293 smbp = (smb_t *) inp->data;
7295 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7296 /* setup the basic parms for the initial request in the packet */
7297 inp->inCom = smbp->com;
7298 inp->wctp = &smbp->wct;
7300 inp->ncb_length = ncbp->ncb_length;
7305 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7306 /* log it and discard it */
7307 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7308 __FILE__, __LINE__, ncbp->ncb_length);
7309 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7313 /* We are an ongoing op */
7314 thrd_Increment(&ongoingOps);
7316 /* set up response packet for receiving output */
7317 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7318 smb_FormatResponsePacket(vcp, inp, outp);
7319 outWctp = outp->wctp;
7321 /* Remember session generation number and time */
7322 oldGen = sessionGen;
7323 oldTime = GetTickCount();
7325 while (inp->inCom != 0xff) {
7326 dp = &smb_dispatchTable[inp->inCom];
7328 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7329 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7330 code = outp->resumeCode;
7334 /* process each request in the packet; inCom, wctp and inCount
7335 * are already set up.
7337 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7340 /* now do the dispatch */
7341 /* start by formatting the response record a little, as a default */
7342 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7344 outWctp[1] = 0xff; /* no operation */
7345 outWctp[2] = 0; /* padding */
7350 /* not a chained request, this is a more reasonable default */
7351 outWctp[0] = 0; /* wct of zero */
7352 outWctp[1] = 0; /* and bcc (word) of zero */
7356 /* once set, stays set. Doesn't matter, since we never chain
7357 * "no response" calls.
7359 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7363 /* we have a recognized operation */
7365 if (inp->inCom == 0x1d)
7367 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7369 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",myCrt_Dispatch(inp->inCom),vcp,vcp->lana,vcp->lsn);
7370 code = (*(dp->procp)) (vcp, inp, outp);
7371 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",code,vcp,vcp->lana,vcp->lsn);
7373 if ( code == CM_ERROR_BADSMB ||
7374 code == CM_ERROR_BADOP )
7376 #endif /* LOG_PACKET */
7379 if (oldGen != sessionGen) {
7380 newTime = GetTickCount();
7381 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7382 newTime - oldTime, ncbp->ncb_length);
7383 osi_Log2(smb_logp, "Pkt straddled session startup, "
7384 "took %d ms, ncb length %d", newTime - oldTime, ncbp->ncb_length);
7388 /* bad opcode, fail the request, after displaying it */
7389 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7392 #endif /* LOG_PACKET */
7395 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7396 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7397 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7398 if (code == IDCANCEL)
7401 code = CM_ERROR_BADOP;
7404 /* catastrophic failure: log as much as possible */
7405 if (code == CM_ERROR_BADSMB) {
7406 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7410 #endif /* LOG_PACKET */
7411 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7414 code = CM_ERROR_INVAL;
7417 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7418 thrd_Decrement(&ongoingOps);
7423 /* now, if we failed, turn the current response into an empty
7424 * one, and fill in the response packet's error code.
7427 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7428 smb_MapNTError(code, &NTStatus);
7429 outWctp = outp->wctp;
7430 smbp = (smb_t *) &outp->data;
7431 if (code != CM_ERROR_PARTIALWRITE
7432 && code != CM_ERROR_BUFFERTOOSMALL
7433 && code != CM_ERROR_GSSCONTINUE) {
7434 /* nuke wct and bcc. For a partial
7435 * write or an in-process authentication handshake,
7436 * assume they're OK.
7442 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7443 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7444 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7445 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7446 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7450 smb_MapCoreError(code, vcp, &errCode, &errClass);
7451 outWctp = outp->wctp;
7452 smbp = (smb_t *) &outp->data;
7453 if (code != CM_ERROR_PARTIALWRITE) {
7454 /* nuke wct and bcc. For a partial
7455 * write, assume they're OK.
7461 smbp->errLow = (unsigned char) (errCode & 0xff);
7462 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7463 smbp->rcls = errClass;
7466 } /* error occurred */
7468 /* if we're here, we've finished one request. Look to see if
7469 * this is a chained opcode. If it is, setup things to process
7470 * the chained request, and setup the output buffer to hold the
7471 * chained response. Start by finding the next input record.
7473 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7474 break; /* not a chained req */
7475 tp = inp->wctp; /* points to start of last request */
7476 /* in a chained request, the first two
7477 * parm fields are required, and are
7478 * AndXCommand/AndXReserved and
7480 if (tp[0] < 2) break;
7481 if (tp[1] == 0xff) break; /* no more chained opcodes */
7483 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7486 /* and now append the next output request to the end of this
7487 * last request. Begin by finding out where the last response
7488 * ends, since that's where we'll put our new response.
7490 outWctp = outp->wctp; /* ptr to out parameters */
7491 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7492 nparms = outWctp[0] << 1;
7493 tp = outWctp + nparms + 1; /* now points to bcc field */
7494 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7495 tp += 2 /* for the count itself */ + nbytes;
7496 /* tp now points to the new output record; go back and patch the
7497 * second parameter (off2) to point to the new record.
7499 temp = (unsigned int)(tp - outp->data);
7500 outWctp[3] = (unsigned char) (temp & 0xff);
7501 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7502 outWctp[2] = 0; /* padding */
7503 outWctp[1] = inp->inCom; /* next opcode */
7505 /* finally, setup for the next iteration */
7508 } /* while loop over all requests in the packet */
7510 /* now send the output packet, and return */
7512 smb_SendPacket(vcp, outp);
7513 thrd_Decrement(&ongoingOps);
7518 /* Wait for Netbios() calls to return, and make the results available to server
7519 * threads. Note that server threads can't wait on the NCBevents array
7520 * themselves, because NCB events are manual-reset, and the servers would race
7521 * each other to reset them.
7523 void smb_ClientWaiter(void *parmp)
7528 while (smbShutdownFlag == 0) {
7529 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7531 if (code == WAIT_OBJECT_0)
7534 /* error checking */
7535 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7537 int abandonIdx = code - WAIT_ABANDONED_0;
7538 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7541 if (code == WAIT_IO_COMPLETION)
7543 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7547 if (code == WAIT_TIMEOUT)
7549 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7552 if (code == WAIT_FAILED)
7554 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7557 idx = code - WAIT_OBJECT_0;
7559 /* check idx range! */
7560 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7562 /* this is fatal - log as much as possible */
7563 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7564 osi_assertx(0, "invalid index");
7567 thrd_ResetEvent(NCBevents[idx]);
7568 thrd_SetEvent(NCBreturns[0][idx]);
7573 * Try to have one NCBRECV request waiting for every live session. Not more
7574 * than one, because if there is more than one, it's hard to handle Write Raw.
7576 void smb_ServerWaiter(void *parmp)
7579 int idx_session, idx_NCB;
7582 while (smbShutdownFlag == 0) {
7584 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7586 if (code == WAIT_OBJECT_0)
7589 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7591 int abandonIdx = code - WAIT_ABANDONED_0;
7592 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7595 if (code == WAIT_IO_COMPLETION)
7597 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7601 if (code == WAIT_TIMEOUT)
7603 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7606 if (code == WAIT_FAILED)
7608 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7611 idx_session = code - WAIT_OBJECT_0;
7613 /* check idx range! */
7614 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
7616 /* this is fatal - log as much as possible */
7617 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
7618 osi_assertx(0, "invalid index");
7623 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
7625 if (code == WAIT_OBJECT_0) {
7626 if (smbShutdownFlag == 1)
7632 /* error checking */
7633 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7635 int abandonIdx = code - WAIT_ABANDONED_0;
7636 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7639 if (code == WAIT_IO_COMPLETION)
7641 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
7645 if (code == WAIT_TIMEOUT)
7647 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
7650 if (code == WAIT_FAILED)
7652 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
7655 idx_NCB = code - WAIT_OBJECT_0;
7657 /* check idx range! */
7658 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
7660 /* this is fatal - log as much as possible */
7661 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
7662 osi_assertx(0, "invalid index");
7665 /* Link them together */
7666 NCBsessions[idx_NCB] = idx_session;
7669 ncbp = NCBs[idx_NCB];
7670 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
7671 ncbp->ncb_command = NCBRECV | ASYNCH;
7672 ncbp->ncb_lana_num = lanas[idx_session];
7673 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
7674 ncbp->ncb_event = NCBevents[idx_NCB];
7675 ncbp->ncb_length = SMB_PACKETSIZE;
7681 * The top level loop for handling SMB request messages. Each server thread
7682 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
7683 * NCB and buffer for the incoming request are loaned to us.
7685 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
7686 * to immediately send a request for the rest of the data. This must come
7687 * before any other traffic for that session, so we delay setting the session
7688 * event until that data has come in.
7690 void smb_Server(VOID *parmp)
7692 INT_PTR myIdx = (INT_PTR) parmp;
7696 smb_packet_t *outbufp;
7698 int idx_NCB, idx_session;
7700 smb_vc_t *vcp = NULL;
7703 rx_StartClientThread();
7706 outbufp = GetPacket();
7707 outbufp->ncbp = outncbp;
7715 smb_ResetServerPriority();
7717 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
7720 /* terminate silently if shutdown flag is set */
7721 if (code == WAIT_OBJECT_0) {
7722 if (smbShutdownFlag == 1) {
7723 thrd_SetEvent(smb_ServerShutdown[myIdx]);
7729 /* error checking */
7730 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7732 int abandonIdx = code - WAIT_ABANDONED_0;
7733 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
7736 if (code == WAIT_IO_COMPLETION)
7738 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
7742 if (code == WAIT_TIMEOUT)
7744 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
7747 if (code == WAIT_FAILED)
7749 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
7752 idx_NCB = code - WAIT_OBJECT_0;
7754 /* check idx range! */
7755 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
7757 /* this is fatal - log as much as possible */
7758 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
7759 osi_assertx(0, "invalid index");
7762 ncbp = NCBs[idx_NCB];
7763 idx_session = NCBsessions[idx_NCB];
7764 rc = ncbp->ncb_retcode;
7766 if (rc != NRC_PENDING && rc != NRC_GOODRET)
7767 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
7771 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7775 /* Can this happen? Or is it just my UNIX paranoia? */
7776 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
7781 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
7784 /* Client closed session */
7785 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7787 lock_ObtainMutex(&vcp->mx);
7788 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7789 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7791 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7792 lock_ReleaseMutex(&vcp->mx);
7793 lock_ObtainWrite(&smb_globalLock);
7794 dead_sessions[vcp->session] = TRUE;
7795 lock_ReleaseWrite(&smb_globalLock);
7796 smb_CleanupDeadVC(vcp);
7800 lock_ReleaseMutex(&vcp->mx);
7806 /* Treat as transient error */
7807 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
7810 "dispatch smb recv failed, message incomplete, ncb_length %d",
7813 "SMB message incomplete, "
7814 "length %d", ncbp->ncb_length);
7817 * We used to discard the packet.
7818 * Instead, try handling it normally.
7822 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7826 /* A weird error code. Log it, sleep, and continue. */
7827 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
7829 lock_ObtainMutex(&vcp->mx);
7830 if (vcp && vcp->errorCount++ > 3) {
7831 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
7832 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
7833 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
7835 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
7836 lock_ReleaseMutex(&vcp->mx);
7837 lock_ObtainWrite(&smb_globalLock);
7838 dead_sessions[vcp->session] = TRUE;
7839 lock_ReleaseWrite(&smb_globalLock);
7840 smb_CleanupDeadVC(vcp);
7844 lock_ReleaseMutex(&vcp->mx);
7850 lock_ReleaseMutex(&vcp->mx);
7852 thrd_SetEvent(SessionEvents[idx_session]);
7857 /* Success, so now dispatch on all the data in the packet */
7859 smb_concurrentCalls++;
7860 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
7861 smb_maxObsConcurrentCalls = smb_concurrentCalls;
7864 * If at this point vcp is NULL (implies that packet was invalid)
7865 * then we are in big trouble. This means either :
7866 * a) we have the wrong NCB.
7867 * b) Netbios screwed up the call.
7868 * c) The VC was already marked dead before we were able to
7870 * Obviously this implies that
7871 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
7872 * lanas[idx_session] != ncbp->ncb_lana_num )
7873 * Either way, we can't do anything with this packet.
7874 * Log, sleep and resume.
7877 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
7881 ncbp->ncb_lana_num);
7883 /* Also log in the trace log. */
7884 osi_Log4(smb_logp, "Server: VCP does not exist!"
7885 "LSNs[idx_session]=[%d],"
7886 "lanas[idx_session]=[%d],"
7887 "ncbp->ncb_lsn=[%d],"
7888 "ncbp->ncb_lana_num=[%d]",
7892 ncbp->ncb_lana_num);
7894 /* thrd_Sleep(1000); Don't bother sleeping */
7895 thrd_SetEvent(SessionEvents[idx_session]);
7896 smb_concurrentCalls--;
7900 smb_SetRequestStartTime();
7902 vcp->errorCount = 0;
7903 bufp = (struct smb_packet *) ncbp->ncb_buffer;
7904 smbp = (smb_t *)bufp->data;
7909 if (smbp->com == 0x1d) {
7910 /* Special handling for Write Raw */
7911 raw_write_cont_t rwc;
7912 EVENT_HANDLE rwevent;
7913 char eventName[MAX_PATH];
7915 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
7916 if (rwc.code == 0) {
7917 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
7918 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7919 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7920 ncbp->ncb_command = NCBRECV | ASYNCH;
7921 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
7922 ncbp->ncb_lana_num = vcp->lana;
7923 ncbp->ncb_buffer = rwc.buf;
7924 ncbp->ncb_length = 65535;
7925 ncbp->ncb_event = rwevent;
7927 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
7928 thrd_CloseHandle(rwevent);
7930 thrd_SetEvent(SessionEvents[idx_session]);
7932 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
7934 else if (smbp->com == 0xa0) {
7936 * Serialize the handling for NT Transact
7939 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7940 thrd_SetEvent(SessionEvents[idx_session]);
7942 thrd_SetEvent(SessionEvents[idx_session]);
7943 /* TODO: what else needs to be serialized? */
7944 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
7947 __except( smb_ServerExceptionFilter() ) {
7950 smb_concurrentCalls--;
7953 thrd_SetEvent(NCBavails[idx_NCB]);
7960 * Exception filter for the server threads. If an exception occurs in the
7961 * dispatch routines, which is where exceptions are most common, then do a
7962 * force trace and give control to upstream exception handlers. Useful for
7965 DWORD smb_ServerExceptionFilter(void) {
7966 /* While this is not the best time to do a trace, if it succeeds, then
7967 * we have a trace (assuming tracing was enabled). Otherwise, this should
7968 * throw a second exception.
7970 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
7971 afsd_ForceTrace(TRUE);
7972 buf_ForceTrace(TRUE);
7973 return EXCEPTION_CONTINUE_SEARCH;
7977 * Create a new NCB and associated events, packet buffer, and "space" buffer.
7978 * If the number of server threads is M, and the number of live sessions is
7979 * N, then the number of NCB's in use at any time either waiting for, or
7980 * holding, received messages is M + N, so that is how many NCB's get created.
7982 void InitNCBslot(int idx)
7984 struct smb_packet *bufp;
7985 EVENT_HANDLE retHandle;
7987 char eventName[MAX_PATH];
7989 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
7991 NCBs[idx] = GetNCB();
7992 sprintf(eventName,"NCBavails[%d]", idx);
7993 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
7994 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7995 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
7996 sprintf(eventName,"NCBevents[%d]", idx);
7997 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
7998 if ( GetLastError() == ERROR_ALREADY_EXISTS )
7999 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8000 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8001 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8002 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8003 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8004 for (i=0; i<smb_NumServerThreads; i++)
8005 NCBreturns[i][idx] = retHandle;
8007 bufp->spacep = cm_GetSpace();
8011 /* listen for new connections */
8012 void smb_Listener(void *parmp)
8018 int session, thread;
8019 smb_vc_t *vcp = NULL;
8021 char rname[NCBNAMSZ+1];
8022 char cname[MAX_COMPUTERNAME_LENGTH+1];
8023 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8024 INT_PTR lana = (INT_PTR) parmp;
8028 /* retrieve computer name */
8029 GetComputerName(cname, &cnamelen);
8032 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8033 memset(ncbp, 0, sizeof(NCB));
8036 ncbp->ncb_command = NCBLISTEN;
8037 ncbp->ncb_rto = 0; /* No receive timeout */
8038 ncbp->ncb_sto = 0; /* No send timeout */
8040 /* pad out with spaces instead of null termination */
8041 len = (long)strlen(smb_localNamep);
8042 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8043 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8045 strcpy(ncbp->ncb_callname, "*");
8046 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8048 ncbp->ncb_lana_num = (UCHAR)lana;
8050 code = Netbios(ncbp);
8052 if (code == NRC_BRIDGE) {
8053 int lanaRemaining = 0;
8055 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
8060 "NCBLISTEN lana=%d failed with NRC_BRIDGE. Listener thread exiting.",
8061 ncbp->ncb_lana_num, code);
8063 for (i = 0; i < lana_list.length; i++) {
8064 if (lana_list.lana[i] == ncbp->ncb_lana_num) {
8065 smb_StopListener(ncbp, lana_list.lana[i]);
8066 lana_list.lana[i] = 255;
8068 if (lana_list.lana[i] != 255)
8072 if (lanaRemaining == 0) {
8073 cm_VolStatus_Network_Stopped(cm_NetbiosName
8078 smb_ListenerState = SMB_LISTENER_STOPPED;
8079 smb_LANadapter = -1;
8080 lana_list.length = 0;
8084 } else if (code != 0) {
8085 char tbuffer[AFSPATHMAX];
8087 /* terminate silently if shutdown flag is set */
8088 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1) {
8093 "NCBLISTEN lana=%d failed with code %d",
8094 ncbp->ncb_lana_num, code);
8096 "Client exiting due to network failure. Please restart client.\n");
8099 "Client exiting due to network failure. Please restart client.\n"
8100 "NCBLISTEN lana=%d failed with code %d",
8101 ncbp->ncb_lana_num, code);
8103 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8104 MB_OK|MB_SERVICE_NOTIFICATION);
8105 osi_panic(tbuffer, __FILE__, __LINE__);
8108 /* check for remote conns */
8109 /* first get remote name and insert null terminator */
8110 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8111 for (i=NCBNAMSZ; i>0; i--) {
8112 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8118 /* compare with local name */
8120 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8121 flags |= SMB_VCFLAG_REMOTECONN;
8124 lock_ObtainMutex(&smb_ListenerLock);
8126 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8127 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8129 /* now ncbp->ncb_lsn is the connection ID */
8130 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8131 if (vcp->session == 0) {
8132 /* New generation */
8133 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8136 /* Log session startup */
8138 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8139 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8140 #endif /* NOTSERVICE */
8141 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8142 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8144 if (reportSessionStartups) {
8145 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8148 lock_ObtainMutex(&vcp->mx);
8149 strcpy(vcp->rname, rname);
8150 vcp->flags |= flags;
8151 lock_ReleaseMutex(&vcp->mx);
8153 /* Allocate slot in session arrays */
8154 /* Re-use dead session if possible, otherwise add one more */
8155 /* But don't look at session[0], it is reserved */
8156 lock_ObtainWrite(&smb_globalLock);
8157 for (session = 1; session < numSessions; session++) {
8158 if (dead_sessions[session]) {
8159 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8160 dead_sessions[session] = FALSE;
8164 lock_ReleaseWrite(&smb_globalLock);
8166 /* We are re-using an existing VC because the lsn and lana
8168 session = vcp->session;
8170 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8172 /* Log session startup */
8174 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8175 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8176 #endif /* NOTSERVICE */
8177 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8178 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8180 if (reportSessionStartups) {
8181 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8185 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8186 unsigned long code = CM_ERROR_ALLBUSY;
8187 smb_packet_t * outp = GetPacket();
8188 unsigned char *outWctp;
8191 smb_FormatResponsePacket(vcp, NULL, outp);
8194 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8195 unsigned long NTStatus;
8196 smb_MapNTError(code, &NTStatus);
8197 outWctp = outp->wctp;
8198 smbp = (smb_t *) &outp->data;
8202 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8203 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8204 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8205 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8206 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8208 unsigned short errCode;
8209 unsigned char errClass;
8210 smb_MapCoreError(code, vcp, &errCode, &errClass);
8211 outWctp = outp->wctp;
8212 smbp = (smb_t *) &outp->data;
8216 smbp->errLow = (unsigned char) (errCode & 0xff);
8217 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8218 smbp->rcls = errClass;
8220 smb_SendPacket(vcp, outp);
8221 smb_FreePacket(outp);
8223 lock_ObtainMutex(&vcp->mx);
8224 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8225 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8227 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8228 lock_ReleaseMutex(&vcp->mx);
8229 lock_ObtainWrite(&smb_globalLock);
8230 dead_sessions[vcp->session] = TRUE;
8231 lock_ReleaseWrite(&smb_globalLock);
8232 smb_CleanupDeadVC(vcp);
8234 lock_ReleaseMutex(&vcp->mx);
8237 /* assert that we do not exceed the maximum number of sessions or NCBs.
8238 * we should probably want to wait for a session to be freed in case
8241 osi_assertx(session < SESSION_MAX - 1, "invalid session");
8242 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
8244 lock_ObtainMutex(&vcp->mx);
8245 vcp->session = session;
8246 lock_ReleaseMutex(&vcp->mx);
8247 lock_ObtainWrite(&smb_globalLock);
8248 LSNs[session] = ncbp->ncb_lsn;
8249 lanas[session] = ncbp->ncb_lana_num;
8250 lock_ReleaseWrite(&smb_globalLock);
8252 if (session == numSessions) {
8253 /* Add new NCB for new session */
8254 char eventName[MAX_PATH];
8256 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8258 InitNCBslot(numNCBs);
8259 lock_ObtainWrite(&smb_globalLock);
8261 lock_ReleaseWrite(&smb_globalLock);
8262 thrd_SetEvent(NCBavails[0]);
8263 thrd_SetEvent(NCBevents[0]);
8264 for (thread = 0; thread < smb_NumServerThreads; thread++)
8265 thrd_SetEvent(NCBreturns[thread][0]);
8266 /* Also add new session event */
8267 sprintf(eventName, "SessionEvents[%d]", session);
8268 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8269 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8270 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8271 lock_ObtainWrite(&smb_globalLock);
8273 lock_ReleaseWrite(&smb_globalLock);
8274 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8275 thrd_SetEvent(SessionEvents[0]);
8277 thrd_SetEvent(SessionEvents[session]);
8283 lock_ReleaseMutex(&smb_ListenerLock);
8284 } /* dispatch while loop */
8289 /* initialize Netbios */
8290 int smb_NetbiosInit(void)
8293 int i, lana, code, l;
8295 int delname_tried=0;
8298 lana_number_t lanaNum;
8300 /* setup the NCB system */
8303 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8304 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8305 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8307 if (smb_LANadapter != -1)
8308 afsi_log("LAN adapter number %d", smb_LANadapter);
8310 afsi_log("LAN adapter number not determined");
8313 afsi_log("Set for gateway service");
8315 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8317 /* something went horribly wrong. We can't proceed without a netbios name */
8319 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8320 osi_panic(buf, __FILE__, __LINE__);
8323 /* remember the name */
8324 len = (int)strlen(cm_NetbiosName);
8326 free(smb_localNamep);
8327 smb_localNamep = malloc(len+1);
8328 strcpy(smb_localNamep, cm_NetbiosName);
8329 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8332 if (smb_LANadapter == -1) {
8333 ncbp->ncb_command = NCBENUM;
8334 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8335 ncbp->ncb_length = sizeof(lana_list);
8336 code = Netbios(ncbp);
8338 afsi_log("Netbios NCBENUM error code %d", code);
8339 osi_panic(s, __FILE__, __LINE__);
8343 lana_list.length = 1;
8344 lana_list.lana[0] = smb_LANadapter;
8347 for (i = 0; i < lana_list.length; i++) {
8348 /* reset the adaptor: in Win32, this is required for every process, and
8349 * acts as an init call, not as a real hardware reset.
8351 ncbp->ncb_command = NCBRESET;
8352 ncbp->ncb_callname[0] = 100;
8353 ncbp->ncb_callname[2] = 100;
8354 ncbp->ncb_lana_num = lana_list.lana[i];
8355 code = Netbios(ncbp);
8357 code = ncbp->ncb_retcode;
8359 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8360 lana_list.lana[i] = 255; /* invalid lana */
8362 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8366 /* and declare our name so we can receive connections */
8367 memset(ncbp, 0, sizeof(*ncbp));
8368 len=lstrlen(smb_localNamep);
8369 memset(smb_sharename,' ',NCBNAMSZ);
8370 memcpy(smb_sharename,smb_localNamep,len);
8371 afsi_log("lana_list.length %d", lana_list.length);
8373 /* Keep the name so we can unregister it later */
8374 for (l = 0; l < lana_list.length; l++) {
8375 lana = lana_list.lana[l];
8377 ncbp->ncb_command = NCBADDNAME;
8378 ncbp->ncb_lana_num = lana;
8379 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8380 code = Netbios(ncbp);
8382 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8383 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8385 char name[NCBNAMSZ+1];
8387 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8388 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8392 code = ncbp->ncb_retcode;
8395 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8398 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8399 if (code == NRC_BRIDGE) { /* invalid LANA num */
8400 lana_list.lana[l] = 255;
8403 else if (code == NRC_DUPNAME) {
8404 afsi_log("Name already exists; try to delete it");
8405 memset(ncbp, 0, sizeof(*ncbp));
8406 ncbp->ncb_command = NCBDELNAME;
8407 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8408 ncbp->ncb_lana_num = lana;
8409 code = Netbios(ncbp);
8411 code = ncbp->ncb_retcode;
8413 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8415 if (code != 0 || delname_tried) {
8416 lana_list.lana[l] = 255;
8418 else if (code == 0) {
8419 if (!delname_tried) {
8427 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8428 lana_list.lana[l] = 255; /* invalid lana */
8432 lana_found = 1; /* at least one worked */
8436 osi_assertx(lana_list.length >= 0, "empty lana list");
8438 afsi_log("No valid LANA numbers found!");
8439 lana_list.length = 0;
8440 smb_LANadapter = -1;
8441 smb_ListenerState = SMB_LISTENER_STOPPED;
8442 cm_VolStatus_Network_Stopped(cm_NetbiosName
8449 /* we're done with the NCB now */
8452 return (lana_list.length > 0 ? 1 : 0);
8455 void smb_StartListeners()
8461 if (smb_ListenerState == SMB_LISTENER_STARTED)
8464 smb_ListenerState = SMB_LISTENER_STARTED;
8465 cm_VolStatus_Network_Started(cm_NetbiosName
8471 for (i = 0; i < lana_list.length; i++) {
8472 if (lana_list.lana[i] == 255)
8474 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
8475 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
8476 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
8477 thrd_CloseHandle(phandle);
8481 void smb_RestartListeners()
8483 if (!powerStateSuspended && smb_ListenerState == SMB_LISTENER_STOPPED) {
8484 if (smb_NetbiosInit())
8485 smb_StartListeners();
8489 void smb_StopListener(NCB *ncbp, int lana)
8493 memset(ncbp, 0, sizeof(*ncbp));
8494 ncbp->ncb_command = NCBDELNAME;
8495 ncbp->ncb_lana_num = lana;
8496 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8497 code = Netbios(ncbp);
8499 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
8500 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8502 /* and then reset the LANA; this will cause the listener threads to exit */
8503 ncbp->ncb_command = NCBRESET;
8504 ncbp->ncb_callname[0] = 100;
8505 ncbp->ncb_callname[2] = 100;
8506 ncbp->ncb_lana_num = lana;
8507 code = Netbios(ncbp);
8509 code = ncbp->ncb_retcode;
8511 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
8513 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
8517 void smb_StopListeners(void)
8522 if (smb_ListenerState == SMB_LISTENER_STOPPED)
8525 smb_ListenerState = SMB_LISTENER_STOPPED;
8526 cm_VolStatus_Network_Stopped(cm_NetbiosName
8534 /* Unregister the SMB name */
8535 for (l = 0; l < lana_list.length; l++) {
8536 lana = lana_list.lana[l];
8539 smb_StopListener(ncbp, lana);
8541 /* mark the adapter invalid */
8542 lana_list.lana[l] = 255; /* invalid lana */
8546 /* force a re-evaluation of the network adapters */
8547 lana_list.length = 0;
8548 smb_LANadapter = -1;
8550 Sleep(1000); /* give the listener threads a chance to exit */
8553 void smb_Init(osi_log_t *logp, int useV3,
8563 EVENT_HANDLE retHandle;
8564 char eventName[MAX_PATH];
8566 smb_TlsRequestSlot = TlsAlloc();
8568 smb_MBfunc = aMBfunc;
8572 /* Initialize smb_localZero */
8573 myTime.tm_isdst = -1; /* compute whether on DST or not */
8574 myTime.tm_year = 70;
8580 smb_localZero = mktime(&myTime);
8582 #ifndef USE_NUMERIC_TIME_CONV
8583 /* Initialize kludge-GMT */
8584 smb_CalculateNowTZ();
8585 #endif /* USE_NUMERIC_TIME_CONV */
8586 #ifdef AFS_FREELANCE_CLIENT
8587 /* Make sure the root.afs volume has the correct time */
8588 cm_noteLocalMountPointChange();
8591 /* initialize the remote debugging log */
8594 /* and the global lock */
8595 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
8596 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
8598 /* Raw I/O data structures */
8599 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
8601 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
8603 /* 4 Raw I/O buffers */
8604 smb_RawBufs = calloc(65536,1);
8605 *((char **)smb_RawBufs) = NULL;
8606 for (i=0; i<3; i++) {
8607 char *rawBuf = calloc(65536,1);
8608 *((char **)rawBuf) = smb_RawBufs;
8609 smb_RawBufs = rawBuf;
8612 /* global free lists */
8613 smb_ncbFreeListp = NULL;
8614 smb_packetFreeListp = NULL;
8618 /* Initialize listener and server structures */
8620 memset(dead_sessions, 0, sizeof(dead_sessions));
8621 sprintf(eventName, "SessionEvents[0]");
8622 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8623 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8624 afsi_log("Event Object Already Exists: %s", eventName);
8626 smb_NumServerThreads = nThreads;
8627 sprintf(eventName, "NCBavails[0]");
8628 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8629 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8630 afsi_log("Event Object Already Exists: %s", eventName);
8631 sprintf(eventName, "NCBevents[0]");
8632 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8633 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8634 afsi_log("Event Object Already Exists: %s", eventName);
8635 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
8636 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
8637 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8638 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8639 afsi_log("Event Object Already Exists: %s", eventName);
8640 for (i = 0; i < smb_NumServerThreads; i++) {
8641 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
8642 NCBreturns[i][0] = retHandle;
8645 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
8646 for (i = 0; i < smb_NumServerThreads; i++) {
8647 sprintf(eventName, "smb_ServerShutdown[%d]", i);
8648 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8649 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8650 afsi_log("Event Object Already Exists: %s", eventName);
8651 InitNCBslot((int)(i+1));
8653 numNCBs = smb_NumServerThreads + 1;
8655 /* Initialize dispatch table */
8656 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
8657 /* Prepare the table for unknown operations */
8658 for(i=0; i<= SMB_NOPCODES; i++) {
8659 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
8661 /* Fill in the ones we do know */
8662 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
8663 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
8664 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
8665 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
8666 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
8667 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
8668 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
8669 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
8670 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
8671 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
8672 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
8673 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
8674 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
8675 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
8676 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
8677 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
8678 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
8679 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
8680 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
8681 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
8682 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
8683 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8684 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
8685 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
8686 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
8687 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
8688 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
8689 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
8690 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8691 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
8692 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8693 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
8694 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
8695 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
8696 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8697 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
8698 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
8699 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
8700 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
8701 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
8702 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
8703 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
8704 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8705 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
8706 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8707 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
8708 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
8709 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
8710 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
8711 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
8712 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
8713 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
8714 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
8715 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
8716 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
8717 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
8718 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
8719 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
8720 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
8721 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
8722 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
8723 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
8724 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
8725 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
8726 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
8727 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
8728 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
8729 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
8730 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
8731 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
8732 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
8733 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
8734 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
8735 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
8737 /* setup tran 2 dispatch table */
8738 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
8739 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
8740 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
8741 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
8742 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
8743 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
8744 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
8745 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
8746 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
8747 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
8748 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
8749 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
8750 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
8751 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
8752 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
8753 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
8754 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
8755 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
8757 /* setup the rap dispatch table */
8758 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
8759 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
8760 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
8761 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
8762 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
8766 /* if we are doing SMB authentication we have register outselves as a logon process */
8767 if (smb_authType != SMB_AUTH_NONE) {
8768 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
8769 LSA_STRING afsProcessName;
8770 LSA_OPERATIONAL_MODE dummy; /*junk*/
8772 afsProcessName.Buffer = "OpenAFSClientDaemon";
8773 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
8774 afsProcessName.MaximumLength = afsProcessName.Length + 1;
8776 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
8778 if (nts == STATUS_SUCCESS) {
8779 LSA_STRING packageName;
8780 /* we are registered. Find out the security package id */
8781 packageName.Buffer = MSV1_0_PACKAGE_NAME;
8782 packageName.Length = (USHORT)strlen(packageName.Buffer);
8783 packageName.MaximumLength = packageName.Length + 1;
8784 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
8785 if (nts == STATUS_SUCCESS) {
8787 * This code forces Windows to authenticate against the Logon Cache
8788 * first instead of attempting to authenticate against the Domain
8789 * Controller. When the Windows logon cache is enabled this improves
8790 * performance by removing the network access and works around a bug
8791 * seen at sites which are using a MIT Kerberos principal to login
8792 * to machines joined to a non-root domain in a multi-domain forest.
8793 * MsV1_0SetProcessOption was added in Windows XP.
8795 PVOID pResponse = NULL;
8796 ULONG cbResponse = 0;
8797 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
8799 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
8800 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
8801 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
8802 OptionsRequest.DisableOptions = FALSE;
8804 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
8807 sizeof(OptionsRequest),
8813 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
8814 char message[AFSPATHMAX];
8815 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
8817 OutputDebugString(message);
8820 OutputDebugString("MsV1_0SetProcessOption success");
8821 afsi_log("MsV1_0SetProcessOption success");
8823 /* END - code from Larry */
8825 smb_lsaLogonOrigin.Buffer = "OpenAFS";
8826 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
8827 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
8829 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
8831 /* something went wrong. We report the error and revert back to no authentication
8832 because we can't perform any auth requests without a successful lsa handle
8833 or sec package id. */
8834 afsi_log("Reverting to NO SMB AUTH");
8835 smb_authType = SMB_AUTH_NONE;
8838 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
8840 /* something went wrong. We report the error and revert back to no authentication
8841 because we can't perform any auth requests without a successful lsa handle
8842 or sec package id. */
8843 afsi_log("Reverting to NO SMB AUTH");
8844 smb_authType = SMB_AUTH_NONE;
8848 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
8849 * time prevents the failure of authentication when logged into Windows with an
8850 * external Kerberos principal mapped to a local account.
8852 else if ( smb_authType == SMB_AUTH_EXTENDED) {
8853 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
8854 * then the only option is NTLMSSP anyway; so just fallback.
8859 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
8860 if (secBlobLength == 0) {
8861 smb_authType = SMB_AUTH_NTLM;
8862 afsi_log("Reverting to SMB AUTH NTLM");
8871 /* Now get ourselves a domain name. */
8872 /* For now we are using the local computer name as the domain name.
8873 * It is actually the domain for local logins, and we are acting as
8874 * a local SMB server.
8876 bufsize = sizeof(smb_ServerDomainName) - 1;
8877 GetComputerName(smb_ServerDomainName, &bufsize);
8878 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
8879 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
8882 /* Start listeners, waiters, servers, and daemons */
8884 smb_StartListeners();
8886 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
8887 NULL, 0, &lpid, "smb_ClientWaiter");
8888 osi_assertx(phandle != NULL, , "smb_ClientWaiter thread creation failure");
8889 thrd_CloseHandle(phandle);
8891 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
8892 NULL, 0, &lpid, "smb_ServerWaiter");
8893 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
8894 thrd_CloseHandle(phandle);
8896 for (i=0; i<smb_NumServerThreads; i++) {
8897 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
8898 (void *) i, 0, &lpid, "smb_Server");
8899 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
8900 thrd_CloseHandle(phandle);
8903 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
8904 NULL, 0, &lpid, "smb_Daemon");
8905 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
8906 thrd_CloseHandle(phandle);
8908 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
8909 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
8910 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
8911 thrd_CloseHandle(phandle);
8916 void smb_Shutdown(void)
8923 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
8925 /* setup the NCB system */
8928 /* Block new sessions by setting shutdown flag */
8929 smbShutdownFlag = 1;
8931 /* Hang up all sessions */
8932 memset((char *)ncbp, 0, sizeof(NCB));
8933 for (i = 1; i < numSessions; i++)
8935 if (dead_sessions[i])
8938 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8939 ncbp->ncb_command = NCBHANGUP;
8940 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
8941 ncbp->ncb_lsn = (UCHAR)LSNs[i];
8942 code = Netbios(ncbp);
8943 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
8944 if (code == 0) code = ncbp->ncb_retcode;
8946 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
8947 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
8951 /* Trigger the shutdown of all SMB threads */
8952 for (i = 0; i < smb_NumServerThreads; i++)
8953 thrd_SetEvent(NCBreturns[i][0]);
8955 thrd_SetEvent(NCBevents[0]);
8956 thrd_SetEvent(SessionEvents[0]);
8957 thrd_SetEvent(NCBavails[0]);
8959 for (i = 0;i < smb_NumServerThreads; i++) {
8960 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
8961 if (code == WAIT_OBJECT_0) {
8964 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
8965 thrd_SetEvent(NCBreturns[i--][0]);
8969 /* Delete Netbios name */
8970 memset((char *)ncbp, 0, sizeof(NCB));
8971 for (i = 0; i < lana_list.length; i++) {
8972 if (lana_list.lana[i] == 255) continue;
8973 ncbp->ncb_command = NCBDELNAME;
8974 ncbp->ncb_lana_num = lana_list.lana[i];
8975 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8976 code = Netbios(ncbp);
8978 code = ncbp->ncb_retcode;
8980 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
8981 ncbp->ncb_lana_num, code);
8986 /* Release the reference counts held by the VCs */
8987 lock_ObtainWrite(&smb_rctLock);
8988 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
8993 if (vcp->magic != SMB_VC_MAGIC)
8994 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
8995 __FILE__, __LINE__);
8997 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
8999 if (fidp->scp != NULL) {
9002 lock_ObtainMutex(&fidp->mx);
9003 if (fidp->scp != NULL) {
9006 lock_ObtainMutex(&scp->mx);
9007 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9008 lock_ReleaseMutex(&scp->mx);
9009 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9010 cm_ReleaseSCache(scp);
9012 lock_ReleaseMutex(&fidp->mx);
9016 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9018 smb_ReleaseVCNoLock(tidp->vcp);
9020 cm_user_t *userp = tidp->userp;
9022 lock_ReleaseWrite(&smb_rctLock);
9023 cm_ReleaseUser(userp);
9024 lock_ObtainWrite(&smb_rctLock);
9028 lock_ReleaseWrite(&smb_rctLock);
9030 TlsFree(smb_TlsRequestSlot);
9033 /* Get the UNC \\<servername>\<sharename> prefix. */
9034 char *smb_GetSharename()
9038 /* Make sure we have been properly initialized. */
9039 if (smb_localNamep == NULL)
9042 /* Allocate space for \\<servername>\<sharename>, plus the
9045 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
9046 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
9052 void smb_LogPacket(smb_packet_t *packet)
9055 unsigned length, paramlen, datalen, i, j;
9057 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9059 if (!packet) return;
9061 osi_Log0(smb_logp, "*** SMB packet dump ***");
9063 vp = (BYTE *) packet->data;
9065 datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
9066 length = paramlen + 2 + datalen;
9069 for (i=0;i < length; i+=16)
9071 memset( buf, ' ', 80 );
9076 buf[strlen(buf)] = ' ';
9078 cp = (BYTE*) buf + 7;
9080 for (j=0;j < 16 && (i+j)<length; j++)
9082 *(cp++) = hex[vp[i+j] >> 4];
9083 *(cp++) = hex[vp[i+j] & 0xf];
9093 for (j=0;j < 16 && (i+j)<length;j++)
9095 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9106 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9109 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9111 #endif /* LOG_PACKET */
9114 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9122 lock_ObtainRead(&smb_rctLock);
9124 sprintf(output, "begin dumping smb_vc_t\r\n");
9125 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9127 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9131 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9132 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9133 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9135 sprintf(output, "begin dumping smb_fid_t\r\n");
9136 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9138 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9140 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",
9141 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9142 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9143 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9144 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9147 sprintf(output, "done dumping smb_fid_t\r\n");
9148 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9151 sprintf(output, "done dumping smb_vc_t\r\n");
9152 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9154 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9155 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9157 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9161 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9162 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9163 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9165 sprintf(output, "begin dumping smb_fid_t\r\n");
9166 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9168 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9170 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",
9171 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9172 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9173 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9174 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9177 sprintf(output, "done dumping smb_fid_t\r\n");
9178 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9181 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9182 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9185 lock_ReleaseRead(&smb_rctLock);
9189 long smb_IsNetworkStarted(void)
9191 return (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);