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 #define STRSAFE_NO_DEPRECATE
37 /* These characters are illegal in Windows filenames */
38 static char *illegalChars = "\\/:*?\"<>|";
40 static int smbShutdownFlag = 0;
41 static int smb_ListenerState = SMB_LISTENER_UNINITIALIZED;
43 int smb_LogoffTokenTransfer;
44 time_t smb_LogoffTransferTimeout;
46 int smb_StoreAnsiFilenames = 0;
48 DWORD last_msg_time = 0;
52 unsigned int sessionGen = 0;
54 extern void afsi_log(char *pattern, ...);
55 extern HANDLE afsi_file;
56 extern int powerStateSuspended;
58 osi_hyper_t hzero = {0, 0};
59 osi_hyper_t hones = {0xFFFFFFFF, -1};
62 osi_rwlock_t smb_globalLock;
63 osi_rwlock_t smb_rctLock;
64 osi_mutex_t smb_ListenerLock;
65 osi_mutex_t smb_StartedLock;
67 unsigned char smb_LANadapter = LANA_INVALID;
68 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
69 int smb_LanAdapterChangeDetected = 0;
70 afs_uint32 smb_AsyncStore = 1;
71 afs_uint32 smb_AsyncStoreSize = CM_CONFIGDEFAULT_ASYNCSTORESIZE;
73 BOOL isGateway = FALSE;
76 long smb_maxObsConcurrentCalls=0;
77 long smb_concurrentCalls=0;
79 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
81 smb_packet_t *smb_packetFreeListp;
82 smb_ncb_t *smb_ncbFreeListp;
84 afs_uint32 smb_NumServerThreads;
86 afs_uint32 numNCBs, numSessions, numVCs;
88 int smb_maxVCPerServer;
89 int smb_maxMpxRequests;
91 int smb_authType = SMB_AUTH_EXTENDED; /* type of SMB auth to use. One of SMB_AUTH_* */
93 ULONG smb_lsaSecPackage;
94 LSA_STRING smb_lsaLogonOrigin;
96 #define NCB_MAX MAXIMUM_WAIT_OBJECTS
97 EVENT_HANDLE NCBavails[NCB_MAX], NCBevents[NCB_MAX];
98 EVENT_HANDLE **NCBreturns;
99 EVENT_HANDLE **NCBShutdown;
100 EVENT_HANDLE *smb_ServerShutdown;
101 EVENT_HANDLE ListenerShutdown[256];
102 DWORD NCBsessions[NCB_MAX];
104 struct smb_packet *bufs[NCB_MAX];
106 #define SESSION_MAX MAXIMUM_WAIT_OBJECTS - 4
107 EVENT_HANDLE SessionEvents[SESSION_MAX];
108 unsigned short LSNs[SESSION_MAX];
109 int lanas[SESSION_MAX];
110 BOOL dead_sessions[SESSION_MAX];
113 osi_mutex_t smb_RawBufLock;
116 #define SMB_MASKFLAG_TILDE 1
117 #define SMB_MASKFLAG_CASEFOLD 2
119 #define RAWTIMEOUT INFINITE
122 typedef struct raw_write_cont {
131 /* dir search stuff */
132 long smb_dirSearchCounter = 1;
133 smb_dirSearch_t *smb_firstDirSearchp;
134 smb_dirSearch_t *smb_lastDirSearchp;
136 /* hide dot files? */
137 int smb_hideDotFiles;
139 /* Negotiate Unicode support? */
142 /* global state about V3 protocols */
143 int smb_useV3; /* try to negotiate V3 */
145 static showErrors = 0;
146 /* MessageBox or something like it */
147 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
150 * Time in Unix format of midnight, 1/1/1970 local time.
151 * When added to dosUTime, gives Unix (AFS) time.
153 time_t smb_localZero = 0;
155 #define USE_NUMERIC_TIME_CONV 1
157 #ifndef USE_NUMERIC_TIME_CONV
158 /* Time difference for converting to kludge-GMT */
159 afs_uint32 smb_NowTZ;
160 #endif /* USE_NUMERIC_TIME_CONV */
162 char *smb_localNamep = NULL;
164 smb_vc_t *smb_allVCsp;
165 smb_vc_t *smb_deadVCsp;
167 smb_username_t *usernamesp = NULL;
169 smb_waitingLockRequest_t *smb_allWaitingLocks;
171 DWORD smb_TlsRequestSlot = -1;
174 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
175 NCB *ncbp, raw_write_cont_t *rwcp);
176 int smb_NetbiosInit(int);
179 void smb_LogPacket(smb_packet_t *packet);
180 #endif /* LOG_PACKET */
182 char smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = ""; /* domain name */
183 int smb_ServerDomainNameLength = 0;
184 char smb_ServerOS[] = "Windows 5.0"; /* Faux OS String */
185 int smb_ServerOSLength = sizeof(smb_ServerOS);
186 char smb_ServerLanManager[] = "Windows 2000 LAN Manager"; /* Faux LAN Manager string */
187 int smb_ServerLanManagerLength = sizeof(smb_ServerLanManager);
189 /* Faux server GUID. This is never checked. */
190 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
192 void smb_ResetServerPriority()
194 void * p = TlsGetValue(smb_TlsRequestSlot);
197 TlsSetValue(smb_TlsRequestSlot, NULL);
198 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
202 void smb_SetRequestStartTime()
204 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
206 tp = malloc(sizeof(time_t));
210 if (!TlsSetValue(smb_TlsRequestSlot, tp))
215 void smb_UpdateServerPriority()
217 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
220 time_t now = osi_Time();
222 /* Give one priority boost for each 15 seconds */
223 SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
228 const char * ncb_error_string(int code)
232 case 0x01: s = "llegal buffer length"; break;
233 case 0x03: s = "illegal command"; break;
234 case 0x05: s = "command timed out"; break;
235 case 0x06: s = "message incomplete, issue another command"; break;
236 case 0x07: s = "illegal buffer address"; break;
237 case 0x08: s = "session number out of range"; break;
238 case 0x09: s = "no resource available"; break;
239 case 0x0a: s = "session closed"; break;
240 case 0x0b: s = "command cancelled"; break;
241 case 0x0d: s = "duplicate name"; break;
242 case 0x0e: s = "name table full"; break;
243 case 0x0f: s = "no deletions, name has active sessions"; break;
244 case 0x11: s = "local session table full"; break;
245 case 0x12: s = "remote session table full"; break;
246 case 0x13: s = "illegal name number"; break;
247 case 0x14: s = "no callname"; break;
248 case 0x15: s = "cannot put * in NCB_NAME"; break;
249 case 0x16: s = "name in use on remote adapter"; break;
250 case 0x17: s = "name deleted"; break;
251 case 0x18: s = "session ended abnormally"; break;
252 case 0x19: s = "name conflict detected"; break;
253 case 0x21: s = "interface busy, IRET before retrying"; break;
254 case 0x22: s = "too many commands outstanding, retry later";break;
255 case 0x23: s = "ncb_lana_num field invalid"; break;
256 case 0x24: s = "command completed while cancel occurring "; break;
257 case 0x26: s = "command not valid to cancel"; break;
258 case 0x30: s = "name defined by anther local process"; break;
259 case 0x34: s = "environment undefined. RESET required"; break;
260 case 0x35: s = "required OS resources exhausted"; break;
261 case 0x36: s = "max number of applications exceeded"; break;
262 case 0x37: s = "no saps available for netbios"; break;
263 case 0x38: s = "requested resources are not available"; break;
264 case 0x39: s = "invalid ncb address or length > segment"; break;
265 case 0x3B: s = "invalid NCB DDID"; break;
266 case 0x3C: s = "lock of user area failed"; break;
267 case 0x3f: s = "NETBIOS not loaded"; break;
268 case 0x40: s = "system error"; break;
269 default: s = "unknown error";
275 char * myCrt_Dispatch(int i)
280 return "(00)ReceiveCoreMakeDir";
282 return "(01)ReceiveCoreRemoveDir";
284 return "(02)ReceiveCoreOpen";
286 return "(03)ReceiveCoreCreate";
288 return "(04)ReceiveCoreClose";
290 return "(05)ReceiveCoreFlush";
292 return "(06)ReceiveCoreUnlink";
294 return "(07)ReceiveCoreRename";
296 return "(08)ReceiveCoreGetFileAttributes";
298 return "(09)ReceiveCoreSetFileAttributes";
300 return "(0a)ReceiveCoreRead";
302 return "(0b)ReceiveCoreWrite";
304 return "(0c)ReceiveCoreLockRecord";
306 return "(0d)ReceiveCoreUnlockRecord";
308 return "(0e)SendCoreBadOp";
310 return "(0f)ReceiveCoreCreate";
312 return "(10)ReceiveCoreCheckPath";
314 return "(11)SendCoreBadOp";
316 return "(12)ReceiveCoreSeek";
318 return "(1a)ReceiveCoreReadRaw";
320 return "(1d)ReceiveCoreWriteRawDummy";
322 return "(22)ReceiveV3SetAttributes";
324 return "(23)ReceiveV3GetAttributes";
326 return "(24)ReceiveV3LockingX";
328 return "(25)ReceiveV3Trans";
330 return "(26)ReceiveV3Trans[aux]";
332 return "(29)SendCoreBadOp";
334 return "(2b)ReceiveCoreEcho";
336 return "(2d)ReceiveV3OpenX";
338 return "(2e)ReceiveV3ReadX";
340 return "(2f)ReceiveV3WriteX";
342 return "(32)ReceiveV3Tran2A";
344 return "(33)ReceiveV3Tran2A[aux]";
346 return "(34)ReceiveV3FindClose";
348 return "(35)ReceiveV3FindNotifyClose";
350 return "(70)ReceiveCoreTreeConnect";
352 return "(71)ReceiveCoreTreeDisconnect";
354 return "(72)ReceiveNegotiate";
356 return "(73)ReceiveV3SessionSetupX";
358 return "(74)ReceiveV3UserLogoffX";
360 return "(75)ReceiveV3TreeConnectX";
362 return "(80)ReceiveCoreGetDiskAttributes";
364 return "(81)ReceiveCoreSearchDir";
368 return "(83)FindUnique";
370 return "(84)FindClose";
372 return "(A0)ReceiveNTTransact";
374 return "(A2)ReceiveNTCreateX";
376 return "(A4)ReceiveNTCancel";
378 return "(A5)ReceiveNTRename";
380 return "(C0)OpenPrintFile";
382 return "(C1)WritePrintFile";
384 return "(C2)ClosePrintFile";
386 return "(C3)GetPrintQueue";
388 return "(D8)ReadBulk";
390 return "(D9)WriteBulk";
392 return "(DA)WriteBulkData";
394 return "unknown SMB op";
398 char * myCrt_2Dispatch(int i)
403 return "unknown SMB op-2";
405 return "S(00)CreateFile_ReceiveTran2Open";
407 return "S(01)FindFirst_ReceiveTran2SearchDir";
409 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
411 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
413 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
415 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
417 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
419 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
421 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
423 return "S(09)_ReceiveTran2FSCTL";
425 return "S(0a)_ReceiveTran2IOCTL";
427 return "S(0b)_ReceiveTran2FindNotifyFirst";
429 return "S(0c)_ReceiveTran2FindNotifyNext";
431 return "S(0d)_ReceiveTran2CreateDirectory";
433 return "S(0e)_ReceiveTran2SessionSetup";
435 return "S(0f)_QueryFileSystemInformationFid";
437 return "S(10)_ReceiveTran2GetDfsReferral";
439 return "S(11)_ReceiveTran2ReportDfsInconsistency";
443 char * myCrt_RapDispatch(int i)
448 return "unknown RAP OP";
450 return "RAP(0)NetShareEnum";
452 return "RAP(1)NetShareGetInfo";
454 return "RAP(13)NetServerGetInfo";
456 return "RAP(63)NetWkStaGetInfo";
460 /* scache must be locked */
461 unsigned int smb_Attributes(cm_scache_t *scp)
465 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
466 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
467 scp->fileType == CM_SCACHETYPE_INVALID)
469 attrs = SMB_ATTR_DIRECTORY;
470 #ifdef SPECIAL_FOLDERS
471 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
472 #endif /* SPECIAL_FOLDERS */
473 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
474 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
479 * We used to mark a file RO if it was in an RO volume, but that
480 * turns out to be impolitic in NT. See defect 10007.
483 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
484 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
486 if ((scp->unixModeBits & 0222) == 0)
487 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
493 /* Check if the named file/dir is a dotfile/dotdir */
494 /* String pointed to by lastComp can have leading slashes, but otherwise should have
495 no other patch components */
496 unsigned int smb_IsDotFile(char *lastComp) {
499 /* skip over slashes */
500 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
505 /* nulls, curdir and parent dir doesn't count */
511 if(*(s+1) == '.' && !*(s + 2))
518 static int ExtractBits(WORD bits, short start, short len)
525 num = bits << (16 - end);
526 num = num >> ((16 - end) + start);
531 void ShowUnixTime(char *FuncName, time_t unixTime)
536 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
538 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
539 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
541 int day, month, year, sec, min, hour;
544 day = ExtractBits(wDate, 0, 5);
545 month = ExtractBits(wDate, 5, 4);
546 year = ExtractBits(wDate, 9, 7) + 1980;
548 sec = ExtractBits(wTime, 0, 5);
549 min = ExtractBits(wTime, 5, 6);
550 hour = ExtractBits(wTime, 11, 5);
552 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
553 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
557 /* Determine if we are observing daylight savings time */
558 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
560 TIME_ZONE_INFORMATION timeZoneInformation;
561 SYSTEMTIME utc, local, localDST;
563 /* Get the time zone info. NT uses this to calc if we are in DST. */
564 GetTimeZoneInformation(&timeZoneInformation);
566 /* Return the daylight bias */
567 *pDstBias = timeZoneInformation.DaylightBias;
569 /* Return the bias */
570 *pBias = timeZoneInformation.Bias;
572 /* Now determine if DST is being observed */
574 /* Get the UTC (GMT) time */
577 /* Convert UTC time to local time using the time zone info. If we are
578 observing DST, the calculated local time will include this.
580 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
582 /* Set the daylight bias to 0. The daylight bias is the amount of change
583 * in time that we use for daylight savings time. By setting this to 0
584 * we cause there to be no change in time during daylight savings time.
586 timeZoneInformation.DaylightBias = 0;
588 /* Convert the utc time to local time again, but this time without any
589 adjustment for daylight savings time.
591 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
593 /* If the two times are different, then it means that the localDST that
594 we calculated includes the daylight bias, and therefore we are
595 observing daylight savings time.
597 *pDST = localDST.wHour != local.wHour;
601 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
603 BOOL dst; /* Will be TRUE if observing DST */
604 LONG dstBias; /* Offset from local time if observing DST */
605 LONG bias; /* Offset from GMT for local time */
608 * This function will adjust the last write time to compensate
609 * for two bugs in the smb client:
611 * 1) During Daylight Savings Time, the LastWriteTime is ahead
612 * in time by the DaylightBias (ignoring the sign - the
613 * DaylightBias is always stored as a negative number). If
614 * the DaylightBias is -60, then the LastWriteTime will be
615 * ahead by 60 minutes.
617 * 2) If the local time zone is a positive offset from GMT, then
618 * the LastWriteTime will be the correct local time plus the
619 * Bias (ignoring the sign - a positive offset from GMT is
620 * always stored as a negative Bias). If the Bias is -120,
621 * then the LastWriteTime will be ahead by 120 minutes.
623 * These bugs can occur at the same time.
626 GetTimeZoneInfo(&dst, &dstBias, &bias);
628 /* First adjust for DST */
630 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
632 /* Now adjust for a positive offset from GMT (a negative bias). */
634 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
637 #ifndef USE_NUMERIC_TIME_CONV
639 * Calculate the difference (in seconds) between local time and GMT.
640 * This enables us to convert file times to kludge-GMT.
646 struct tm gmt_tm, local_tm;
647 int days, hours, minutes, seconds;
650 gmt_tm = *(gmtime(&t));
651 local_tm = *(localtime(&t));
653 days = local_tm.tm_yday - gmt_tm.tm_yday;
654 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
655 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
656 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
660 #endif /* USE_NUMERIC_TIME_CONV */
662 #ifdef USE_NUMERIC_TIME_CONV
663 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
665 // Note that LONGLONG is a 64-bit value
668 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
669 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
670 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
673 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
678 time_t ersatz_unixTime;
681 * Must use kludge-GMT instead of real GMT.
682 * kludge-GMT is computed by adding time zone difference to localtime.
685 * ltp = gmtime(&unixTime);
687 ersatz_unixTime = unixTime - smb_NowTZ;
688 ltp = localtime(&ersatz_unixTime);
690 /* if we fail, make up something */
693 localJunk.tm_year = 89 - 20;
694 localJunk.tm_mon = 4;
695 localJunk.tm_mday = 12;
696 localJunk.tm_hour = 0;
697 localJunk.tm_min = 0;
698 localJunk.tm_sec = 0;
701 stm.wYear = ltp->tm_year + 1900;
702 stm.wMonth = ltp->tm_mon + 1;
703 stm.wDayOfWeek = ltp->tm_wday;
704 stm.wDay = ltp->tm_mday;
705 stm.wHour = ltp->tm_hour;
706 stm.wMinute = ltp->tm_min;
707 stm.wSecond = ltp->tm_sec;
708 stm.wMilliseconds = 0;
710 SystemTimeToFileTime(&stm, largeTimep);
712 #endif /* USE_NUMERIC_TIME_CONV */
714 #ifdef USE_NUMERIC_TIME_CONV
715 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
717 // Note that LONGLONG is a 64-bit value
720 ll = largeTimep->dwHighDateTime;
722 ll += largeTimep->dwLowDateTime;
724 ll -= 116444736000000000;
727 *unixTimep = (DWORD)ll;
729 #else /* USE_NUMERIC_TIME_CONV */
730 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
736 FileTimeToSystemTime(largeTimep, &stm);
738 lt.tm_year = stm.wYear - 1900;
739 lt.tm_mon = stm.wMonth - 1;
740 lt.tm_wday = stm.wDayOfWeek;
741 lt.tm_mday = stm.wDay;
742 lt.tm_hour = stm.wHour;
743 lt.tm_min = stm.wMinute;
744 lt.tm_sec = stm.wSecond;
747 save_timezone = _timezone;
748 _timezone += smb_NowTZ;
749 *unixTimep = mktime(<);
750 _timezone = save_timezone;
752 #endif /* USE_NUMERIC_TIME_CONV */
754 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
764 /* if we fail, make up something */
767 localJunk.tm_year = 89 - 20;
768 localJunk.tm_mon = 4;
769 localJunk.tm_mday = 12;
770 localJunk.tm_hour = 0;
771 localJunk.tm_min = 0;
772 localJunk.tm_sec = 0;
775 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
776 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
777 *searchTimep = (dosDate<<16) | dosTime;
780 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
782 unsigned short dosDate;
783 unsigned short dosTime;
786 dosDate = (unsigned short) (searchTime & 0xffff);
787 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
789 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
790 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
791 localTm.tm_mday = (dosDate) & 0x1f;
792 localTm.tm_hour = (dosTime>>11) & 0x1f;
793 localTm.tm_min = (dosTime >> 5) & 0x3f;
794 localTm.tm_sec = (dosTime & 0x1f) * 2;
795 localTm.tm_isdst = -1; /* compute whether DST in effect */
797 *unixTimep = mktime(&localTm);
800 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
802 time_t diff_t = unixTime - smb_localZero;
803 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
804 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
806 *dosUTimep = (afs_uint32)diff_t;
809 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
811 *unixTimep = dosTime + smb_localZero;
814 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
818 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
819 lock_ObtainWrite(&smb_rctLock);
820 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
821 if (vcp->magic != SMB_VC_MAGIC)
822 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
825 if (lsn == vcp->lsn && lana == vcp->lana &&
826 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
827 smb_HoldVCNoLock(vcp);
831 if (!vcp && (flags & SMB_FLAG_CREATE)) {
832 vcp = malloc(sizeof(*vcp));
833 memset(vcp, 0, sizeof(*vcp));
834 vcp->vcID = ++numVCs;
835 vcp->magic = SMB_VC_MAGIC;
836 vcp->refCount = 2; /* smb_allVCsp and caller */
839 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
840 vcp->nextp = smb_allVCsp;
842 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
847 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
848 /* We must obtain a challenge for extended auth
849 * in case the client negotiates smb v3
851 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
852 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
853 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
854 ULONG lsaRespSize = 0;
856 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
858 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
865 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
866 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
867 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
868 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
869 nts, ntsEx, lsaRespSize);
871 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
873 if (ntsEx == STATUS_SUCCESS) {
874 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
875 LsaFreeReturnBuffer(lsaResp);
878 * This will cause the subsequent authentication to fail but
879 * that is better than us dereferencing a NULL pointer and
882 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
886 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
888 if (numVCs >= CM_SESSION_RESERVED) {
890 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
893 lock_ReleaseWrite(&smb_rctLock);
894 lock_ReleaseWrite(&smb_globalLock);
898 int smb_IsStarMask(char *maskp)
903 for(i=0; i<11; i++) {
905 if (tc == '?' || tc == '*' || tc == '>')
911 void smb_ReleaseVCInternal(smb_vc_t *vcp)
918 if (vcp->refCount == 0) {
919 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
920 /* remove VCP from smb_deadVCsp */
921 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
927 lock_FinalizeMutex(&vcp->mx);
928 memset(vcp,0,sizeof(smb_vc_t));
931 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
935 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
936 avcp?"not ":"",vcp, vcp->refCount);
938 GenerateMiniDump(NULL);
940 /* This is a wrong. However, I suspect that there is an undercount
941 * and I don't want to release 1.4.1 in a state that will allow
942 * smb_vc_t objects to be deallocated while still in the
943 * smb_allVCsp list. The list is supposed to keep a reference
944 * to the smb_vc_t. Put it back.
951 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
953 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
954 smb_ReleaseVCInternal(vcp);
957 void smb_ReleaseVC(smb_vc_t *vcp)
959 lock_ObtainWrite(&smb_rctLock);
960 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
961 smb_ReleaseVCInternal(vcp);
962 lock_ReleaseWrite(&smb_rctLock);
965 void smb_HoldVCNoLock(smb_vc_t *vcp)
968 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
971 void smb_HoldVC(smb_vc_t *vcp)
973 lock_ObtainWrite(&smb_rctLock);
975 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
976 lock_ReleaseWrite(&smb_rctLock);
979 void smb_CleanupDeadVC(smb_vc_t *vcp)
987 smb_user_t *uidpIter;
988 smb_user_t *uidpNext;
992 lock_ObtainMutex(&vcp->mx);
993 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
994 lock_ReleaseMutex(&vcp->mx);
995 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
998 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
999 lock_ReleaseMutex(&vcp->mx);
1000 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1002 lock_ObtainWrite(&smb_rctLock);
1003 /* remove VCP from smb_allVCsp */
1004 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1005 if ((*vcpp)->magic != SMB_VC_MAGIC)
1006 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1007 __FILE__, __LINE__);
1010 vcp->nextp = smb_deadVCsp;
1012 /* Hold onto the reference until we are done with this function */
1017 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1018 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1020 if (fidpIter->delete)
1023 fid = fidpIter->fid;
1024 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1026 smb_HoldFIDNoLock(fidpIter);
1027 lock_ReleaseWrite(&smb_rctLock);
1029 smb_CloseFID(vcp, fidpIter, NULL, 0);
1030 smb_ReleaseFID(fidpIter);
1032 lock_ObtainWrite(&smb_rctLock);
1033 fidpNext = vcp->fidsp;
1036 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1037 tidpNext = tidpIter->nextp;
1038 if (tidpIter->delete)
1040 tidpIter->delete = 1;
1042 tid = tidpIter->tid;
1043 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1045 smb_HoldTIDNoLock(tidpIter);
1046 smb_ReleaseTID(tidpIter, TRUE);
1047 tidpNext = vcp->tidsp;
1050 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1051 uidpNext = uidpIter->nextp;
1052 if (uidpIter->delete)
1054 uidpIter->delete = 1;
1056 /* do not add an additional reference count for the smb_user_t
1057 * as the smb_vc_t already is holding a reference */
1058 lock_ReleaseWrite(&smb_rctLock);
1060 smb_ReleaseUID(uidpIter);
1062 lock_ObtainWrite(&smb_rctLock);
1063 uidpNext = vcp->usersp;
1066 /* The vcp is now on the deadVCsp list. We intentionally drop the
1067 * reference so that the refcount can reach 0 and we can delete it */
1068 smb_ReleaseVCNoLock(vcp);
1070 lock_ReleaseWrite(&smb_rctLock);
1071 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1074 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1078 lock_ObtainWrite(&smb_rctLock);
1080 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1081 if (tidp->refCount == 0 && tidp->delete) {
1083 smb_ReleaseTID(tidp, TRUE);
1087 if (tid == tidp->tid) {
1092 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1093 tidp = malloc(sizeof(*tidp));
1094 memset(tidp, 0, sizeof(*tidp));
1095 tidp->nextp = vcp->tidsp;
1098 smb_HoldVCNoLock(vcp);
1100 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1103 lock_ReleaseWrite(&smb_rctLock);
1107 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1112 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1120 lock_ObtainWrite(&smb_rctLock);
1121 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1122 if (tidp->refCount == 0 && (tidp->delete)) {
1123 ltpp = &tidp->vcp->tidsp;
1124 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1128 osi_assertx(tp != NULL, "null smb_tid_t");
1130 lock_FinalizeMutex(&tidp->mx);
1131 userp = tidp->userp; /* remember to drop ref later */
1133 smb_ReleaseVCNoLock(tidp->vcp);
1137 lock_ReleaseWrite(&smb_rctLock);
1139 cm_ReleaseUser(userp);
1142 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1144 smb_user_t *uidp = NULL;
1146 lock_ObtainWrite(&smb_rctLock);
1147 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1148 if (uid == uidp->userID) {
1150 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%s]",
1152 osi_LogSaveString(smb_logp, (uidp->unp) ? uidp->unp->name : ""));
1156 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1157 uidp = malloc(sizeof(*uidp));
1158 memset(uidp, 0, sizeof(*uidp));
1159 uidp->nextp = vcp->usersp;
1160 uidp->refCount = 2; /* one for the vcp and one for the caller */
1162 smb_HoldVCNoLock(vcp);
1164 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1166 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%s]",
1168 osi_LogSaveString(smb_logp,uidp->unp ? uidp->unp->name : ""));
1170 lock_ReleaseWrite(&smb_rctLock);
1174 smb_username_t *smb_FindUserByName(char *usern, char *machine, afs_uint32 flags)
1176 smb_username_t *unp= NULL;
1178 lock_ObtainWrite(&smb_rctLock);
1179 for(unp = usernamesp; unp; unp = unp->nextp) {
1180 if (stricmp(unp->name, usern) == 0 &&
1181 stricmp(unp->machine, machine) == 0) {
1186 if (!unp && (flags & SMB_FLAG_CREATE)) {
1187 unp = malloc(sizeof(*unp));
1188 memset(unp, 0, sizeof(*unp));
1190 unp->nextp = usernamesp;
1191 unp->name = strdup(usern);
1192 unp->machine = strdup(machine);
1194 lock_InitializeMutex(&unp->mx, "username_t mutex");
1195 if (flags & SMB_FLAG_AFSLOGON)
1196 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1199 lock_ReleaseWrite(&smb_rctLock);
1203 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
1205 smb_user_t *uidp= NULL;
1207 lock_ObtainWrite(&smb_rctLock);
1208 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1211 if (stricmp(uidp->unp->name, usern) == 0) {
1213 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%s]",
1214 vcp,uidp->userID,osi_LogSaveString(smb_logp,usern));
1219 lock_ReleaseWrite(&smb_rctLock);
1223 void smb_ReleaseUsername(smb_username_t *unp)
1226 smb_username_t **lupp;
1227 cm_user_t *userp = NULL;
1228 time_t now = osi_Time();
1230 lock_ObtainWrite(&smb_rctLock);
1231 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1232 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1233 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1235 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1239 osi_assertx(up != NULL, "null smb_username_t");
1241 up->nextp = NULL; /* do not remove this */
1242 lock_FinalizeMutex(&unp->mx);
1248 lock_ReleaseWrite(&smb_rctLock);
1250 cm_ReleaseUser(userp);
1253 void smb_HoldUIDNoLock(smb_user_t *uidp)
1258 void smb_ReleaseUID(smb_user_t *uidp)
1262 smb_username_t *unp = NULL;
1264 lock_ObtainWrite(&smb_rctLock);
1265 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1266 if (uidp->refCount == 0) {
1267 lupp = &uidp->vcp->usersp;
1268 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1272 osi_assertx(up != NULL, "null smb_user_t");
1274 lock_FinalizeMutex(&uidp->mx);
1276 smb_ReleaseVCNoLock(uidp->vcp);
1280 lock_ReleaseWrite(&smb_rctLock);
1284 cm_ReleaseUserVCRef(unp->userp);
1285 smb_ReleaseUsername(unp);
1289 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1291 cm_user_t *up = NULL;
1296 lock_ObtainMutex(&uidp->mx);
1298 up = uidp->unp->userp;
1301 lock_ReleaseMutex(&uidp->mx);
1307 /* retrieve a held reference to a user structure corresponding to an incoming
1309 * corresponding release function is cm_ReleaseUser.
1311 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1314 cm_user_t *up = NULL;
1317 smbp = (smb_t *) inp;
1318 uidp = smb_FindUID(vcp, smbp->uid, 0);
1322 up = smb_GetUserFromUID(uidp);
1324 smb_ReleaseUID(uidp);
1329 * Return a pointer to a pathname extracted from a TID structure. The
1330 * TID structure is not held; assume it won't go away.
1332 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, char ** treepath)
1337 tidp = smb_FindTID(vcp, tid, 0);
1341 if (tidp->flags & SMB_TIDFLAG_IPC) {
1342 code = CM_ERROR_TIDIPC;
1343 /* tidp->pathname would be NULL, but that's fine */
1345 *treepath = tidp->pathname;
1346 smb_ReleaseTID(tidp, FALSE);
1351 /* check to see if we have a chained fid, that is, a fid that comes from an
1352 * OpenAndX message that ran earlier in this packet. In this case, the fid
1353 * field in a read, for example, request, isn't set, since the value is
1354 * supposed to be inherited from the openAndX call.
1356 int smb_ChainFID(int fid, smb_packet_t *inp)
1358 if (inp->fid == 0 || inp->inCount == 0)
1364 /* are we a priv'd user? What does this mean on NT? */
1365 int smb_SUser(cm_user_t *userp)
1370 /* find a file ID. If we pass in 0 we select an unused File ID.
1371 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1372 * smb_fid_t data structure if desired File ID cannot be found.
1374 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1379 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1382 lock_ObtainWrite(&smb_rctLock);
1383 /* figure out if we need to allocate a new file ID */
1386 fid = vcp->fidCounter;
1390 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1391 if (fidp->refCount == 0 && fidp->delete) {
1393 lock_ReleaseWrite(&smb_rctLock);
1394 smb_ReleaseFID(fidp);
1395 lock_ObtainWrite(&smb_rctLock);
1398 if (fid == fidp->fid) {
1401 if (fid == 0xFFFF) {
1403 "New FID number wraps on vcp 0x%x", vcp);
1413 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1414 char eventName[MAX_PATH];
1416 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1417 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1418 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1419 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1420 thrd_CloseHandle(event);
1422 if (fid == 0xFFFF) {
1423 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1429 fidp = malloc(sizeof(*fidp));
1430 memset(fidp, 0, sizeof(*fidp));
1431 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1434 smb_HoldVCNoLock(vcp);
1435 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1437 fidp->curr_chunk = fidp->prev_chunk = -2;
1438 fidp->raw_write_event = event;
1440 vcp->fidCounter = fid+1;
1441 if (vcp->fidCounter == 0xFFFF) {
1442 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1444 vcp->fidCounter = 1;
1449 lock_ReleaseWrite(&smb_rctLock);
1453 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1455 smb_fid_t *fidp = NULL;
1461 lock_ObtainWrite(&smb_rctLock);
1462 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1463 if (scp == fidp->scp) {
1468 lock_ReleaseWrite(&smb_rctLock);
1472 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1478 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1479 /* the sm_fid_t->mx and smb_rctLock must not be held */
1480 void smb_ReleaseFID(smb_fid_t *fidp)
1482 cm_scache_t *scp = NULL;
1483 cm_user_t *userp = NULL;
1484 smb_vc_t *vcp = NULL;
1485 smb_ioctl_t *ioctlp;
1487 lock_ObtainMutex(&fidp->mx);
1488 lock_ObtainWrite(&smb_rctLock);
1489 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1490 if (fidp->refCount == 0 && (fidp->delete)) {
1493 scp = fidp->scp; /* release after lock is released */
1495 lock_ObtainWrite(&scp->rw);
1496 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1497 lock_ReleaseWrite(&scp->rw);
1498 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1501 userp = fidp->userp;
1505 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1506 thrd_CloseHandle(fidp->raw_write_event);
1508 /* and see if there is ioctl stuff to free */
1509 ioctlp = fidp->ioctlp;
1512 cm_FreeSpace(ioctlp->prefix);
1513 if (ioctlp->inAllocp)
1514 free(ioctlp->inAllocp);
1515 if (ioctlp->outAllocp)
1516 free(ioctlp->outAllocp);
1519 lock_ReleaseMutex(&fidp->mx);
1520 lock_FinalizeMutex(&fidp->mx);
1524 smb_ReleaseVCNoLock(vcp);
1526 lock_ReleaseMutex(&fidp->mx);
1528 lock_ReleaseWrite(&smb_rctLock);
1530 /* now release the scache structure */
1532 cm_ReleaseSCache(scp);
1535 cm_ReleaseUser(userp);
1539 * Case-insensitive search for one string in another;
1540 * used to find variable names in submount pathnames.
1542 static char *smb_stristr(char *str1, char *str2)
1546 for (cursor = str1; *cursor; cursor++)
1547 if (stricmp(cursor, str2) == 0)
1554 * Substitute a variable value for its name in a submount pathname. Variable
1555 * name has been identified by smb_stristr() and is in substr. Variable name
1556 * length (plus one) is in substr_size. Variable value is in newstr.
1558 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1563 strcpy(temp, substr + substr_size - 1);
1564 strcpy(substr, newstr);
1568 char VNUserName[] = "%USERNAME%";
1569 char VNLCUserName[] = "%LCUSERNAME%";
1570 char VNComputerName[] = "%COMPUTERNAME%";
1571 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1574 typedef struct smb_findShare_rock {
1578 } smb_findShare_rock_t;
1580 #define SMB_FINDSHARE_EXACT_MATCH 1
1581 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1583 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1587 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1588 if (!strnicmp(dep->name, vrock->shareName, 12)) {
1589 if(!stricmp(dep->name, vrock->shareName))
1590 matchType = SMB_FINDSHARE_EXACT_MATCH;
1592 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1593 if(vrock->match) free(vrock->match);
1594 vrock->match = strdup(dep->name);
1595 vrock->matchType = matchType;
1597 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1598 return CM_ERROR_STOPNOW;
1604 /* find a shareName in the table of submounts */
1605 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp, char *shareName,
1609 char pathName[1024];
1616 DWORD allSubmount = 1;
1618 /* if allSubmounts == 0, only return the //mountRoot/all share
1619 * if in fact it has been been created in the subMounts table.
1620 * This is to allow sites that want to restrict access to the
1623 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1624 0, KEY_QUERY_VALUE, &parmKey);
1625 if (code == ERROR_SUCCESS) {
1626 len = sizeof(allSubmount);
1627 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1628 (BYTE *) &allSubmount, &len);
1629 if (code != ERROR_SUCCESS) {
1632 RegCloseKey (parmKey);
1635 if (allSubmount && _stricmp(shareName, "all") == 0) {
1640 /* In case, the all share is disabled we need to still be able
1641 * to handle ioctl requests
1643 if (_stricmp(shareName, "ioctl$") == 0) {
1644 *pathNamep = strdup("/.__ioctl__");
1648 if (_stricmp(shareName, "IPC$") == 0 ||
1649 _stricmp(shareName, "srvsvc") == 0 ||
1650 _stricmp(shareName, "wkssvc") == 0 ||
1651 _stricmp(shareName, SMB_IOCTL_FILENAME_NOSLASH) == 0 ||
1652 _stricmp(shareName, "DESKTOP.INI") == 0
1658 /* Check for volume references
1660 * They look like <cell>{%,#}<volume>
1662 if (strchr(shareName, '%') != NULL ||
1663 strchr(shareName, '#') != NULL) {
1664 char pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1665 /* make room for '/@vol:' + mountchar + NULL terminator*/
1667 osi_Log1(smb_logp, "smb_FindShare found volume reference [%s]",
1668 osi_LogSaveString(smb_logp, shareName));
1670 snprintf(pathstr, sizeof(pathstr)/sizeof(char),
1671 "/" CM_PREFIX_VOL "%s", shareName);
1672 pathstr[sizeof(pathstr)/sizeof(char) - 1] = '\0';
1673 len = (DWORD)(strlen(pathstr) + 1);
1675 *pathNamep = malloc(len);
1677 strcpy(*pathNamep, pathstr);
1679 osi_Log1(smb_logp, " returning pathname [%s]",
1680 osi_LogSaveString(smb_logp, *pathNamep));
1688 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1689 0, KEY_QUERY_VALUE, &parmKey);
1690 if (code == ERROR_SUCCESS) {
1691 len = sizeof(pathName);
1692 code = RegQueryValueEx(parmKey, shareName, NULL, NULL,
1693 (BYTE *) pathName, &len);
1694 if (code != ERROR_SUCCESS)
1696 RegCloseKey (parmKey);
1700 if (len != 0 && len != sizeof(pathName) - 1) {
1701 /* We can accept either unix or PC style AFS pathnames. Convert
1702 * Unix-style to PC style here for internal use.
1705 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1706 p += strlen(cm_mountRoot); /* skip mount path */
1709 if (*q == '/') *q = '\\'; /* change to \ */
1715 if (var = smb_stristr(p, VNUserName)) {
1716 if (uidp && uidp->unp)
1717 smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1719 smb_subst(p, var, sizeof(VNUserName)," ");
1721 else if (var = smb_stristr(p, VNLCUserName))
1723 if (uidp && uidp->unp)
1724 strcpy(temp, uidp->unp->name);
1728 smb_subst(p, var, sizeof(VNLCUserName), temp);
1730 else if (var = smb_stristr(p, VNComputerName))
1732 sizeTemp = sizeof(temp);
1733 GetComputerName((LPTSTR)temp, &sizeTemp);
1734 smb_subst(p, var, sizeof(VNComputerName), temp);
1736 else if (var = smb_stristr(p, VNLCComputerName))
1738 sizeTemp = sizeof(temp);
1739 GetComputerName((LPTSTR)temp, &sizeTemp);
1741 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1746 *pathNamep = strdup(p);
1751 /* First lookup shareName in root.afs */
1753 smb_findShare_rock_t vrock;
1755 char * p = shareName;
1758 /* attempt to locate a partial match in root.afs. This is because
1759 when using the ANSI RAP calls, the share name is limited to 13 chars
1760 and hence is truncated. Of course we prefer exact matches. */
1762 thyper.HighPart = 0;
1765 vrock.shareName = shareName;
1767 vrock.matchType = 0;
1769 cm_HoldSCache(cm_data.rootSCachep);
1770 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1771 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1772 cm_ReleaseSCache(cm_data.rootSCachep);
1774 if (vrock.matchType) {
1775 sprintf(pathName,"/%s/",vrock.match);
1776 *pathNamep = strdup(strlwr(pathName));
1781 /* if we get here, there was no match for the share in root.afs */
1782 /* so try to create \\<netbiosName>\<cellname> */
1787 /* Get the full name for this cell */
1788 code = cm_SearchCellFile(p, temp, 0, 0);
1789 #ifdef AFS_AFSDB_ENV
1790 if (code && cm_dnsEnabled) {
1792 code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1795 /* construct the path */
1797 sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1798 *pathNamep = strdup(strlwr(pathName));
1807 /* Client-side offline caching policy types */
1808 #define CSC_POLICY_MANUAL 0
1809 #define CSC_POLICY_DOCUMENTS 1
1810 #define CSC_POLICY_PROGRAMS 2
1811 #define CSC_POLICY_DISABLE 3
1813 int smb_FindShareCSCPolicy(char *shareName)
1819 int retval = CSC_POLICY_MANUAL;
1821 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1822 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1825 REG_OPTION_NON_VOLATILE,
1831 len = sizeof(policy);
1832 if ( RegQueryValueEx( hkCSCPolicy, shareName, 0, &dwType, policy, &len ) ||
1834 retval = stricmp("all",shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1836 else if (stricmp(policy, "documents") == 0)
1838 retval = CSC_POLICY_DOCUMENTS;
1840 else if (stricmp(policy, "programs") == 0)
1842 retval = CSC_POLICY_PROGRAMS;
1844 else if (stricmp(policy, "disable") == 0)
1846 retval = CSC_POLICY_DISABLE;
1849 RegCloseKey(hkCSCPolicy);
1853 /* find a dir search structure by cookie value, and return it held.
1854 * Must be called with smb_globalLock held.
1856 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1858 smb_dirSearch_t *dsp;
1860 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1861 if (dsp->cookie == cookie) {
1862 if (dsp != smb_firstDirSearchp) {
1863 /* move to head of LRU queue, too, if we're not already there */
1864 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1865 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1866 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1867 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1868 if (!smb_lastDirSearchp)
1869 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1871 lock_ObtainMutex(&dsp->mx);
1873 lock_ReleaseMutex(&dsp->mx);
1879 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1880 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1881 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1887 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1889 lock_ObtainWrite(&smb_globalLock);
1890 lock_ObtainMutex(&dsp->mx);
1891 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1892 dsp->cookie, dsp, dsp->scp);
1893 dsp->flags |= SMB_DIRSEARCH_DELETE;
1894 if (dsp->scp != NULL) {
1895 lock_ObtainWrite(&dsp->scp->rw);
1896 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1897 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1898 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1899 dsp->scp->bulkStatProgress = hzero;
1901 lock_ReleaseWrite(&dsp->scp->rw);
1903 lock_ReleaseMutex(&dsp->mx);
1904 lock_ReleaseWrite(&smb_globalLock);
1907 /* Must be called with the smb_globalLock held */
1908 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1910 cm_scache_t *scp = NULL;
1912 lock_ObtainMutex(&dsp->mx);
1913 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1914 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1915 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1916 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1917 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1918 lock_ReleaseMutex(&dsp->mx);
1919 lock_FinalizeMutex(&dsp->mx);
1921 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1922 dsp->cookie, dsp, scp);
1925 lock_ReleaseMutex(&dsp->mx);
1927 /* do this now to avoid spurious locking hierarchy creation */
1929 cm_ReleaseSCache(scp);
1932 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1934 lock_ObtainWrite(&smb_globalLock);
1935 smb_ReleaseDirSearchNoLock(dsp);
1936 lock_ReleaseWrite(&smb_globalLock);
1939 /* find a dir search structure by cookie value, and return it held */
1940 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1942 smb_dirSearch_t *dsp;
1944 lock_ObtainWrite(&smb_globalLock);
1945 dsp = smb_FindDirSearchNoLock(cookie);
1946 lock_ReleaseWrite(&smb_globalLock);
1950 /* GC some dir search entries, in the address space expected by the specific protocol.
1951 * Must be called with smb_globalLock held; release the lock temporarily.
1953 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
1954 void smb_GCDirSearches(int isV3)
1956 smb_dirSearch_t *prevp;
1957 smb_dirSearch_t *tp;
1958 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1962 victimCount = 0; /* how many have we got so far */
1963 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
1964 /* we'll move tp from queue, so
1967 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
1968 /* if no one is using this guy, and we're either in the new protocol,
1969 * or we're in the old one and this is a small enough ID to be useful
1970 * to the old protocol, GC this guy.
1972 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1973 /* hold and delete */
1974 lock_ObtainMutex(&tp->mx);
1975 tp->flags |= SMB_DIRSEARCH_DELETE;
1976 lock_ReleaseMutex(&tp->mx);
1977 victimsp[victimCount++] = tp;
1981 /* don't do more than this */
1982 if (victimCount >= SMB_DIRSEARCH_GCMAX)
1986 /* now release them */
1987 for (i = 0; i < victimCount; i++) {
1988 smb_ReleaseDirSearchNoLock(victimsp[i]);
1992 /* function for allocating a dir search entry. We need these to remember enough context
1993 * since we don't get passed the path from call to call during a directory search.
1995 * Returns a held dir search structure, and bumps the reference count on the vnode,
1996 * since it saves a pointer to the vnode.
1998 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2000 smb_dirSearch_t *dsp;
2006 lock_ObtainWrite(&smb_globalLock);
2009 /* what's the biggest ID allowed in this version of the protocol */
2010 /* TODO: do we really want a non v3 dir search request to wrap
2011 smb_dirSearchCounter? */
2012 maxAllowed = isV3 ? 65535 : 255;
2013 if (smb_dirSearchCounter > maxAllowed)
2014 smb_dirSearchCounter = 1;
2016 start = smb_dirSearchCounter;
2019 /* twice so we have enough tries to find guys we GC after one pass;
2020 * 10 extra is just in case I mis-counted.
2022 if (++counter > 2*maxAllowed+10)
2023 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2025 if (smb_dirSearchCounter > maxAllowed) {
2026 smb_dirSearchCounter = 1;
2028 if (smb_dirSearchCounter == start) {
2030 smb_GCDirSearches(isV3);
2033 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2035 /* don't need to watch for refcount zero and deleted, since
2036 * we haven't dropped the global lock.
2038 lock_ObtainMutex(&dsp->mx);
2040 lock_ReleaseMutex(&dsp->mx);
2041 ++smb_dirSearchCounter;
2045 dsp = malloc(sizeof(*dsp));
2046 memset(dsp, 0, sizeof(*dsp));
2047 dsp->cookie = smb_dirSearchCounter;
2048 ++smb_dirSearchCounter;
2050 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2051 dsp->lastTime = osi_Time();
2052 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2053 if (!smb_lastDirSearchp)
2054 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2056 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2060 lock_ReleaseWrite(&smb_globalLock);
2064 static smb_packet_t *GetPacket(void)
2068 lock_ObtainWrite(&smb_globalLock);
2069 tbp = smb_packetFreeListp;
2071 smb_packetFreeListp = tbp->nextp;
2072 lock_ReleaseWrite(&smb_globalLock);
2074 tbp = calloc(sizeof(*tbp),1);
2075 tbp->magic = SMB_PACKETMAGIC;
2078 tbp->resumeCode = 0;
2084 tbp->ncb_length = 0;
2087 tbp->stringsp = NULL;
2089 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2094 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2098 memcpy(tbp, pkt, sizeof(smb_packet_t));
2099 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2100 tbp->stringsp = NULL;
2102 smb_HoldVC(tbp->vcp);
2106 static NCB *GetNCB(void)
2111 lock_ObtainWrite(&smb_globalLock);
2112 tbp = smb_ncbFreeListp;
2114 smb_ncbFreeListp = tbp->nextp;
2115 lock_ReleaseWrite(&smb_globalLock);
2117 tbp = calloc(sizeof(*tbp),1);
2118 tbp->magic = SMB_NCBMAGIC;
2121 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2123 memset(&tbp->ncb, 0, sizeof(NCB));
2128 static void FreeSMBStrings(smb_packet_t * pkt)
2133 for (s = pkt->stringsp; s; s = ns) {
2137 pkt->stringsp = NULL;
2140 void smb_FreePacket(smb_packet_t *tbp)
2142 smb_vc_t * vcp = NULL;
2143 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2145 lock_ObtainWrite(&smb_globalLock);
2146 tbp->nextp = smb_packetFreeListp;
2147 smb_packetFreeListp = tbp;
2148 tbp->magic = SMB_PACKETMAGIC;
2152 tbp->resumeCode = 0;
2158 tbp->ncb_length = 0;
2160 FreeSMBStrings(tbp);
2161 lock_ReleaseWrite(&smb_globalLock);
2167 static void FreeNCB(NCB *bufferp)
2171 tbp = (smb_ncb_t *) bufferp;
2172 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2174 lock_ObtainWrite(&smb_globalLock);
2175 tbp->nextp = smb_ncbFreeListp;
2176 smb_ncbFreeListp = tbp;
2177 lock_ReleaseWrite(&smb_globalLock);
2180 /* get a ptr to the data part of a packet, and its count */
2181 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2185 unsigned char *afterParmsp;
2187 parmBytes = *smbp->wctp << 1;
2188 afterParmsp = smbp->wctp + parmBytes + 1;
2190 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2191 if (nbytesp) *nbytesp = dataBytes;
2193 /* don't forget to skip the data byte count, since it follows
2194 * the parameters; that's where the "2" comes from below.
2196 return (unsigned char *) (afterParmsp + 2);
2199 /* must set all the returned parameters before playing around with the
2200 * data region, since the data region is located past the end of the
2201 * variable number of parameters.
2203 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2205 unsigned char *afterParmsp;
2207 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2209 *afterParmsp++ = dsize & 0xff;
2210 *afterParmsp = (dsize>>8) & 0xff;
2213 /* return the parm'th parameter in the smbp packet */
2214 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2217 unsigned char *parmDatap;
2219 parmCount = *smbp->wctp;
2221 if (parm >= parmCount) {
2224 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2225 parm, parmCount, smbp->ncb_length);
2226 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2227 parm, parmCount, smbp->ncb_length);
2228 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2229 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2230 osi_panic(s, __FILE__, __LINE__);
2232 parmDatap = smbp->wctp + (2*parm) + 1;
2234 return parmDatap[0] + (parmDatap[1] << 8);
2237 /* return the parm'th parameter in the smbp packet */
2238 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2241 unsigned char *parmDatap;
2243 parmCount = *smbp->wctp;
2245 if (parm >= parmCount) {
2248 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2249 parm, parmCount, smbp->ncb_length);
2250 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2251 parm, parmCount, smbp->ncb_length);
2252 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2253 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2254 osi_panic(s, __FILE__, __LINE__);
2256 parmDatap = smbp->wctp + (2*parm) + 1;
2258 return parmDatap[0];
2261 /* return the parm'th parameter in the smbp packet */
2262 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2265 unsigned char *parmDatap;
2267 parmCount = *smbp->wctp;
2269 if (parm + 1 >= parmCount) {
2272 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2273 parm, parmCount, smbp->ncb_length);
2274 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2275 parm, parmCount, smbp->ncb_length);
2276 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2277 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2278 osi_panic(s, __FILE__, __LINE__);
2280 parmDatap = smbp->wctp + (2*parm) + 1;
2282 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2285 /* return the parm'th parameter in the smbp packet */
2286 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2289 unsigned char *parmDatap;
2291 parmCount = *smbp->wctp;
2293 if (parm * 2 + offset >= parmCount * 2) {
2296 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2297 parm, offset, parmCount, smbp->ncb_length);
2298 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2299 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2300 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2301 parm, offset, parmCount, smbp->ncb_length);
2302 osi_panic(s, __FILE__, __LINE__);
2304 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2306 return parmDatap[0] + (parmDatap[1] << 8);
2309 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2313 /* make sure we have enough slots */
2314 if (*smbp->wctp <= slot)
2315 *smbp->wctp = slot+1;
2317 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2318 *parmDatap++ = parmValue & 0xff;
2319 *parmDatap = (parmValue>>8) & 0xff;
2322 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2326 /* make sure we have enough slots */
2327 if (*smbp->wctp <= slot)
2328 *smbp->wctp = slot+2;
2330 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2331 *parmDatap++ = parmValue & 0xff;
2332 *parmDatap++ = (parmValue>>8) & 0xff;
2333 *parmDatap++ = (parmValue>>16) & 0xff;
2334 *parmDatap = (parmValue>>24) & 0xff;
2337 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2342 /* make sure we have enough slots */
2343 if (*smbp->wctp <= slot)
2344 *smbp->wctp = slot+4;
2346 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2348 *parmDatap++ = *parmValuep++;
2351 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2355 /* make sure we have enough slots */
2356 if (*smbp->wctp <= slot) {
2357 if (smbp->oddByte) {
2359 *smbp->wctp = slot+1;
2364 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2365 *parmDatap++ = parmValue & 0xff;
2370 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
2374 lastSlashp = strrchr(inPathp, '\\');
2376 *lastComponentp = lastSlashp;
2379 if (inPathp == lastSlashp)
2381 *outPathp++ = *inPathp++;
2390 unsigned char *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2391 char **chainpp, int flags)
2399 if (!WANTS_UNICODE(pktp))
2400 flags |= SMB_STRF_FORCEASCII;
2403 cb = sizeof(pktp->data) - (inp - pktp->data);
2404 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2405 #ifdef DEBUG_UNICODE
2408 cb = sizeof(pktp->data);
2410 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2413 unsigned char *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2414 char ** chainpp, int flags)
2419 if (!WANTS_UNICODE(pktp))
2420 flags |= SMB_STRF_FORCEASCII;
2423 cb = sizeof(pktp->data) - (inp - pktp->data);
2424 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2425 #ifdef DEBUG_UNICODE
2428 cb = sizeof(pktp->data);
2430 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2433 unsigned char *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2434 size_t cb, char ** chainpp, int flags)
2437 if (!WANTS_UNICODE(pktp))
2438 flags |= SMB_STRF_FORCEASCII;
2441 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2444 unsigned char *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2445 size_t cch, char ** chainpp, int flags)
2450 if (!WANTS_UNICODE(pktp))
2451 flags |= SMB_STRF_FORCEASCII;
2453 cb = cch * sizeof(wchar_t);
2456 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2459 unsigned char *smb_ParseStringBuf(const unsigned char * bufbase,
2460 cm_space_t ** stringspp,
2461 unsigned char *inp, size_t *pcb_max,
2462 char **chainpp, int flags)
2465 if (!(flags & SMB_STRF_FORCEASCII)) {
2468 cm_space_t * spacep;
2471 if (bufbase && ((inp - bufbase) % 2) != 0) {
2472 inp++; /* unicode strings are always word aligned */
2476 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2478 cch_src = *pcb_max / sizeof(wchar_t);
2482 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2489 spacep = cm_GetSpace();
2490 spacep->nextp = *stringspp;
2491 *stringspp = spacep;
2495 *chainpp = inp + sizeof(wchar_t);
2498 spacep->data[0] = '\0';
2499 return spacep->data;
2502 cb_dest = cm_NormalizeUtf16StringToUtf8((const wchar_t *) inp, cch_src,
2503 spacep->data, sizeof(spacep->data));
2505 *stringspp = spacep->nextp;
2506 cm_FreeSpace(spacep);
2507 #ifdef DEBUG_UNICODE
2514 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2517 #ifdef DEBUG_UNICODE
2520 } else if (spacep->data[cb_dest - 1] != 0) {
2521 spacep->data[cb_dest++] = 0;
2524 return spacep->data;
2528 /* Not using Unicode */
2530 *chainpp = inp + strlen(inp) + 1;
2532 if ((flags & SMB_STRF_ANSIPATH) && smb_StoreAnsiFilenames)
2533 OemToChar(inp, inp);
2540 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2541 unsigned char * str,
2542 size_t * plen, int flags)
2548 /* we are only calculating the required size */
2551 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2554 nchars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
2556 if (nchars == 0 && GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
2558 if ((flags & SMB_STRF_ANSIPATH) && smb_StoreAnsiFilenames)
2559 nchars = MultiByteToWideChar(1252 /* ANSI - Latin1 */,
2560 0, str, -1, NULL, 0);
2562 nchars = MultiByteToWideChar(CP_OEMCP,
2563 0, str, -1, NULL, 0);
2567 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2568 osi_LogSaveString(smb_logp, str),
2576 *plen = sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENULL)? nchars - 1 : nchars);
2578 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2588 *plen = ((flags & SMB_STRF_IGNORENULL)? len: len+1);
2594 /* Number of bytes left in the buffer. */
2595 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2596 align = ((outp - pktp->data) % 2);
2597 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2599 align = (((size_t) outp) % 2);
2600 buffersize = sizeof(pktp->data);
2605 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2613 if (buffersize < sizeof(wchar_t))
2616 *((wchar_t *) outp) = L'\0';
2617 if (plen && !(flags & SMB_STRF_IGNORENULL))
2618 *plen += sizeof(wchar_t);
2619 return outp + sizeof(wchar_t);
2622 nchars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
2623 str, -1, (wchar_t *) outp, buffersize);
2624 if (nchars == 0 && GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
2626 /* If we failed to translate the string from UTF-8 to
2627 UTF-16, then chances are the string wasn't UTF-8 to
2628 begin with. If StoreAnsiFileNames is set and this is
2629 possibly an ANSI file name, we try assuming that the
2630 source name is in ANSI. otherwise we try OEM. */
2632 if ((flags & SMB_STRF_ANSIPATH) && smb_StoreAnsiFilenames)
2633 nchars = MultiByteToWideChar(1252 /* ANSI - Latin1 */,
2634 0, str, -1, (wchar_t *) outp, buffersize);
2636 nchars = MultiByteToWideChar(CP_OEMCP,
2637 0, str, -1, (wchar_t *) outp, buffersize);
2641 /* Both 1252 and OEM should translate to Unicode without a
2642 complaint. This is something else. */
2643 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2644 osi_LogSaveString(smb_logp, str),
2650 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENULL)? nchars - 1: nchars);
2652 return outp + sizeof(wchar_t) * nchars;
2660 len = strlen(str); len++;
2661 if (len > buffersize)
2666 *plen += ((flags & SMB_STRF_IGNORENULL)? len - 1: len);
2672 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2678 tlen = inp[0] + (inp[1]<<8);
2679 inp += 2; /* skip length field */
2682 *chainpp = inp + tlen;
2691 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2695 if (*inp++ != 0x1) return NULL;
2696 tlen = inp[0] + (inp[1]<<8);
2697 inp += 2; /* skip length field */
2700 *chainpp = inp + tlen;
2703 if (lengthp) *lengthp = tlen;
2708 /* format a packet as a response */
2709 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2714 outp = (smb_t *) op;
2716 /* zero the basic structure through the smb_wct field, and zero the data
2717 * size field, assuming that wct stays zero; otherwise, you have to
2718 * explicitly set the data size field, too.
2720 inSmbp = (smb_t *) inp;
2721 memset(outp, 0, sizeof(smb_t)+2);
2727 outp->com = inSmbp->com;
2728 outp->tid = inSmbp->tid;
2729 outp->pid = inSmbp->pid;
2730 outp->uid = inSmbp->uid;
2731 outp->mid = inSmbp->mid;
2732 outp->res[0] = inSmbp->res[0];
2733 outp->res[1] = inSmbp->res[1];
2734 op->inCom = inSmbp->com;
2736 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2737 #ifdef SEND_CANONICAL_PATHNAMES
2738 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2740 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2742 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2743 outp->flg2 |= SMB_FLAGS2_UNICODE;
2746 /* copy fields in generic packet area */
2747 op->wctp = &outp->wct;
2750 /* send a (probably response) packet; vcp tells us to whom to send it.
2751 * we compute the length by looking at wct and bcc fields.
2753 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2767 memset((char *)ncbp, 0, sizeof(NCB));
2769 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2770 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2771 extra += tp[0] + (tp[1]<<8);
2772 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2773 extra += 3; /* wct and length fields */
2775 ncbp->ncb_length = extra; /* bytes to send */
2776 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2777 ncbp->ncb_lana_num = vcp->lana;
2778 ncbp->ncb_command = NCBSEND; /* op means send data */
2779 ncbp->ncb_buffer = (char *) inp;/* packet */
2780 code = Netbios(ncbp);
2783 const char * s = ncb_error_string(code);
2784 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2785 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2787 lock_ObtainMutex(&vcp->mx);
2788 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2789 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2791 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2792 lock_ReleaseMutex(&vcp->mx);
2793 lock_ObtainWrite(&smb_globalLock);
2794 dead_sessions[vcp->session] = TRUE;
2795 lock_ReleaseWrite(&smb_globalLock);
2796 smb_CleanupDeadVC(vcp);
2798 lock_ReleaseMutex(&vcp->mx);
2806 void smb_MapNTError(long code, unsigned long *NTStatusp)
2808 unsigned long NTStatus;
2810 /* map CM_ERROR_* errors to NT 32-bit status codes */
2811 /* NT Status codes are listed in ntstatus.h not winerror.h */
2812 if (code == CM_ERROR_NOSUCHCELL) {
2813 NTStatus = 0xC000000FL; /* No such file */
2815 else if (code == CM_ERROR_NOSUCHVOLUME) {
2816 NTStatus = 0xC000000FL; /* No such file */
2818 else if (code == CM_ERROR_TIMEDOUT) {
2820 NTStatus = 0xC00000CFL; /* Sharing Paused */
2822 NTStatus = 0x00000102L; /* Timeout */
2825 else if (code == CM_ERROR_RETRY) {
2826 NTStatus = 0xC000022DL; /* Retry */
2828 else if (code == CM_ERROR_NOACCESS) {
2829 NTStatus = 0xC0000022L; /* Access denied */
2831 else if (code == CM_ERROR_READONLY) {
2832 NTStatus = 0xC00000A2L; /* Write protected */
2834 else if (code == CM_ERROR_NOSUCHFILE ||
2835 code == CM_ERROR_BPLUS_NOMATCH) {
2836 NTStatus = 0xC000000FL; /* No such file */
2838 else if (code == CM_ERROR_NOSUCHPATH) {
2839 NTStatus = 0xC000003AL; /* Object path not found */
2841 else if (code == CM_ERROR_TOOBIG) {
2842 NTStatus = 0xC000007BL; /* Invalid image format */
2844 else if (code == CM_ERROR_INVAL) {
2845 NTStatus = 0xC000000DL; /* Invalid parameter */
2847 else if (code == CM_ERROR_BADFD) {
2848 NTStatus = 0xC0000008L; /* Invalid handle */
2850 else if (code == CM_ERROR_BADFDOP) {
2851 NTStatus = 0xC0000022L; /* Access denied */
2853 else if (code == CM_ERROR_EXISTS) {
2854 NTStatus = 0xC0000035L; /* Object name collision */
2856 else if (code == CM_ERROR_NOTEMPTY) {
2857 NTStatus = 0xC0000101L; /* Directory not empty */
2859 else if (code == CM_ERROR_CROSSDEVLINK) {
2860 NTStatus = 0xC00000D4L; /* Not same device */
2862 else if (code == CM_ERROR_NOTDIR) {
2863 NTStatus = 0xC0000103L; /* Not a directory */
2865 else if (code == CM_ERROR_ISDIR) {
2866 NTStatus = 0xC00000BAL; /* File is a directory */
2868 else if (code == CM_ERROR_BADOP) {
2870 /* I have no idea where this comes from */
2871 NTStatus = 0xC09820FFL; /* SMB no support */
2873 NTStatus = 0xC00000BBL; /* Not supported */
2874 #endif /* COMMENT */
2876 else if (code == CM_ERROR_BADSHARENAME) {
2877 NTStatus = 0xC00000CCL; /* Bad network name */
2879 else if (code == CM_ERROR_NOIPC) {
2881 NTStatus = 0xC0000022L; /* Access Denied */
2883 NTStatus = 0xC000013DL; /* Remote Resources */
2886 else if (code == CM_ERROR_CLOCKSKEW) {
2887 NTStatus = 0xC0000133L; /* Time difference at DC */
2889 else if (code == CM_ERROR_BADTID) {
2890 NTStatus = 0xC0982005L; /* SMB bad TID */
2892 else if (code == CM_ERROR_USESTD) {
2893 NTStatus = 0xC09820FBL; /* SMB use standard */
2895 else if (code == CM_ERROR_QUOTA) {
2896 NTStatus = 0xC0000044L; /* Quota exceeded */
2898 else if (code == CM_ERROR_SPACE) {
2899 NTStatus = 0xC000007FL; /* Disk full */
2901 else if (code == CM_ERROR_ATSYS) {
2902 NTStatus = 0xC0000033L; /* Object name invalid */
2904 else if (code == CM_ERROR_BADNTFILENAME) {
2905 NTStatus = 0xC0000033L; /* Object name invalid */
2907 else if (code == CM_ERROR_WOULDBLOCK) {
2908 NTStatus = 0xC0000055L; /* Lock not granted */
2910 else if (code == CM_ERROR_SHARING_VIOLATION) {
2911 NTStatus = 0xC0000043L; /* Sharing violation */
2913 else if (code == CM_ERROR_LOCK_CONFLICT) {
2914 NTStatus = 0xC0000054L; /* Lock conflict */
2916 else if (code == CM_ERROR_PARTIALWRITE) {
2917 NTStatus = 0xC000007FL; /* Disk full */
2919 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2920 NTStatus = 0xC0000023L; /* Buffer too small */
2922 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2923 NTStatus = 0xC0000035L; /* Object name collision */
2925 else if (code == CM_ERROR_BADPASSWORD) {
2926 NTStatus = 0xC000006DL; /* unknown username or bad password */
2928 else if (code == CM_ERROR_BADLOGONTYPE) {
2929 NTStatus = 0xC000015BL; /* logon type not granted */
2931 else if (code == CM_ERROR_GSSCONTINUE) {
2932 NTStatus = 0xC0000016L; /* more processing required */
2934 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2936 NTStatus = 0xC0000280L; /* reparse point not resolved */
2938 NTStatus = 0xC0000022L; /* Access Denied */
2941 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2942 NTStatus = 0xC0000257L; /* Path Not Covered */
2944 else if (code == CM_ERROR_ALLBUSY) {
2945 NTStatus = 0xC000022DL; /* Retry */
2947 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2948 NTStatus = 0xC00000BEL; /* Bad Network Path */
2950 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
2951 NTStatus = 0xC0000322L; /* No Kerberos key */
2953 else if (code == CM_ERROR_BAD_LEVEL) {
2954 NTStatus = 0xC0000148L; /* Invalid Level */
2956 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
2957 NTStatus = 0xC000007EL; /* Range Not Locked */
2959 else if (code == CM_ERROR_NOSUCHDEVICE) {
2960 NTStatus = 0xC000000EL; /* No Such Device */
2962 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
2963 NTStatus = 0xC0000055L; /* Lock Not Granted */
2965 NTStatus = 0xC0982001L; /* SMB non-specific error */
2968 *NTStatusp = NTStatus;
2969 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
2972 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2973 unsigned char *classp)
2975 unsigned char class;
2976 unsigned short error;
2978 /* map CM_ERROR_* errors to SMB errors */
2979 if (code == CM_ERROR_NOSUCHCELL) {
2981 error = 3; /* bad path */
2983 else if (code == CM_ERROR_NOSUCHVOLUME) {
2985 error = 3; /* bad path */
2987 else if (code == CM_ERROR_TIMEDOUT) {
2989 error = 81; /* server is paused */
2991 else if (code == CM_ERROR_RETRY) {
2992 class = 2; /* shouldn't happen */
2995 else if (code == CM_ERROR_NOACCESS) {
2997 error = 4; /* bad access */
2999 else if (code == CM_ERROR_READONLY) {
3001 error = 19; /* read only */
3003 else if (code == CM_ERROR_NOSUCHFILE ||
3004 code == CM_ERROR_BPLUS_NOMATCH) {
3006 error = 2; /* ENOENT! */
3008 else if (code == CM_ERROR_NOSUCHPATH) {
3010 error = 3; /* Bad path */
3012 else if (code == CM_ERROR_TOOBIG) {
3014 error = 11; /* bad format */
3016 else if (code == CM_ERROR_INVAL) {
3017 class = 2; /* server non-specific error code */
3020 else if (code == CM_ERROR_BADFD) {
3022 error = 6; /* invalid file handle */
3024 else if (code == CM_ERROR_BADFDOP) {
3025 class = 1; /* invalid op on FD */
3028 else if (code == CM_ERROR_EXISTS) {
3030 error = 80; /* file already exists */
3032 else if (code == CM_ERROR_NOTEMPTY) {
3034 error = 5; /* delete directory not empty */
3036 else if (code == CM_ERROR_CROSSDEVLINK) {
3038 error = 17; /* EXDEV */
3040 else if (code == CM_ERROR_NOTDIR) {
3041 class = 1; /* bad path */
3044 else if (code == CM_ERROR_ISDIR) {
3045 class = 1; /* access denied; DOS doesn't have a good match */
3048 else if (code == CM_ERROR_BADOP) {
3052 else if (code == CM_ERROR_BADSHARENAME) {
3056 else if (code == CM_ERROR_NOIPC) {
3058 error = 4; /* bad access */
3060 else if (code == CM_ERROR_CLOCKSKEW) {
3061 class = 1; /* invalid function */
3064 else if (code == CM_ERROR_BADTID) {
3068 else if (code == CM_ERROR_USESTD) {
3072 else if (code == CM_ERROR_REMOTECONN) {
3076 else if (code == CM_ERROR_QUOTA) {
3077 if (vcp->flags & SMB_VCFLAG_USEV3) {
3079 error = 39; /* disk full */
3083 error = 5; /* access denied */
3086 else if (code == CM_ERROR_SPACE) {
3087 if (vcp->flags & SMB_VCFLAG_USEV3) {
3089 error = 39; /* disk full */
3093 error = 5; /* access denied */
3096 else if (code == CM_ERROR_PARTIALWRITE) {
3098 error = 39; /* disk full */
3100 else if (code == CM_ERROR_ATSYS) {
3102 error = 2; /* ENOENT */
3104 else if (code == CM_ERROR_WOULDBLOCK) {
3106 error = 33; /* lock conflict */
3108 else if (code == CM_ERROR_LOCK_CONFLICT) {
3110 error = 33; /* lock conflict */
3112 else if (code == CM_ERROR_SHARING_VIOLATION) {
3114 error = 33; /* lock conflict */
3116 else if (code == CM_ERROR_NOFILES) {
3118 error = 18; /* no files in search */
3120 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3122 error = 183; /* Samba uses this */
3124 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3125 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3127 error = 2; /* bad password */
3129 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3131 error = 3; /* bad path */
3140 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3143 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3145 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3146 return CM_ERROR_BADOP;
3150 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3152 unsigned short EchoCount, i;
3153 char *data, *outdata;
3156 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3158 for (i=1; i<=EchoCount; i++) {
3159 data = smb_GetSMBData(inp, &dataSize);
3160 smb_SetSMBParm(outp, 0, i);
3161 smb_SetSMBDataLength(outp, dataSize);
3162 outdata = smb_GetSMBData(outp, NULL);
3163 memcpy(outdata, data, dataSize);
3164 smb_SendPacket(vcp, outp);
3170 /* SMB_COM_READ_RAW */
3171 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3174 long count, minCount, finalCount;
3178 smb_t *smbp = (smb_t*) inp;
3180 cm_user_t *userp = NULL;
3183 char *rawBuf = NULL;
3188 fd = smb_GetSMBParm(inp, 0);
3189 count = smb_GetSMBParm(inp, 3);
3190 minCount = smb_GetSMBParm(inp, 4);
3191 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3193 if (*inp->wctp == 10) {
3194 /* we were sent a request with 64-bit file offsets */
3195 #ifdef AFS_LARGEFILES
3196 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3198 if (LargeIntegerLessThanZero(offset)) {
3199 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3203 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3204 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3207 offset.HighPart = 0;
3211 /* we were sent a request with 32-bit file offsets */
3212 offset.HighPart = 0;
3215 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3216 fd, offset.HighPart, offset.LowPart, count);
3218 fidp = smb_FindFID(vcp, fd, 0);
3222 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3223 smb_CloseFID(vcp, fidp, NULL, 0);
3224 code = CM_ERROR_NOSUCHFILE;
3231 LARGE_INTEGER LOffset, LLength;
3234 key = cm_GenerateKey(vcp->vcID, pid, fd);
3236 LOffset.HighPart = offset.HighPart;
3237 LOffset.LowPart = offset.LowPart;
3238 LLength.HighPart = 0;
3239 LLength.LowPart = count;
3241 lock_ObtainWrite(&fidp->scp->rw);
3242 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3243 lock_ReleaseWrite(&fidp->scp->rw);
3249 lock_ObtainMutex(&smb_RawBufLock);
3251 /* Get a raw buf, from head of list */
3252 rawBuf = smb_RawBufs;
3253 smb_RawBufs = *(char **)smb_RawBufs;
3255 lock_ReleaseMutex(&smb_RawBufLock);
3259 lock_ObtainMutex(&fidp->mx);
3260 if (fidp->flags & SMB_FID_IOCTL)
3262 lock_ReleaseMutex(&fidp->mx);
3263 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3265 /* Give back raw buffer */
3266 lock_ObtainMutex(&smb_RawBufLock);
3267 *((char **) rawBuf) = smb_RawBufs;
3269 smb_RawBufs = rawBuf;
3270 lock_ReleaseMutex(&smb_RawBufLock);
3273 lock_ReleaseMutex(&fidp->mx);
3274 smb_ReleaseFID(fidp);
3277 lock_ReleaseMutex(&fidp->mx);
3279 userp = smb_GetUserFromVCP(vcp, inp);
3281 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3287 cm_ReleaseUser(userp);
3290 smb_ReleaseFID(fidp);
3294 memset((char *)ncbp, 0, sizeof(NCB));
3296 ncbp->ncb_length = (unsigned short) finalCount;
3297 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3298 ncbp->ncb_lana_num = vcp->lana;
3299 ncbp->ncb_command = NCBSEND;
3300 ncbp->ncb_buffer = rawBuf;
3302 code = Netbios(ncbp);
3304 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3307 /* Give back raw buffer */
3308 lock_ObtainMutex(&smb_RawBufLock);
3309 *((char **) rawBuf) = smb_RawBufs;
3311 smb_RawBufs = rawBuf;
3312 lock_ReleaseMutex(&smb_RawBufLock);
3318 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3320 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3325 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3327 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3332 /* SMB_COM_NEGOTIATE */
3333 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3340 int VistaProtoIndex;
3341 int protoIndex; /* index we're using */
3346 char protocol_array[10][1024]; /* protocol signature of the client */
3347 int caps; /* capabilities */
3350 TIME_ZONE_INFORMATION tzi;
3352 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3355 namep = smb_GetSMBData(inp, &dbytes);
3358 coreProtoIndex = -1; /* not found */
3361 VistaProtoIndex = -1;
3362 while(namex < dbytes) {
3363 osi_Log1(smb_logp, "Protocol %s",
3364 osi_LogSaveString(smb_logp, namep+1));
3365 strcpy(protocol_array[tcounter], namep+1);
3367 /* namep points at the first protocol, or really, a 0x02
3368 * byte preceding the null-terminated ASCII name.
3370 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3371 coreProtoIndex = tcounter;
3373 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3374 v3ProtoIndex = tcounter;
3376 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3377 NTProtoIndex = tcounter;
3379 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3380 VistaProtoIndex = tcounter;
3383 /* compute size of protocol entry */
3384 entryLength = (int)strlen(namep+1);
3385 entryLength += 2; /* 0x02 bytes and null termination */
3387 /* advance over this protocol entry */
3388 namex += entryLength;
3389 namep += entryLength;
3390 tcounter++; /* which proto entry we're looking at */
3393 lock_ObtainMutex(&vcp->mx);
3395 if (VistaProtoIndex != -1) {
3396 protoIndex = VistaProtoIndex;
3397 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3400 if (NTProtoIndex != -1) {
3401 protoIndex = NTProtoIndex;
3402 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3404 else if (v3ProtoIndex != -1) {
3405 protoIndex = v3ProtoIndex;
3406 vcp->flags |= SMB_VCFLAG_USEV3;
3408 else if (coreProtoIndex != -1) {
3409 protoIndex = coreProtoIndex;
3410 vcp->flags |= SMB_VCFLAG_USECORE;
3412 else protoIndex = -1;
3413 lock_ReleaseMutex(&vcp->mx);
3415 if (protoIndex == -1)
3416 return CM_ERROR_INVAL;
3417 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3418 smb_SetSMBParm(outp, 0, protoIndex);
3419 if (smb_authType != SMB_AUTH_NONE) {
3420 smb_SetSMBParmByte(outp, 1,
3421 NEGOTIATE_SECURITY_USER_LEVEL |
3422 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3424 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3426 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3427 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3428 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3429 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3430 /* The session key is not a well documented field however most clients
3431 * will echo back the session key to the server. Currently we are using
3432 * the same value for all sessions. We should generate a random value
3433 * and store it into the vcp
3435 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3436 smb_SetSMBParm(outp, 8, 1);
3438 * Tried changing the capabilities to support for W2K - defect 117695
3439 * Maybe something else needs to be changed here?
3443 smb_SetSMBParmLong(outp, 9, 0x43fd);
3445 smb_SetSMBParmLong(outp, 9, 0x251);
3448 * 32-bit error codes *
3454 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3456 NTNEGOTIATE_CAPABILITY_DFS |
3458 #ifdef AFS_LARGEFILES
3459 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3461 NTNEGOTIATE_CAPABILITY_NTFIND |
3462 NTNEGOTIATE_CAPABILITY_RAWMODE |
3463 NTNEGOTIATE_CAPABILITY_NTSMB;
3465 if ( smb_authType == SMB_AUTH_EXTENDED )
3466 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3469 if ( smb_UseUnicode ) {
3470 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3474 smb_SetSMBParmLong(outp, 9, caps);
3476 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3477 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3478 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3480 GetTimeZoneInformation(&tzi);
3481 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3483 if (smb_authType == SMB_AUTH_NTLM) {
3484 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3485 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3486 /* paste in encryption key */
3487 datap = smb_GetSMBData(outp, NULL);
3488 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3489 /* and the faux domain name */
3490 strcpy(datap + MSV1_0_CHALLENGE_LENGTH,smb_ServerDomainName);
3491 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3495 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3497 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3499 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3501 datap = smb_GetSMBData(outp, NULL);
3502 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3505 datap += sizeof(smb_ServerGUID);
3506 memcpy(datap, secBlob, secBlobLength);
3510 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3511 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3514 else if (v3ProtoIndex != -1) {
3515 smb_SetSMBParm(outp, 0, protoIndex);
3517 /* NOTE: Extended authentication cannot be negotiated with v3
3518 * therefore we fail over to NTLM
3520 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3521 smb_SetSMBParm(outp, 1,
3522 NEGOTIATE_SECURITY_USER_LEVEL |
3523 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3525 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3527 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3528 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3529 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3530 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3531 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3532 smb_SetSMBParm(outp, 7, 1);
3534 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3535 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3536 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3538 GetTimeZoneInformation(&tzi);
3539 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3541 /* NOTE: Extended authentication cannot be negotiated with v3
3542 * therefore we fail over to NTLM
3544 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3545 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3546 smb_SetSMBParm(outp, 12, 0); /* resvd */
3547 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3548 datap = smb_GetSMBData(outp, NULL);
3549 /* paste in a new encryption key */
3550 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3551 /* and the faux domain name */
3552 strcpy(datap + MSV1_0_CHALLENGE_LENGTH, smb_ServerDomainName);
3554 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3555 smb_SetSMBParm(outp, 12, 0); /* resvd */
3556 smb_SetSMBDataLength(outp, 0);
3559 else if (coreProtoIndex != -1) { /* not really supported anymore */
3560 smb_SetSMBParm(outp, 0, protoIndex);
3561 smb_SetSMBDataLength(outp, 0);
3566 void smb_CheckVCs(void)
3568 smb_vc_t * vcp, *nextp;
3569 smb_packet_t * outp = GetPacket();
3572 lock_ObtainWrite(&smb_rctLock);
3573 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3575 if (vcp->magic != SMB_VC_MAGIC)
3576 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3577 __FILE__, __LINE__);
3581 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3584 smb_HoldVCNoLock(vcp);
3586 smb_HoldVCNoLock(nextp);
3587 smb_FormatResponsePacket(vcp, NULL, outp);
3588 smbp = (smb_t *)outp;
3589 outp->inCom = smbp->com = 0x2b /* Echo */;
3597 smb_SetSMBParm(outp, 0, 0);
3598 smb_SetSMBDataLength(outp, 0);
3599 lock_ReleaseWrite(&smb_rctLock);
3601 smb_SendPacket(vcp, outp);
3603 lock_ObtainWrite(&smb_rctLock);
3604 smb_ReleaseVCNoLock(vcp);
3606 smb_ReleaseVCNoLock(nextp);
3608 lock_ReleaseWrite(&smb_rctLock);
3609 smb_FreePacket(outp);
3612 void smb_Daemon(void *parmp)
3614 afs_uint32 count = 0;
3615 smb_username_t **unpp;
3618 while(smbShutdownFlag == 0) {
3622 if (smbShutdownFlag == 1)
3625 if ((count % 72) == 0) { /* every five minutes */
3627 time_t old_localZero = smb_localZero;
3629 /* Initialize smb_localZero */
3630 myTime.tm_isdst = -1; /* compute whether on DST or not */
3631 myTime.tm_year = 70;
3637 smb_localZero = mktime(&myTime);
3639 #ifndef USE_NUMERIC_TIME_CONV
3640 smb_CalculateNowTZ();
3641 #endif /* USE_NUMERIC_TIME_CONV */
3642 #ifdef AFS_FREELANCE
3643 if ( smb_localZero != old_localZero )
3644 cm_noteLocalMountPointChange();
3650 /* GC smb_username_t objects that will no longer be used */
3652 lock_ObtainWrite(&smb_rctLock);
3653 for ( unpp=&usernamesp; *unpp; ) {
3655 smb_username_t *unp;
3657 lock_ObtainMutex(&(*unpp)->mx);
3658 if ( (*unpp)->refCount > 0 ||
3659 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3660 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3662 else if (!smb_LogoffTokenTransfer ||
3663 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3665 lock_ReleaseMutex(&(*unpp)->mx);
3673 lock_FinalizeMutex(&unp->mx);
3679 cm_ReleaseUser(userp);
3681 unpp = &(*unpp)->nextp;
3684 lock_ReleaseWrite(&smb_rctLock);
3686 /* XXX GC dir search entries */
3690 void smb_WaitingLocksDaemon()
3692 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3693 smb_waitingLock_t *wl, *wlNext;
3696 smb_packet_t *inp, *outp;
3700 while (smbShutdownFlag == 0) {
3701 lock_ObtainWrite(&smb_globalLock);
3702 nwlRequest = smb_allWaitingLocks;
3703 if (nwlRequest == NULL) {
3704 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3709 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3716 lock_ObtainWrite(&smb_globalLock);
3718 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3720 wlRequest = nwlRequest;
3721 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3722 lock_ReleaseWrite(&smb_globalLock);
3726 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3727 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3730 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
3731 code = CM_ERROR_LOCK_NOT_GRANTED;
3735 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3737 /* wl->state is either _DONE or _WAITING. _ERROR
3738 would no longer be on the queue. */
3739 code = cm_RetryLock( wl->lockp,
3740 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3743 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3744 } else if (code != CM_ERROR_WOULDBLOCK) {
3745 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3750 if (code == CM_ERROR_WOULDBLOCK) {
3753 if (wlRequest->msTimeout != 0xffffffff
3754 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
3766 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3769 scp = wlRequest->scp;
3770 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3774 lock_ObtainWrite(&scp->rw);
3776 for (wl = wlRequest->locks; wl; wl = wlNext) {
3777 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3779 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3780 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3781 wl->LLength, wl->key, NULL, &req);
3783 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3788 lock_ReleaseWrite(&scp->rw);
3792 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3795 for (wl = wlRequest->locks; wl; wl = wlNext) {
3796 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3797 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3802 vcp = wlRequest->vcp;
3803 inp = wlRequest->inp;
3804 outp = wlRequest->outp;
3806 ncbp->ncb_length = inp->ncb_length;
3807 inp->spacep = cm_GetSpace();
3809 /* Remove waitingLock from list */
3810 lock_ObtainWrite(&smb_globalLock);
3811 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3813 lock_ReleaseWrite(&smb_globalLock);
3815 /* Resume packet processing */
3817 smb_SetSMBDataLength(outp, 0);
3818 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3819 outp->resumeCode = code;
3821 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3824 cm_FreeSpace(inp->spacep);
3825 smb_FreePacket(inp);
3826 smb_FreePacket(outp);
3828 cm_ReleaseSCache(wlRequest->scp);
3831 } while (nwlRequest && smbShutdownFlag == 0);
3836 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3838 osi_Log0(smb_logp, "SMB receive get disk attributes");
3840 smb_SetSMBParm(outp, 0, 32000);
3841 smb_SetSMBParm(outp, 1, 64);
3842 smb_SetSMBParm(outp, 2, 1024);
3843 smb_SetSMBParm(outp, 3, 30000);
3844 smb_SetSMBParm(outp, 4, 0);
3845 smb_SetSMBDataLength(outp, 0);
3849 /* SMB_COM_TREE_CONNECT */
3850 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3854 unsigned short newTid;
3855 char shareName[AFSPATHMAX];
3862 osi_Log0(smb_logp, "SMB receive tree connect");
3864 /* parse input parameters */
3865 tp = smb_GetSMBData(inp, NULL);
3866 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
3867 tp = strrchr(pathp, '\\');
3869 return CM_ERROR_BADSMB;
3870 strcpy(shareName, tp+1);
3872 lock_ObtainMutex(&vcp->mx);
3873 newTid = vcp->tidCounter++;
3874 lock_ReleaseMutex(&vcp->mx);
3876 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3877 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3878 userp = smb_GetUserFromUID(uidp);
3879 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3881 smb_ReleaseUID(uidp);
3883 smb_ReleaseTID(tidp, FALSE);
3884 return CM_ERROR_BADSHARENAME;
3886 lock_ObtainMutex(&tidp->mx);
3887 tidp->userp = userp;
3888 tidp->pathname = sharePath;
3889 lock_ReleaseMutex(&tidp->mx);
3890 smb_ReleaseTID(tidp, FALSE);
3892 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3893 smb_SetSMBParm(rsp, 1, newTid);
3894 smb_SetSMBDataLength(rsp, 0);
3896 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3900 /* set maskp to the mask part of the incoming path.
3901 * Mask is 11 bytes long (8.3 with the dot elided).
3902 * Returns true if succeeds with a valid name, otherwise it does
3903 * its best, but returns false.
3905 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
3913 /* starts off valid */
3916 /* mask starts out all blanks */
3917 memset(maskp, ' ', 11);
3920 /* find last backslash, or use whole thing if there is none */
3921 tp = strrchr(pathp, '\\');
3925 tp++; /* skip slash */
3929 /* names starting with a dot are illegal */
3937 if (tc == '.' || tc == '"')
3945 /* if we get here, tp point after the dot */
3946 up = maskp+8; /* ext goes here */
3953 if (tc == '.' || tc == '"')
3956 /* copy extension if not too long */
3966 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
3976 /* XXX redo this, calling smb_V3MatchMask with a converted mask */
3978 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
3982 /* otherwise, we have a valid 8.3 name; see if we have a match,
3983 * treating '?' as a wildcard in maskp (but not in the file name).
3985 tp1 = umask; /* real name, in mask format */
3986 tp2 = maskp; /* mask, in mask format */
3987 for(i=0; i<11; i++) {
3988 tc1 = *tp1++; /* char from real name */
3989 tc2 = *tp2++; /* char from mask */
3990 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
3991 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
3994 if (tc2 == '?' && tc1 != ' ')
4001 /* we got a match */
4005 char *smb_FindMask(char *pathp)
4009 tp = strrchr(pathp, '\\'); /* find last slash */
4012 return tp+1; /* skip the slash */
4014 return pathp; /* no slash, return the entire path */
4017 /* SMB_COM_SEARCH for a volume label
4019 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4020 dispatch function.) */
4021 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4023 unsigned char *pathp;
4025 unsigned char mask[12];
4026 unsigned char *statBlockp;
4027 unsigned char initStatBlock[21];
4030 osi_Log0(smb_logp, "SMB receive search volume");
4032 /* pull pathname and stat block out of request */
4033 tp = smb_GetSMBData(inp, NULL);
4034 pathp = smb_ParseASCIIBlock(inp, tp, (char **) &tp,
4035 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4036 osi_assertx(pathp != NULL, "null path");
4037 statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
4038 osi_assertx(statBlockp != NULL, "null statBlock");
4040 statBlockp = initStatBlock;
4044 /* for returning to caller */
4045 smb_Get8Dot3MaskFromPath(mask, pathp);
4047 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4048 tp = smb_GetSMBData(outp, NULL);
4050 *tp++ = 43; /* bytes in a dir entry */
4051 *tp++ = 0; /* high byte in counter */
4053 /* now marshall the dir entry, starting with the search status */
4054 *tp++ = statBlockp[0]; /* Reserved */
4055 memcpy(tp, mask, 11); tp += 11; /* FileName */
4057 /* now pass back server use info, with 1st byte non-zero */
4059 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4061 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4063 *tp++ = 0x8; /* attribute: volume */
4073 /* 4 byte file size */
4079 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4082 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4083 memset(tp, ' ', 13);
4086 /* set the length of the data part of the packet to 43 + 3, for the dir
4087 * entry plus the 5 and the length fields.
4089 smb_SetSMBDataLength(outp, 46);
4094 smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
4095 char * tidPathp, char * relPathp,
4096 cm_user_t *userp, cm_req_t *reqp)
4104 smb_dirListPatch_t *patchp;
4105 smb_dirListPatch_t *npatchp;
4106 char path[AFSPATHMAX];
4108 for (patchp = *dirPatchespp; patchp; patchp =
4109 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4111 dptr = patchp->dptr;
4113 snprintf(path, AFSPATHMAX, "%s\\%s", relPathp ? relPathp : "", patchp->dep->name);
4114 reqp->relPathp = path;
4115 reqp->tidPathp = tidPathp;
4117 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4118 reqp->relPathp = reqp->tidPathp = NULL;
4121 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4122 *dptr++ = SMB_ATTR_HIDDEN;
4125 lock_ObtainWrite(&scp->rw);
4126 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
4127 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4129 lock_ReleaseWrite(&scp->rw);
4130 cm_ReleaseSCache(scp);
4131 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4132 *dptr++ = SMB_ATTR_HIDDEN;
4136 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4138 lock_ConvertWToR(&scp->rw);
4139 attr = smb_Attributes(scp);
4140 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4141 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4142 attr |= SMB_ATTR_HIDDEN;
4146 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4149 shortTemp = (unsigned short) (dosTime & 0xffff);
4150 *((u_short *)dptr) = shortTemp;
4153 /* and copy out date */
4154 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4155 *((u_short *)dptr) = shortTemp;
4158 /* copy out file length */
4159 *((u_long *)dptr) = scp->length.LowPart;
4161 lock_ReleaseRead(&scp->rw);
4162 cm_ReleaseSCache(scp);
4165 /* now free the patches */
4166 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4167 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4171 /* and mark the list as empty */
4172 *dirPatchespp = NULL;
4177 /* SMB_COM_SEARCH */
4178 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4185 cm_dirEntry_t *dep = 0;
4187 smb_dirListPatch_t *dirListPatchesp;
4188 smb_dirListPatch_t *curPatchp;
4192 osi_hyper_t dirLength;
4193 osi_hyper_t bufferOffset;
4194 osi_hyper_t curOffset;
4196 unsigned char *inCookiep;
4197 smb_dirSearch_t *dsp;
4201 unsigned long clientCookie;
4202 cm_pageHeader_t *pageHeaderp;
4203 cm_user_t *userp = NULL;
4210 long nextEntryCookie;
4211 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4212 char resByte; /* reserved byte from the cookie */
4213 char *op; /* output data ptr */
4214 char *origOp; /* original value of op */
4215 cm_space_t *spacep; /* for pathname buffer */
4226 maxCount = smb_GetSMBParm(inp, 0);
4228 dirListPatchesp = NULL;
4230 caseFold = CM_FLAG_CASEFOLD;
4232 tp = smb_GetSMBData(inp, NULL);
4233 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4234 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4235 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4237 /* bail out if request looks bad */
4238 if (!tp || !pathp) {
4239 return CM_ERROR_BADSMB;
4242 /* We can handle long names */
4243 if (vcp->flags & SMB_VCFLAG_USENT)
4244 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4246 /* make sure we got a whole search status */
4247 if (dataLength < 21) {
4248 nextCookie = 0; /* start at the beginning of the dir */
4251 attribute = smb_GetSMBParm(inp, 1);
4253 /* handle volume info in another function */
4254 if (attribute & 0x8)
4255 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4257 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
4258 maxCount, osi_LogSaveString(smb_logp, pathp));
4260 if (*pathp == 0) { /* null pathp, treat as root dir */
4261 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4262 return CM_ERROR_NOFILES;
4266 dsp = smb_NewDirSearch(0);
4267 dsp->attribute = attribute;
4268 smb_Get8Dot3MaskFromPath(mask, pathp);
4269 memcpy(dsp->mask, mask, 12);
4271 /* track if this is likely to match a lot of entries */
4272 if (smb_IsStarMask(mask))
4277 /* pull the next cookie value out of the search status block */
4278 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4279 + (inCookiep[16]<<24);
4280 dsp = smb_FindDirSearch(inCookiep[12]);
4282 /* can't find dir search status; fatal error */
4283 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%s]",
4284 inCookiep[12], nextCookie, osi_LogSaveString(smb_logp, pathp));
4285 return CM_ERROR_BADFD;
4287 attribute = dsp->attribute;
4288 resByte = inCookiep[0];
4290 /* copy out client cookie, in host byte order. Don't bother
4291 * interpreting it, since we're just passing it through, anyway.
4293 memcpy(&clientCookie, &inCookiep[17], 4);
4295 memcpy(mask, dsp->mask, 12);
4297 /* assume we're doing a star match if it has continued for more
4303 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4304 nextCookie, dsp->cookie, attribute);
4306 userp = smb_GetUserFromVCP(vcp, inp);
4308 /* try to get the vnode for the path name next */
4309 lock_ObtainMutex(&dsp->mx);
4312 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4316 spacep = inp->spacep;
4317 smb_StripLastComponent(spacep->data, NULL, pathp);
4318 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4320 lock_ReleaseMutex(&dsp->mx);
4321 cm_ReleaseUser(userp);
4322 smb_DeleteDirSearch(dsp);
4323 smb_ReleaseDirSearch(dsp);
4324 return CM_ERROR_NOFILES;
4326 strcpy(dsp->tidPath, tidPathp ? tidPathp : "/");
4327 strcpy(dsp->relPath, spacep->data);
4329 code = cm_NameI(cm_data.rootSCachep, spacep->data,
4330 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4333 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4334 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->data);
4335 cm_ReleaseSCache(scp);
4336 lock_ReleaseMutex(&dsp->mx);
4337 cm_ReleaseUser(userp);
4338 smb_DeleteDirSearch(dsp);
4339 smb_ReleaseDirSearch(dsp);
4340 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4341 return CM_ERROR_PATH_NOT_COVERED;
4343 return CM_ERROR_BADSHARENAME;
4345 #endif /* DFS_SUPPORT */
4348 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4349 /* we need one hold for the entry we just stored into,
4350 * and one for our own processing. When we're done with this
4351 * function, we'll drop the one for our own processing.
4352 * We held it once from the namei call, and so we do another hold
4356 lock_ObtainWrite(&scp->rw);
4357 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4358 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4359 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4360 dsp->flags |= SMB_DIRSEARCH_BULKST;
4361 dsp->scp->bulkStatProgress = hzero;
4363 lock_ReleaseWrite(&scp->rw);
4366 lock_ReleaseMutex(&dsp->mx);
4368 cm_ReleaseUser(userp);
4369 smb_DeleteDirSearch(dsp);
4370 smb_ReleaseDirSearch(dsp);
4374 /* reserves space for parameter; we'll adjust it again later to the
4375 * real count of the # of entries we returned once we've actually
4376 * assembled the directory listing.
4378 smb_SetSMBParm(outp, 0, 0);
4380 /* get the directory size */
4381 lock_ObtainWrite(&scp->rw);
4382 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4383 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4385 lock_ReleaseWrite(&scp->rw);
4386 cm_ReleaseSCache(scp);
4387 cm_ReleaseUser(userp);
4388 smb_DeleteDirSearch(dsp);
4389 smb_ReleaseDirSearch(dsp);
4393 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4395 dirLength = scp->length;
4397 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4398 curOffset.HighPart = 0;
4399 curOffset.LowPart = nextCookie;
4400 origOp = op = smb_GetSMBData(outp, NULL);
4401 /* and write out the basic header */
4402 *op++ = 5; /* variable block */
4403 op += 2; /* skip vbl block length; we'll fill it in later */
4407 /* make sure that curOffset.LowPart doesn't point to the first
4408 * 32 bytes in the 2nd through last dir page, and that it doesn't
4409 * point at the first 13 32-byte chunks in the first dir page,
4410 * since those are dir and page headers, and don't contain useful
4413 temp = curOffset.LowPart & (2048-1);
4414 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4415 /* we're in the first page */
4416 if (temp < 13*32) temp = 13*32;
4419 /* we're in a later dir page */
4420 if (temp < 32) temp = 32;
4423 /* make sure the low order 5 bits are zero */
4426 /* now put temp bits back ito curOffset.LowPart */
4427 curOffset.LowPart &= ~(2048-1);
4428 curOffset.LowPart |= temp;
4430 /* check if we've returned all the names that will fit in the
4433 if (returnedNames >= maxCount) {
4434 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4435 returnedNames, maxCount);
4439 /* check if we've passed the dir's EOF */
4440 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4442 /* see if we can use the bufferp we have now; compute in which page
4443 * the current offset would be, and check whether that's the offset
4444 * of the buffer we have. If not, get the buffer.
4446 thyper.HighPart = curOffset.HighPart;
4447 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4448 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4451 buf_Release(bufferp);
4454 lock_ReleaseWrite(&scp->rw);
4455 code = buf_Get(scp, &thyper, &bufferp);
4456 lock_ObtainMutex(&dsp->mx);
4458 /* now, if we're doing a star match, do bulk fetching of all of
4459 * the status info for files in the dir.
4462 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4463 lock_ObtainWrite(&scp->rw);
4464 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4465 LargeIntegerGreaterThanOrEqualTo(thyper,
4466 scp->bulkStatProgress)) {
4467 /* Don't bulk stat if risking timeout */
4468 int now = GetTickCount();
4469 if (now - req.startTime > RDRtimeout * 1000) {
4470 scp->bulkStatProgress = thyper;
4471 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4472 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4473 dsp->scp->bulkStatProgress = hzero;
4475 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4478 lock_ObtainWrite(&scp->rw);
4480 lock_ReleaseMutex(&dsp->mx);
4482 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4486 bufferOffset = thyper;
4488 /* now get the data in the cache */
4490 code = cm_SyncOp(scp, bufferp, userp, &req,
4492 CM_SCACHESYNC_NEEDCALLBACK |
4493 CM_SCACHESYNC_READ);
4495 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4499 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4501 if (cm_HaveBuffer(scp, bufferp, 0)) {
4502 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4506 /* otherwise, load the buffer and try again */
4507 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4509 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4510 scp, bufferp, code);
4515 buf_Release(bufferp);
4519 } /* if (wrong buffer) ... */
4521 /* now we have the buffer containing the entry we're interested in; copy
4522 * it out if it represents a non-deleted entry.
4524 entryInDir = curOffset.LowPart & (2048-1);
4525 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4527 /* page header will help tell us which entries are free. Page header
4528 * can change more often than once per buffer, since AFS 3 dir page size
4529 * may be less than (but not more than a buffer package buffer.
4531 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4532 temp &= ~(2048 - 1); /* turn off intra-page bits */
4533 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4535 /* now determine which entry we're looking at in the page. If it is
4536 * free (there's a free bitmap at the start of the dir), we should
4537 * skip these 32 bytes.
4539 slotInPage = (entryInDir & 0x7e0) >> 5;
4540 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4541 /* this entry is free */
4542 numDirChunks = 1; /* only skip this guy */
4546 tp = bufferp->datap + entryInBuffer;
4547 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4549 /* while we're here, compute the next entry's location, too,
4550 * since we'll need it when writing out the cookie into the dir
4553 * XXXX Probably should do more sanity checking.
4555 numDirChunks = cm_NameEntries(dep->name, NULL);
4557 /* compute the offset of the cookie representing the next entry */
4558 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4560 /* Compute 8.3 name if necessary */
4561 actualName = dep->name;
4562 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4563 cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
4564 actualName = shortName;
4567 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%s)",
4568 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4569 osi_LogSaveString(smb_logp, actualName));
4571 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4572 /* this is one of the entries to use: it is not deleted
4573 * and it matches the star pattern we're looking for.
4576 /* Eliminate entries that don't match requested
4579 /* no hidden files */
4580 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4581 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4585 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4587 /* We have already done the cm_TryBulkStat above */
4588 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4589 fileType = cm_FindFileType(&fid);
4590 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4591 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4593 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4594 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4595 fileType == CM_SCACHETYPE_DFSLINK ||
4596 fileType == CM_SCACHETYPE_INVALID)
4597 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4602 memcpy(op, mask, 11); op += 11;
4603 *op++ = (char) dsp->cookie; /* they say it must be non-zero */
4604 *op++ = (char)(nextEntryCookie & 0xff);
4605 *op++ = (char)((nextEntryCookie>>8) & 0xff);
4606 *op++ = (char)((nextEntryCookie>>16) & 0xff);
4607 *op++ = (char)((nextEntryCookie>>24) & 0xff);
4608 memcpy(op, &clientCookie, 4); op += 4;
4610 /* now we emit the attribute. This is sort of tricky,
4611 * since we need to really stat the file to find out
4612 * what type of entry we've got. Right now, we're
4613 * copying out data from a buffer, while holding the
4614 * scp locked, so it isn't really convenient to stat
4615 * something now. We'll put in a place holder now,
4616 * and make a second pass before returning this to get
4617 * the real attributes. So, we just skip the data for
4618 * now, and adjust it later. We allocate a patch
4619 * record to make it easy to find this point later.
4620 * The replay will happen at a time when it is safe to
4621 * unlock the directory.
4623 curPatchp = malloc(sizeof(*curPatchp));
4624 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4625 curPatchp->dptr = op;
4626 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4628 /* do hidden attribute here since name won't be around when applying
4632 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4633 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4635 curPatchp->flags = 0;
4637 op += 9; /* skip attr, time, date and size */
4639 /* zero out name area. The spec says to pad with
4640 * spaces, but Samba doesn't, and neither do we.
4644 /* finally, we get to copy out the name; we know that
4645 * it fits in 8.3 or the pattern wouldn't match, but it
4646 * never hurts to be sure.
4648 strncpy(op, actualName, 13);
4649 if (smb_StoreAnsiFilenames)
4651 /* This is a UCHAR field, which is ASCII even if Unicode
4654 /* Uppercase if requested by client */
4655 if (!KNOWS_LONG_NAMES(inp))
4660 /* now, adjust the # of entries copied */
4662 } /* if we're including this name */
4665 /* and adjust curOffset to be where the new cookie is */
4666 thyper.HighPart = 0;
4667 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4668 curOffset = LargeIntegerAdd(thyper, curOffset);
4669 } /* while copying data for dir listing */
4671 /* release the mutex */
4672 lock_ReleaseWrite(&scp->rw);
4674 buf_Release(bufferp);
4678 /* apply and free last set of patches; if not doing a star match, this
4679 * will be empty, but better safe (and freeing everything) than sorry.
4681 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4683 /* special return code for unsuccessful search */
4684 if (code == 0 && dataLength < 21 && returnedNames == 0)
4685 code = CM_ERROR_NOFILES;
4687 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4688 returnedNames, code);
4691 smb_DeleteDirSearch(dsp);
4692 smb_ReleaseDirSearch(dsp);
4693 cm_ReleaseSCache(scp);
4694 cm_ReleaseUser(userp);
4698 /* finalize the output buffer */
4699 smb_SetSMBParm(outp, 0, returnedNames);
4700 temp = (long) (op - origOp);
4701 smb_SetSMBDataLength(outp, temp);
4703 /* the data area is a variable block, which has a 5 (already there)
4704 * followed by the length of the # of data bytes. We now know this to
4705 * be "temp," although that includes the 3 bytes of vbl block header.
4706 * Deduct for them and fill in the length field.
4708 temp -= 3; /* deduct vbl block info */
4709 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4710 origOp[1] = (char)(temp & 0xff);
4711 origOp[2] = (char)((temp>>8) & 0xff);
4712 if (returnedNames == 0)
4713 smb_DeleteDirSearch(dsp);
4714 smb_ReleaseDirSearch(dsp);
4715 cm_ReleaseSCache(scp);
4716 cm_ReleaseUser(userp);
4721 /* verify that this is a valid path to a directory. I don't know why they
4722 * don't use the get file attributes call.
4724 * SMB_COM_CHECK_DIRECTORY
4726 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4730 cm_scache_t *rootScp;
4731 cm_scache_t *newScp;
4740 pathp = smb_GetSMBData(inp, NULL);
4741 pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
4743 return CM_ERROR_BADFD;
4744 osi_Log1(smb_logp, "SMB receive check path %s",
4745 osi_LogSaveString(smb_logp, pathp));
4747 rootScp = cm_data.rootSCachep;
4749 userp = smb_GetUserFromVCP(vcp, inp);
4751 caseFold = CM_FLAG_CASEFOLD;
4753 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4755 cm_ReleaseUser(userp);
4756 return CM_ERROR_NOSUCHPATH;
4758 code = cm_NameI(rootScp, pathp,
4759 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4760 userp, tidPathp, &req, &newScp);
4763 cm_ReleaseUser(userp);
4768 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4769 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4770 cm_ReleaseSCache(newScp);
4771 cm_ReleaseUser(userp);
4772 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4773 return CM_ERROR_PATH_NOT_COVERED;
4775 return CM_ERROR_BADSHARENAME;
4777 #endif /* DFS_SUPPORT */
4779 /* now lock the vnode with a callback; returns with newScp locked */
4780 lock_ObtainWrite(&newScp->rw);
4781 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4782 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4784 if (code != CM_ERROR_NOACCESS) {
4785 lock_ReleaseWrite(&newScp->rw);
4786 cm_ReleaseSCache(newScp);
4787 cm_ReleaseUser(userp);
4791 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4794 attrs = smb_Attributes(newScp);
4796 if (!(attrs & SMB_ATTR_DIRECTORY))
4797 code = CM_ERROR_NOTDIR;
4799 lock_ReleaseWrite(&newScp->rw);
4801 cm_ReleaseSCache(newScp);
4802 cm_ReleaseUser(userp);
4806 /* SMB_COM_SET_INFORMATION */
4807 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4811 cm_scache_t *rootScp;
4812 unsigned short attribute;
4814 cm_scache_t *newScp;
4823 /* decode basic attributes we're passed */
4824 attribute = smb_GetSMBParm(inp, 0);
4825 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4827 pathp = smb_GetSMBData(inp, NULL);
4828 pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
4830 return CM_ERROR_BADSMB;
4832 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4833 dosTime, attribute);
4835 rootScp = cm_data.rootSCachep;
4837 userp = smb_GetUserFromVCP(vcp, inp);
4839 caseFold = CM_FLAG_CASEFOLD;
4841 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4843 cm_ReleaseUser(userp);
4844 return CM_ERROR_NOSUCHFILE;
4846 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4847 tidPathp, &req, &newScp);
4850 cm_ReleaseUser(userp);
4855 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4856 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4857 cm_ReleaseSCache(newScp);
4858 cm_ReleaseUser(userp);
4859 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4860 return CM_ERROR_PATH_NOT_COVERED;
4862 return CM_ERROR_BADSHARENAME;
4864 #endif /* DFS_SUPPORT */
4866 /* now lock the vnode with a callback; returns with newScp locked; we
4867 * need the current status to determine what the new status is, in some
4870 lock_ObtainWrite(&newScp->rw);
4871 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4872 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4874 lock_ReleaseWrite(&newScp->rw);
4875 cm_ReleaseSCache(newScp);
4876 cm_ReleaseUser(userp);
4880 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4882 /* Check for RO volume */
4883 if (newScp->flags & CM_SCACHEFLAG_RO) {
4884 lock_ReleaseWrite(&newScp->rw);
4885 cm_ReleaseSCache(newScp);
4886 cm_ReleaseUser(userp);
4887 return CM_ERROR_READONLY;
4890 /* prepare for setattr call */
4893 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4894 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4896 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4897 /* we're told to make a writable file read-only */
4898 attr.unixModeBits = newScp->unixModeBits & ~0222;
4899 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4901 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4902 /* we're told to make a read-only file writable */
4903 attr.unixModeBits = newScp->unixModeBits | 0222;
4904 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4906 lock_ReleaseWrite(&newScp->rw);
4908 /* now call setattr */
4910 code = cm_SetAttr(newScp, &attr, userp, &req);
4914 cm_ReleaseSCache(newScp);
4915 cm_ReleaseUser(userp);
4921 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4925 cm_scache_t *rootScp;
4926 cm_scache_t *newScp, *dscp;
4938 pathp = smb_GetSMBData(inp, NULL);
4939 pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
4941 return CM_ERROR_BADSMB;
4943 if (*pathp == 0) /* null path */
4946 osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
4947 osi_LogSaveString(smb_logp, pathp));
4949 rootScp = cm_data.rootSCachep;
4951 userp = smb_GetUserFromVCP(vcp, inp);
4953 /* we shouldn't need this for V3 requests, but we seem to */
4954 caseFold = CM_FLAG_CASEFOLD;
4956 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4958 cm_ReleaseUser(userp);
4959 return CM_ERROR_NOSUCHFILE;
4963 * XXX Strange hack XXX
4965 * As of Patch 5 (16 July 97), we are having the following problem:
4966 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
4967 * requests to look up "desktop.ini" in all the subdirectories.
4968 * This can cause zillions of timeouts looking up non-existent cells
4969 * and volumes, especially in the top-level directory.
4971 * We have not found any way to avoid this or work around it except
4972 * to explicitly ignore the requests for mount points that haven't
4973 * yet been evaluated and for directories that haven't yet been
4976 * We should modify this hack to provide a fake desktop.ini file
4977 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
4979 spacep = inp->spacep;
4980 smb_StripLastComponent(spacep->data, &lastComp, pathp);
4981 #ifndef SPECIAL_FOLDERS
4982 if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
4983 code = cm_NameI(rootScp, spacep->data,
4984 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
4985 userp, tidPathp, &req, &dscp);
4988 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
4989 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
4990 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4991 return CM_ERROR_PATH_NOT_COVERED;
4993 return CM_ERROR_BADSHARENAME;
4995 #endif /* DFS_SUPPORT */
4996 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
4997 code = CM_ERROR_NOSUCHFILE;
4998 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
4999 cm_buf_t *bp = buf_Find(dscp, &hzero);
5004 code = CM_ERROR_NOSUCHFILE;
5006 cm_ReleaseSCache(dscp);
5008 cm_ReleaseUser(userp);
5013 #endif /* SPECIAL_FOLDERS */
5015 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5016 tidPathp, &req, &newScp);
5018 cm_ReleaseUser(userp);
5023 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5024 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5025 cm_ReleaseSCache(newScp);
5026 cm_ReleaseUser(userp);
5027 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5028 return CM_ERROR_PATH_NOT_COVERED;
5030 return CM_ERROR_BADSHARENAME;
5032 #endif /* DFS_SUPPORT */
5034 /* now lock the vnode with a callback; returns with newScp locked */
5035 lock_ObtainWrite(&newScp->rw);
5036 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5037 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5039 lock_ReleaseWrite(&newScp->rw);
5040 cm_ReleaseSCache(newScp);
5041 cm_ReleaseUser(userp);
5045 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5048 /* use smb_Attributes instead. Also the fact that a file is
5049 * in a readonly volume doesn't mean it shojuld be marked as RO
5051 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
5052 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
5053 newScp->fileType == CM_SCACHETYPE_INVALID)
5054 attrs = SMB_ATTR_DIRECTORY;
5057 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
5058 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
5060 attrs = smb_Attributes(newScp);
5063 smb_SetSMBParm(outp, 0, attrs);
5065 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5066 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5067 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5068 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5069 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5070 smb_SetSMBParm(outp, 5, 0);
5071 smb_SetSMBParm(outp, 6, 0);
5072 smb_SetSMBParm(outp, 7, 0);
5073 smb_SetSMBParm(outp, 8, 0);
5074 smb_SetSMBParm(outp, 9, 0);
5075 smb_SetSMBDataLength(outp, 0);
5076 lock_ReleaseWrite(&newScp->rw);
5078 cm_ReleaseSCache(newScp);
5079 cm_ReleaseUser(userp);
5084 /* SMB_COM_TREE_DISCONNECT */
5085 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5089 osi_Log0(smb_logp, "SMB receive tree disconnect");
5091 /* find the tree and free it */
5092 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5094 lock_ObtainWrite(&smb_rctLock);
5096 smb_ReleaseTID(tidp, TRUE);
5097 lock_ReleaseWrite(&smb_rctLock);
5104 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5122 pathp = smb_GetSMBData(inp, NULL);
5123 pathp = smb_ParseASCIIBlock(inp, pathp, NULL, SMB_STRF_ANSIPATH);
5125 osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
5127 #ifdef DEBUG_VERBOSE
5131 hexpath = osi_HexifyString( pathp );
5132 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5137 share = smb_GetSMBParm(inp, 0);
5138 attribute = smb_GetSMBParm(inp, 1);
5140 spacep = inp->spacep;
5141 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5142 if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
5143 /* special case magic file name for receiving IOCTL requests
5144 * (since IOCTL calls themselves aren't getting through).
5146 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5147 smb_SetupIoctlFid(fidp, spacep);
5148 smb_SetSMBParm(outp, 0, fidp->fid);
5149 smb_SetSMBParm(outp, 1, 0); /* attrs */
5150 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5151 smb_SetSMBParm(outp, 3, 0);
5152 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5153 smb_SetSMBParm(outp, 5, 0x7fff);
5154 /* pass the open mode back */
5155 smb_SetSMBParm(outp, 6, (share & 0xf));
5156 smb_SetSMBDataLength(outp, 0);
5157 smb_ReleaseFID(fidp);
5161 userp = smb_GetUserFromVCP(vcp, inp);
5163 caseFold = CM_FLAG_CASEFOLD;
5165 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5167 cm_ReleaseUser(userp);
5168 return CM_ERROR_NOSUCHPATH;
5170 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5171 tidPathp, &req, &scp);
5174 cm_ReleaseUser(userp);
5179 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5180 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5181 cm_ReleaseSCache(scp);
5182 cm_ReleaseUser(userp);
5183 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5184 return CM_ERROR_PATH_NOT_COVERED;
5186 return CM_ERROR_BADSHARENAME;
5188 #endif /* DFS_SUPPORT */
5190 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5192 cm_ReleaseSCache(scp);
5193 cm_ReleaseUser(userp);
5197 /* don't need callback to check file type, since file types never
5198 * change, and namei and cm_Lookup all stat the object at least once on
5199 * a successful return.
5201 if (scp->fileType != CM_SCACHETYPE_FILE) {
5202 cm_ReleaseSCache(scp);
5203 cm_ReleaseUser(userp);
5204 return CM_ERROR_ISDIR;
5207 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5208 osi_assertx(fidp, "null smb_fid_t");
5210 /* save a pointer to the vnode */
5212 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5213 lock_ObtainWrite(&scp->rw);
5214 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5215 lock_ReleaseWrite(&scp->rw);
5219 fidp->userp = userp;
5221 lock_ObtainMutex(&fidp->mx);
5222 if ((share & 0xf) == 0)
5223 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5224 else if ((share & 0xf) == 1)
5225 fidp->flags |= SMB_FID_OPENWRITE;
5227 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5228 lock_ReleaseMutex(&fidp->mx);
5230 lock_ObtainRead(&scp->rw);
5231 smb_SetSMBParm(outp, 0, fidp->fid);
5232 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5233 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5234 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5235 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5236 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5237 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5238 /* pass the open mode back; XXXX add access checks */
5239 smb_SetSMBParm(outp, 6, (share & 0xf));
5240 smb_SetSMBDataLength(outp, 0);
5241 lock_ReleaseRead(&scp->rw);
5244 cm_Open(scp, 0, userp);
5246 /* send and free packet */
5247 smb_ReleaseFID(fidp);
5248 cm_ReleaseUser(userp);
5249 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5253 typedef struct smb_unlinkRock {
5258 char *maskp; /* pointer to the star pattern */
5261 cm_dirEntryList_t * matches;
5264 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5267 smb_unlinkRock_t *rockp;
5275 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5276 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5277 caseFold |= CM_FLAG_8DOT3;
5279 matchName = dep->name;
5280 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
5282 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5283 !cm_Is8Dot3(dep->name)) {
5284 cm_Gen8Dot3Name(dep, shortName, NULL);
5285 matchName = shortName;
5286 /* 8.3 matches are always case insensitive */
5287 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5290 osi_Log1(smb_logp, "Found match %s",
5291 osi_LogSaveString(smb_logp, matchName));
5293 cm_DirEntryListAdd(dep->name, &rockp->matches);
5297 /* If we made a case sensitive exact match, we might as well quit now. */
5298 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !strcmp(matchName, rockp->maskp))
5299 code = CM_ERROR_STOPNOW;
5308 /* SMB_COM_DELETE */
5309 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5318 smb_unlinkRock_t rock;
5327 attribute = smb_GetSMBParm(inp, 0);
5329 tp = smb_GetSMBData(inp, NULL);
5330 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5332 osi_Log1(smb_logp, "SMB receive unlink %s",
5333 osi_LogSaveString(smb_logp, pathp));
5335 spacep = inp->spacep;
5336 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5338 userp = smb_GetUserFromVCP(vcp, inp);
5340 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5342 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5344 cm_ReleaseUser(userp);
5345 return CM_ERROR_NOSUCHPATH;
5347 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold, userp, tidPathp,
5350 cm_ReleaseUser(userp);
5355 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5356 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,spacep->data);
5357 cm_ReleaseSCache(dscp);
5358 cm_ReleaseUser(userp);
5359 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5360 return CM_ERROR_PATH_NOT_COVERED;
5362 return CM_ERROR_BADSHARENAME;
5364 #endif /* DFS_SUPPORT */
5366 /* otherwise, scp points to the parent directory. */
5373 rock.maskp = smb_FindMask(pathp);
5374 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5377 thyper.HighPart = 0;
5382 rock.matches = NULL;
5384 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5385 * match. If that fails, we do a case insensitve match.
5387 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5388 !smb_IsStarMask(rock.maskp)) {
5389 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5392 thyper.HighPart = 0;
5393 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5398 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5400 if (code == CM_ERROR_STOPNOW)
5403 if (code == 0 && rock.matches) {
5404 cm_dirEntryList_t * entry;
5406 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5408 osi_Log1(smb_logp, "Unlinking %s",
5409 osi_LogSaveString(smb_logp, entry->name));
5410 code = cm_Unlink(dscp, entry->name, userp, &req);
5412 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5413 smb_NotifyChange(FILE_ACTION_REMOVED,
5414 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5415 dscp, entry->name, NULL, TRUE);
5419 cm_DirEntryListFree(&rock.matches);
5421 cm_ReleaseUser(userp);
5423 cm_ReleaseSCache(dscp);
5425 if (code == 0 && !rock.any)
5426 code = CM_ERROR_NOSUCHFILE;
5430 typedef struct smb_renameRock {
5431 cm_scache_t *odscp; /* old dir */
5432 cm_scache_t *ndscp; /* new dir */
5433 cm_user_t *userp; /* user */
5434 cm_req_t *reqp; /* request struct */
5435 smb_vc_t *vcp; /* virtual circuit */
5436 char *maskp; /* pointer to star pattern of old file name */
5437 int flags; /* tilde, casefold, etc */
5438 char *newNamep; /* ptr to the new file's name */
5439 char oldName[MAX_PATH];
5443 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5446 smb_renameRock_t *rockp;
5449 char shortName[13]="";
5451 rockp = (smb_renameRock_t *) vrockp;
5453 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5454 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5455 caseFold |= CM_FLAG_8DOT3;
5457 match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
5459 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5460 !cm_Is8Dot3(dep->name)) {
5461 cm_Gen8Dot3Name(dep, shortName, NULL);
5462 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
5467 strncpy(rockp->oldName, dep->name, sizeof(rockp->oldName)/sizeof(char) - 1);
5468 rockp->oldName[sizeof(rockp->oldName)/sizeof(char) - 1] = '\0';
5469 code = CM_ERROR_STOPNOW;
5479 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp, int attrs)
5482 cm_space_t *spacep = NULL;
5483 smb_renameRock_t rock;
5484 cm_scache_t *oldDscp = NULL;
5485 cm_scache_t *newDscp = NULL;
5486 cm_scache_t *tmpscp= NULL;
5487 cm_scache_t *tmpscp2 = NULL;
5497 userp = smb_GetUserFromVCP(vcp, inp);
5498 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5500 cm_ReleaseUser(userp);
5501 return CM_ERROR_NOSUCHPATH;
5505 spacep = inp->spacep;
5506 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5508 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5509 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5510 userp, tidPathp, &req, &oldDscp);
5512 cm_ReleaseUser(userp);
5517 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5518 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
5519 cm_ReleaseSCache(oldDscp);
5520 cm_ReleaseUser(userp);
5521 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5522 return CM_ERROR_PATH_NOT_COVERED;
5524 return CM_ERROR_BADSHARENAME;
5526 #endif /* DFS_SUPPORT */
5528 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5529 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5530 userp, tidPathp, &req, &newDscp);
5533 cm_ReleaseSCache(oldDscp);
5534 cm_ReleaseUser(userp);
5539 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5540 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
5541 cm_ReleaseSCache(oldDscp);
5542 cm_ReleaseSCache(newDscp);
5543 cm_ReleaseUser(userp);
5544 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5545 return CM_ERROR_PATH_NOT_COVERED;
5547 return CM_ERROR_BADSHARENAME;
5549 #endif /* DFS_SUPPORT */
5552 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5553 * next, get the component names, and lower case them.
5556 /* handle the old name first */
5558 oldLastNamep = oldPathp;
5562 /* and handle the new name, too */
5564 newLastNamep = newPathp;
5568 /* TODO: The old name could be a wildcard. The new name must not be */
5570 /* do the vnode call */
5571 rock.odscp = oldDscp;
5572 rock.ndscp = newDscp;
5576 rock.maskp = oldLastNamep;
5577 rock.flags = ((strchr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5578 rock.newNamep = newLastNamep;
5579 rock.oldName[0] = '\0';
5582 /* Check if the file already exists; if so return error */
5583 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5584 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5585 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5587 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5588 osi_LogSaveString(smb_logp, newLastNamep));
5590 /* Check if the old and the new names differ only in case. If so return
5591 * success, else return CM_ERROR_EXISTS
5593 if (!code && oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
5595 /* This would be a success only if the old file is *as same as* the new file */
5596 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5598 if (tmpscp == tmpscp2)
5601 code = CM_ERROR_EXISTS;
5602 cm_ReleaseSCache(tmpscp2);
5605 code = CM_ERROR_NOSUCHFILE;
5608 /* file exist, do not rename, also fixes move */
5609 osi_Log0(smb_logp, "Can't rename. Target already exists");
5610 code = CM_ERROR_EXISTS;
5614 cm_ReleaseSCache(tmpscp);
5615 cm_ReleaseSCache(newDscp);
5616 cm_ReleaseSCache(oldDscp);
5617 cm_ReleaseUser(userp);
5621 /* Now search the directory for the pattern, and do the appropriate rename when found */
5622 thyper.LowPart = 0; /* search dir from here */
5623 thyper.HighPart = 0;
5625 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5626 if (code == 0 && !rock.any) {
5628 thyper.HighPart = 0;
5629 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5630 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5632 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5634 if (code == CM_ERROR_STOPNOW && rock.oldName[0] != '\0') {
5635 code = cm_Rename(rock.odscp, rock.oldName,
5636 rock.ndscp, rock.newNamep, rock.userp,
5638 /* if the call worked, stop doing the search now, since we
5639 * really only want to rename one file.
5641 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5642 } else if (code == 0) {
5643 code = CM_ERROR_NOSUCHFILE;
5646 /* Handle Change Notification */
5648 * Being lazy, not distinguishing between files and dirs in this
5649 * filter, since we'd have to do a lookup.
5652 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5653 if (oldDscp == newDscp) {
5654 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5655 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5656 filter, oldDscp, oldLastNamep,
5657 newLastNamep, TRUE);
5659 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5660 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5661 filter, oldDscp, oldLastNamep,
5663 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5664 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5665 filter, newDscp, newLastNamep,
5671 cm_ReleaseSCache(tmpscp);
5672 cm_ReleaseUser(userp);
5673 cm_ReleaseSCache(oldDscp);
5674 cm_ReleaseSCache(newDscp);
5679 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, char * oldPathp, char * newPathp)
5682 cm_space_t *spacep = NULL;
5683 cm_scache_t *oldDscp = NULL;
5684 cm_scache_t *newDscp = NULL;
5685 cm_scache_t *tmpscp= NULL;
5686 cm_scache_t *tmpscp2 = NULL;
5687 cm_scache_t *sscp = NULL;
5696 userp = smb_GetUserFromVCP(vcp, inp);
5698 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5700 cm_ReleaseUser(userp);
5701 return CM_ERROR_NOSUCHPATH;
5706 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5708 spacep = inp->spacep;
5709 smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
5711 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5712 userp, tidPathp, &req, &oldDscp);
5714 cm_ReleaseUser(userp);
5719 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5720 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->data);
5721 cm_ReleaseSCache(oldDscp);
5722 cm_ReleaseUser(userp);
5723 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5724 return CM_ERROR_PATH_NOT_COVERED;
5726 return CM_ERROR_BADSHARENAME;
5728 #endif /* DFS_SUPPORT */
5730 smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
5731 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold,
5732 userp, tidPathp, &req, &newDscp);
5734 cm_ReleaseSCache(oldDscp);
5735 cm_ReleaseUser(userp);
5740 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5741 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->data);
5742 cm_ReleaseSCache(newDscp);
5743 cm_ReleaseSCache(oldDscp);
5744 cm_ReleaseUser(userp);
5745 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5746 return CM_ERROR_PATH_NOT_COVERED;
5748 return CM_ERROR_BADSHARENAME;
5750 #endif /* DFS_SUPPORT */
5752 /* Now, although we did two lookups for the two directories (because the same
5753 * directory can be referenced through different paths), we only allow hard links
5754 * within the same directory. */
5755 if (oldDscp != newDscp) {
5756 cm_ReleaseSCache(oldDscp);
5757 cm_ReleaseSCache(newDscp);
5758 cm_ReleaseUser(userp);
5759 return CM_ERROR_CROSSDEVLINK;
5762 /* handle the old name first */
5764 oldLastNamep = oldPathp;
5768 /* and handle the new name, too */
5770 newLastNamep = newPathp;
5774 /* now lookup the old name */
5775 osi_Log1(smb_logp," looking up [%s]", osi_LogSaveString(smb_logp,oldLastNamep));
5776 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5778 cm_ReleaseSCache(oldDscp);
5779 cm_ReleaseSCache(newDscp);
5780 cm_ReleaseUser(userp);
5784 /* Check if the file already exists; if so return error */
5785 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5786 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5787 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5789 osi_Log2(smb_logp, " lookup returns %ld for [%s]", code,
5790 osi_LogSaveString(smb_logp, newLastNamep));
5792 /* if the existing link is to the same file, then we return success */
5794 if(sscp == tmpscp) {
5797 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5798 code = CM_ERROR_EXISTS;
5803 cm_ReleaseSCache(tmpscp);
5804 cm_ReleaseSCache(sscp);
5805 cm_ReleaseSCache(newDscp);
5806 cm_ReleaseSCache(oldDscp);
5807 cm_ReleaseUser(userp);
5811 /* now create the hardlink */
5812 osi_Log1(smb_logp," Attempting to create new link [%s]", osi_LogSaveString(smb_logp, newLastNamep));
5813 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5814 osi_Log1(smb_logp," Link returns 0x%x", code);
5816 /* Handle Change Notification */
5818 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5819 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5820 smb_NotifyChange(FILE_ACTION_ADDED,
5821 filter, newDscp, newLastNamep,
5826 cm_ReleaseSCache(tmpscp);
5827 cm_ReleaseUser(userp);
5828 cm_ReleaseSCache(sscp);
5829 cm_ReleaseSCache(oldDscp);
5830 cm_ReleaseSCache(newDscp);
5834 /* SMB_COM_RENAME */
5836 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5843 tp = smb_GetSMBData(inp, NULL);
5844 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5845 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5847 osi_Log2(smb_logp, "smb rename [%s] to [%s]",
5848 osi_LogSaveString(smb_logp, oldPathp),
5849 osi_LogSaveString(smb_logp, newPathp));
5851 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5853 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5859 typedef struct smb_rmdirRock {
5863 char *maskp; /* pointer to the star pattern */
5866 cm_dirEntryList_t * matches;
5869 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5872 smb_rmdirRock_t *rockp;
5877 rockp = (smb_rmdirRock_t *) vrockp;
5879 matchName = dep->name;
5880 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5881 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5883 match = (strcmp(matchName, rockp->maskp) == 0);
5885 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5886 !cm_Is8Dot3(dep->name)) {
5887 cm_Gen8Dot3Name(dep, shortName, NULL);
5888 matchName = shortName;
5889 match = (cm_stricmp(matchName, rockp->maskp) == 0);
5894 cm_DirEntryListAdd(dep->name, &rockp->matches);
5901 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5909 smb_rmdirRock_t rock;
5918 tp = smb_GetSMBData(inp, NULL);
5919 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5921 spacep = inp->spacep;
5922 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5924 userp = smb_GetUserFromVCP(vcp, inp);
5926 caseFold = CM_FLAG_CASEFOLD;
5928 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5930 cm_ReleaseUser(userp);
5931 return CM_ERROR_NOSUCHPATH;
5933 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5934 userp, tidPathp, &req, &dscp);
5937 cm_ReleaseUser(userp);
5942 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5943 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
5944 cm_ReleaseSCache(dscp);
5945 cm_ReleaseUser(userp);
5946 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5947 return CM_ERROR_PATH_NOT_COVERED;
5949 return CM_ERROR_BADSHARENAME;
5951 #endif /* DFS_SUPPORT */
5953 /* otherwise, scp points to the parent directory. */
5960 rock.maskp = lastNamep;
5961 rock.flags = ((strchr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5964 thyper.HighPart = 0;
5968 rock.matches = NULL;
5970 /* First do a case sensitive match, and if that fails, do a case insensitive match */
5971 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5972 if (code == 0 && !rock.any) {
5974 thyper.HighPart = 0;
5975 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5976 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
5979 if (code == 0 && rock.matches) {
5980 cm_dirEntryList_t * entry;
5982 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5983 osi_Log1(smb_logp, "Removing directory %s",
5984 osi_LogSaveString(smb_logp, entry->name));
5986 code = cm_RemoveDir(dscp, entry->name, userp, &req);
5988 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5989 smb_NotifyChange(FILE_ACTION_REMOVED,
5990 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
5991 dscp, entry->name, NULL, TRUE);
5995 cm_DirEntryListFree(&rock.matches);
5997 cm_ReleaseUser(userp);
5999 cm_ReleaseSCache(dscp);
6001 if (code == 0 && !rock.any)
6002 code = CM_ERROR_NOSUCHFILE;
6007 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6017 fid = smb_GetSMBParm(inp, 0);
6019 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6021 fid = smb_ChainFID(fid, inp);
6022 fidp = smb_FindFID(vcp, fid, 0);
6024 return CM_ERROR_BADFD;
6026 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6027 smb_CloseFID(vcp, fidp, NULL, 0);
6028 smb_ReleaseFID(fidp);
6029 return CM_ERROR_NOSUCHFILE;
6032 lock_ObtainMutex(&fidp->mx);
6033 if (fidp->flags & SMB_FID_IOCTL) {
6034 lock_ReleaseMutex(&fidp->mx);
6035 smb_ReleaseFID(fidp);
6036 return CM_ERROR_BADFD;
6038 lock_ReleaseMutex(&fidp->mx);
6040 userp = smb_GetUserFromVCP(vcp, inp);
6042 lock_ObtainMutex(&fidp->mx);
6043 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6044 cm_scache_t * scp = fidp->scp;
6046 lock_ReleaseMutex(&fidp->mx);
6047 code = cm_FSync(scp, userp, &req);
6048 cm_ReleaseSCache(scp);
6051 lock_ReleaseMutex(&fidp->mx);
6054 smb_ReleaseFID(fidp);
6056 cm_ReleaseUser(userp);
6061 struct smb_FullNameRock {
6067 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6071 struct smb_FullNameRock *vrockp;
6073 vrockp = (struct smb_FullNameRock *)rockp;
6075 if (!cm_Is8Dot3(dep->name)) {
6076 cm_Gen8Dot3Name(dep, shortName, NULL);
6078 if (cm_stricmp(shortName, vrockp->name) == 0) {
6079 vrockp->fullName = strdup(dep->name);
6080 return CM_ERROR_STOPNOW;
6083 if (cm_stricmp(dep->name, vrockp->name) == 0 &&
6084 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6085 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6086 vrockp->fullName = strdup(dep->name);
6087 return CM_ERROR_STOPNOW;
6092 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
6093 char **newPathp, cm_user_t *userp, cm_req_t *reqp)
6095 struct smb_FullNameRock rock;
6101 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6102 if (code == CM_ERROR_STOPNOW)
6103 *newPathp = rock.fullName;
6105 *newPathp = strdup(pathp);
6108 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6109 afs_uint32 dosTime) {
6112 cm_scache_t *dscp = NULL;
6114 cm_scache_t * scp = NULL;
6115 cm_scache_t *delscp = NULL;
6117 int nullcreator = 0;
6119 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6120 fidp, fidp->fid, scp, vcp);
6123 lock_ObtainMutex(&fidp->mx);
6124 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6125 lock_ReleaseMutex(&fidp->mx);
6126 osi_Log0(smb_logp, " No user specified. Not closing fid");
6127 return CM_ERROR_BADFD;
6130 userp = fidp->userp; /* no hold required since fidp is held
6131 throughout the function */
6132 lock_ReleaseMutex(&fidp->mx);
6137 lock_ObtainWrite(&smb_rctLock);
6139 osi_Log0(smb_logp, " Fid already closed.");
6140 lock_ReleaseWrite(&smb_rctLock);
6141 return CM_ERROR_BADFD;
6144 lock_ReleaseWrite(&smb_rctLock);
6146 lock_ObtainMutex(&fidp->mx);
6147 if (fidp->NTopen_dscp) {
6148 dscp = fidp->NTopen_dscp;
6149 cm_HoldSCache(dscp);
6152 if (fidp->NTopen_pathp) {
6153 pathp = strdup(fidp->NTopen_pathp);
6161 /* Don't jump the gun on an async raw write */
6162 while (fidp->raw_writers) {
6163 lock_ReleaseMutex(&fidp->mx);
6164 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6165 lock_ObtainMutex(&fidp->mx);
6168 /* watch for ioctl closes, and read-only opens */
6170 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6171 == SMB_FID_OPENWRITE) {
6172 if (dosTime != 0 && dosTime != -1) {
6173 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6174 /* This fixes defect 10958 */
6175 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6176 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
6178 if (smb_AsyncStore != 2) {
6179 lock_ReleaseMutex(&fidp->mx);
6180 code = cm_FSync(scp, userp, &req);
6181 lock_ObtainMutex(&fidp->mx);
6187 /* unlock any pending locks */
6188 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6189 scp->fileType == CM_SCACHETYPE_FILE) {
6193 lock_ReleaseMutex(&fidp->mx);
6195 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6197 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6198 lock_ObtainWrite(&scp->rw);
6200 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6201 CM_SCACHESYNC_NEEDCALLBACK
6202 | CM_SCACHESYNC_GETSTATUS
6203 | CM_SCACHESYNC_LOCK);
6207 "smb CoreClose SyncOp failure code 0x%x", tcode);
6208 goto post_syncopdone;
6211 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6213 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6217 lock_ReleaseWrite(&scp->rw);
6218 lock_ObtainMutex(&fidp->mx);
6221 if (fidp->flags & SMB_FID_DELONCLOSE) {
6224 lock_ReleaseMutex(&fidp->mx);
6226 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6231 smb_FullName(dscp, delscp, pathp, &fullPathp, userp, &req);
6232 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6233 code = cm_RemoveDir(dscp, fullPathp, userp, &req);
6236 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6237 smb_NotifyChange(FILE_ACTION_REMOVED,
6238 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6239 dscp, fullPathp, NULL, TRUE);
6242 code = cm_Unlink(dscp, fullPathp, userp, &req);
6245 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6246 smb_NotifyChange(FILE_ACTION_REMOVED,
6247 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6248 dscp, fullPathp, NULL, TRUE);
6252 lock_ObtainMutex(&fidp->mx);
6253 fidp->flags &= ~SMB_FID_DELONCLOSE;
6256 /* if this was a newly created file, then clear the creator
6257 * in the stat cache entry. */
6258 if (fidp->flags & SMB_FID_CREATED) {
6260 fidp->flags &= ~SMB_FID_CREATED;
6263 if (fidp->flags & SMB_FID_NTOPEN) {
6264 cm_ReleaseSCache(fidp->NTopen_dscp);
6265 fidp->NTopen_dscp = NULL;
6266 free(fidp->NTopen_pathp);
6267 fidp->NTopen_pathp = NULL;
6268 fidp->flags &= ~SMB_FID_NTOPEN;
6270 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6271 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6274 if (fidp->NTopen_wholepathp) {
6275 free(fidp->NTopen_wholepathp);
6276 fidp->NTopen_wholepathp = NULL;
6280 cm_ReleaseSCache(fidp->scp);
6283 lock_ReleaseMutex(&fidp->mx);
6286 cm_ReleaseSCache(dscp);
6290 lock_ObtainWrite(&delscp->rw);
6292 delscp->flags |= CM_SCACHEFLAG_DELETED;
6293 lock_ReleaseWrite(&delscp->rw);
6295 cm_ReleaseSCache(delscp);
6299 lock_ObtainWrite(&scp->rw);
6300 if (nullcreator && scp->creator == userp)
6301 scp->creator = NULL;
6302 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6303 lock_ReleaseWrite(&scp->rw);
6304 cm_ReleaseSCache(scp);
6314 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6322 fid = smb_GetSMBParm(inp, 0);
6323 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6325 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6327 fid = smb_ChainFID(fid, inp);
6328 fidp = smb_FindFID(vcp, fid, 0);
6330 return CM_ERROR_BADFD;
6333 userp = smb_GetUserFromVCP(vcp, inp);
6335 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6337 smb_ReleaseFID(fidp);
6338 cm_ReleaseUser(userp);
6343 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6345 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6346 cm_user_t *userp, long *readp)
6352 osi_hyper_t fileLength;
6354 osi_hyper_t lastByte;
6355 osi_hyper_t bufferOffset;
6359 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6362 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6363 fidp->fid, offsetp->LowPart, count);
6367 lock_ObtainMutex(&fidp->mx);
6368 /* make sure we have a readable FD */
6369 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6370 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6371 fidp->fid, fidp->flags);
6372 lock_ReleaseMutex(&fidp->mx);
6373 code = CM_ERROR_BADFDOP;
6384 lock_ObtainWrite(&scp->rw);
6386 if (offset.HighPart == 0) {
6387 chunk = offset.LowPart >> cm_logChunkSize;
6388 if (chunk != fidp->curr_chunk) {
6389 fidp->prev_chunk = fidp->curr_chunk;
6390 fidp->curr_chunk = chunk;
6392 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6395 lock_ReleaseMutex(&fidp->mx);
6397 /* start by looking up the file's end */
6398 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6399 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6403 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6405 /* now we have the entry locked, look up the length */
6406 fileLength = scp->length;
6408 /* adjust count down so that it won't go past EOF */
6409 thyper.LowPart = count;
6410 thyper.HighPart = 0;
6411 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6413 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6414 /* we'd read past EOF, so just stop at fileLength bytes.
6415 * Start by computing how many bytes remain in the file.
6417 thyper = LargeIntegerSubtract(fileLength, offset);
6419 /* if we are past EOF, read 0 bytes */
6420 if (LargeIntegerLessThanZero(thyper))
6423 count = thyper.LowPart;
6428 /* now, copy the data one buffer at a time,
6429 * until we've filled the request packet
6432 /* if we've copied all the data requested, we're done */
6433 if (count <= 0) break;
6435 /* otherwise, load up a buffer of data */
6436 thyper.HighPart = offset.HighPart;
6437 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6438 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6441 buf_Release(bufferp);
6444 lock_ReleaseWrite(&scp->rw);
6446 code = buf_Get(scp, &thyper, &bufferp);
6448 lock_ObtainWrite(&scp->rw);
6449 if (code) goto done;
6450 bufferOffset = thyper;
6452 /* now get the data in the cache */
6454 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6455 CM_SCACHESYNC_NEEDCALLBACK |
6456 CM_SCACHESYNC_READ);
6460 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6462 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6464 /* otherwise, load the buffer and try again */
6465 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6469 buf_Release(bufferp);
6473 } /* if (wrong buffer) ... */
6475 /* now we have the right buffer loaded. Copy out the
6476 * data from here to the user's buffer.
6478 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6480 /* and figure out how many bytes we want from this buffer */
6481 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6482 if (nbytes > count) nbytes = count; /* don't go past EOF */
6484 /* now copy the data */
6485 memcpy(op, bufferp->datap + bufIndex, nbytes);
6487 /* adjust counters, pointers, etc. */
6490 thyper.LowPart = nbytes;
6491 thyper.HighPart = 0;
6492 offset = LargeIntegerAdd(thyper, offset);
6496 lock_ReleaseWrite(&scp->rw);
6498 buf_Release(bufferp);
6500 if (code == 0 && sequential)
6501 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6503 cm_ReleaseSCache(scp);
6506 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
6507 fidp->fid, code, *readp);
6512 * smb_WriteData -- common code for Write and Raw Write
6514 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6515 cm_user_t *userp, long *writtenp)
6517 osi_hyper_t offset = *offsetp;
6520 cm_scache_t *scp = NULL;
6521 osi_hyper_t fileLength; /* file's length at start of write */
6522 osi_hyper_t minLength; /* don't read past this */
6523 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6524 cm_buf_t *bufferp = NULL;
6525 osi_hyper_t thyper; /* hyper tmp variable */
6526 osi_hyper_t bufferOffset;
6527 afs_uint32 bufIndex; /* index in buffer where our data is */
6528 int doWriteBack = 0;
6529 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
6533 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6534 fidp->fid, offsetp->LowPart, count);
6538 lock_ObtainMutex(&fidp->mx);
6539 /* make sure we have a writable FD */
6540 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6541 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6542 fidp->fid, fidp->flags);
6543 lock_ReleaseMutex(&fidp->mx);
6544 code = CM_ERROR_BADFDOP;
6552 lock_ReleaseMutex(&fidp->mx);
6554 lock_ObtainWrite(&scp->rw);
6555 /* start by looking up the file's end */
6556 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6557 CM_SCACHESYNC_NEEDCALLBACK
6558 | CM_SCACHESYNC_SETSTATUS
6559 | CM_SCACHESYNC_GETSTATUS);
6563 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6565 /* now we have the entry locked, look up the length */
6566 fileLength = scp->length;
6567 minLength = fileLength;
6568 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6569 minLength = scp->serverLength;
6571 /* adjust file length if we extend past EOF */
6572 thyper.LowPart = count;
6573 thyper.HighPart = 0;
6574 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6575 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6576 /* we'd write past EOF, so extend the file */
6577 scp->mask |= CM_SCACHEMASK_LENGTH;
6578 scp->length = thyper;
6579 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6581 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6583 /* now, if the new position (thyper) and the old (offset) are in
6584 * different storeback windows, remember to store back the previous
6585 * storeback window when we're done with the write.
6587 * the purpose of this logic is to slow down the CIFS client
6588 * in order to avoid the client disconnecting during the CLOSE
6589 * operation if there are too many dirty buffers left to write
6590 * than can be accomplished during 45 seconds. This used to be
6591 * based upon cm_chunkSize but we desire cm_chunkSize to be large
6592 * so that we can read larger amounts of data at a time.
6594 if (smb_AsyncStore == 1 &&
6595 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
6596 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
6597 /* they're different */
6599 writeBackOffset.HighPart = offset.HighPart;
6600 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
6605 /* now, copy the data one buffer at a time, until we've filled the
6608 /* if we've copied all the data requested, we're done */
6612 /* handle over quota or out of space */
6613 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6614 *writtenp = written;
6615 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6619 /* otherwise, load up a buffer of data */
6620 thyper.HighPart = offset.HighPart;
6621 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6622 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6625 lock_ReleaseMutex(&bufferp->mx);
6626 buf_Release(bufferp);
6629 lock_ReleaseWrite(&scp->rw);
6631 code = buf_Get(scp, &thyper, &bufferp);
6633 lock_ObtainMutex(&bufferp->mx);
6634 lock_ObtainWrite(&scp->rw);
6635 if (code) goto done;
6637 bufferOffset = thyper;
6639 /* now get the data in the cache */
6641 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6642 CM_SCACHESYNC_NEEDCALLBACK
6643 | CM_SCACHESYNC_WRITE
6644 | CM_SCACHESYNC_BUFLOCKED);
6648 cm_SyncOpDone(scp, bufferp,
6649 CM_SCACHESYNC_NEEDCALLBACK
6650 | CM_SCACHESYNC_WRITE
6651 | CM_SCACHESYNC_BUFLOCKED);
6653 /* If we're overwriting the entire buffer, or
6654 * if we're writing at or past EOF, mark the
6655 * buffer as current so we don't call
6656 * cm_GetBuffer. This skips the fetch from the
6657 * server in those cases where we're going to
6658 * obliterate all the data in the buffer anyway,
6659 * or in those cases where there is no useful
6660 * data at the server to start with.
6662 * Use minLength instead of scp->length, since
6663 * the latter has already been updated by this
6666 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6667 || LargeIntegerEqualTo(offset, bufferp->offset)
6668 && (count >= cm_data.buf_blockSize
6669 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6670 ConvertLongToLargeInteger(count)),
6672 if (count < cm_data.buf_blockSize
6673 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
6674 memset(bufferp->datap, 0,
6675 cm_data.buf_blockSize);
6676 bufferp->dataVersion = scp->dataVersion;
6679 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6681 /* otherwise, load the buffer and try again */
6682 lock_ReleaseMutex(&bufferp->mx);
6683 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6685 lock_ReleaseWrite(&scp->rw);
6686 lock_ObtainMutex(&bufferp->mx);
6687 lock_ObtainWrite(&scp->rw);
6691 lock_ReleaseMutex(&bufferp->mx);
6692 buf_Release(bufferp);
6696 } /* if (wrong buffer) ... */
6698 /* now we have the right buffer loaded. Copy out the
6699 * data from here to the user's buffer.
6701 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6703 /* and figure out how many bytes we want from this buffer */
6704 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6706 nbytes = count; /* don't go past end of request */
6708 /* now copy the data */
6709 memcpy(bufferp->datap + bufIndex, op, nbytes);
6710 buf_SetDirty(bufferp, bufIndex, nbytes);
6712 /* and record the last writer */
6713 if (bufferp->userp != userp) {
6716 cm_ReleaseUser(bufferp->userp);
6717 bufferp->userp = userp;
6720 /* adjust counters, pointers, etc. */
6724 thyper.LowPart = nbytes;
6725 thyper.HighPart = 0;
6726 offset = LargeIntegerAdd(thyper, offset);
6730 lock_ReleaseWrite(&scp->rw);
6733 lock_ReleaseMutex(&bufferp->mx);
6734 buf_Release(bufferp);
6737 lock_ObtainMutex(&fidp->mx);
6738 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6739 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6740 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6741 fidp->NTopen_dscp, fidp->NTopen_pathp,
6744 lock_ReleaseMutex(&fidp->mx);
6747 if (smb_AsyncStore > 0) {
6751 lock_ObtainWrite(&scp->rw);
6752 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6754 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6755 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6757 lock_ReleaseWrite(&scp->rw);
6758 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6759 writeBackOffset.HighPart,
6760 smb_AsyncStoreSize, 0, userp);
6761 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6764 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
6768 cm_ReleaseSCache(scp);
6771 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6772 fidp->fid, code, *writtenp);
6777 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6780 unsigned short count;
6782 unsigned short hint;
6783 long written = 0, total_written = 0;
6786 smb_t* smbp = (smb_t*) inp;
6789 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6791 int inDataBlockCount;
6793 fd = smb_GetSMBParm(inp, 0);
6794 count = smb_GetSMBParm(inp, 1);
6795 offset.HighPart = 0; /* too bad */
6796 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6797 hint = smb_GetSMBParm(inp, 4);
6799 op = smb_GetSMBData(inp, NULL);
6800 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6802 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6803 fd, offset.LowPart, count);
6805 fd = smb_ChainFID(fd, inp);
6806 fidp = smb_FindFID(vcp, fd, 0);
6808 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6809 return CM_ERROR_BADFD;
6812 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6813 smb_CloseFID(vcp, fidp, NULL, 0);
6814 smb_ReleaseFID(fidp);
6815 return CM_ERROR_NOSUCHFILE;
6818 lock_ObtainMutex(&fidp->mx);
6819 if (fidp->flags & SMB_FID_IOCTL) {
6820 lock_ReleaseMutex(&fidp->mx);
6821 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6822 smb_ReleaseFID(fidp);
6823 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6826 lock_ReleaseMutex(&fidp->mx);
6827 userp = smb_GetUserFromVCP(vcp, inp);
6831 LARGE_INTEGER LOffset;
6832 LARGE_INTEGER LLength;
6835 key = cm_GenerateKey(vcp->vcID, pid, fd);
6837 LOffset.HighPart = offset.HighPart;
6838 LOffset.LowPart = offset.LowPart;
6839 LLength.HighPart = 0;
6840 LLength.LowPart = count;
6842 lock_ObtainWrite(&fidp->scp->rw);
6843 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6844 lock_ReleaseWrite(&fidp->scp->rw);
6847 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6852 /* special case: 0 bytes transferred means truncate to this position */
6856 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6860 truncAttr.mask = CM_ATTRMASK_LENGTH;
6861 truncAttr.length.LowPart = offset.LowPart;
6862 truncAttr.length.HighPart = 0;
6863 lock_ObtainMutex(&fidp->mx);
6864 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6865 fidp->flags |= SMB_FID_LENGTHSETDONE;
6866 lock_ReleaseMutex(&fidp->mx);
6867 smb_SetSMBParm(outp, 0, 0 /* count */);
6868 smb_SetSMBDataLength(outp, 0);
6873 * Work around bug in NT client
6875 * When copying a file, the NT client should first copy the data,
6876 * then copy the last write time. But sometimes the NT client does
6877 * these in the wrong order, so the data copies would inadvertently
6878 * cause the last write time to be overwritten. We try to detect this,
6879 * and don't set client mod time if we think that would go against the
6882 lock_ObtainMutex(&fidp->mx);
6883 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6884 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6885 fidp->scp->clientModTime = time(NULL);
6887 lock_ReleaseMutex(&fidp->mx);
6890 while ( code == 0 && count > 0 ) {
6891 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6892 if (code == 0 && written == 0)
6893 code = CM_ERROR_PARTIALWRITE;
6895 offset = LargeIntegerAdd(offset,
6896 ConvertLongToLargeInteger(written));
6897 count -= (unsigned short)written;
6898 total_written += written;
6902 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6903 total_written, code);
6905 /* set the packet data length to 3 bytes for the data block header,
6906 * plus the size of the data.
6908 smb_SetSMBParm(outp, 0, total_written);
6909 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6910 smb_SetSMBParm(outp, 3, hint);
6911 smb_SetSMBDataLength(outp, 0);
6914 smb_ReleaseFID(fidp);
6915 cm_ReleaseUser(userp);
6920 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6921 NCB *ncbp, raw_write_cont_t *rwcp)
6930 fd = smb_GetSMBParm(inp, 0);
6931 fidp = smb_FindFID(vcp, fd, 0);
6933 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6934 smb_CloseFID(vcp, fidp, NULL, 0);
6935 smb_ReleaseFID(fidp);
6939 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
6940 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
6942 userp = smb_GetUserFromVCP(vcp, inp);
6945 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
6947 if (rwcp->writeMode & 0x1) { /* synchronous */
6950 smb_FormatResponsePacket(vcp, inp, outp);
6951 op = (smb_t *) outp;
6952 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
6953 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
6954 smb_SetSMBDataLength(outp, 0);
6955 smb_SendPacket(vcp, outp);
6956 smb_FreePacket(outp);
6958 else { /* asynchronous */
6959 lock_ObtainMutex(&fidp->mx);
6960 fidp->raw_writers--;
6961 if (fidp->raw_writers == 0)
6962 thrd_SetEvent(fidp->raw_write_event);
6963 lock_ReleaseMutex(&fidp->mx);
6966 /* Give back raw buffer */
6967 lock_ObtainMutex(&smb_RawBufLock);
6968 *((char **)rawBuf) = smb_RawBufs;
6969 smb_RawBufs = rawBuf;
6970 lock_ReleaseMutex(&smb_RawBufLock);
6972 smb_ReleaseFID(fidp);
6973 cm_ReleaseUser(userp);
6976 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6981 /* SMB_COM_WRITE_RAW */
6982 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
6985 long count, written = 0, total_written = 0;
6989 smb_t *smbp = (smb_t*) inp;
6993 unsigned short writeMode;
6995 fd = smb_GetSMBParm(inp, 0);
6996 totalCount = smb_GetSMBParm(inp, 1);
6997 count = smb_GetSMBParm(inp, 10);
6998 writeMode = smb_GetSMBParm(inp, 7);
7000 op = (char *) inp->data;
7001 op += smb_GetSMBParm(inp, 11);
7003 offset.HighPart = 0;
7004 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7006 if (*inp->wctp == 14) {
7007 /* we received a 64-bit file offset */
7008 #ifdef AFS_LARGEFILES
7009 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7011 if (LargeIntegerLessThanZero(offset)) {
7013 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7014 offset.HighPart, offset.LowPart);
7015 return CM_ERROR_BADSMB;
7018 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7020 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7021 return CM_ERROR_BADSMB;
7024 offset.HighPart = 0;
7027 offset.HighPart = 0; /* 32-bit file offset */
7031 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7032 fd, offset.HighPart, offset.LowPart, count);
7034 " WriteRaw WriteMode 0x%x",
7037 fd = smb_ChainFID(fd, inp);
7038 fidp = smb_FindFID(vcp, fd, 0);
7040 return CM_ERROR_BADFD;
7043 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7044 smb_CloseFID(vcp, fidp, NULL, 0);
7045 smb_ReleaseFID(fidp);
7046 return CM_ERROR_NOSUCHFILE;
7052 LARGE_INTEGER LOffset;
7053 LARGE_INTEGER LLength;
7056 key = cm_GenerateKey(vcp->vcID, pid, fd);
7058 LOffset.HighPart = offset.HighPart;
7059 LOffset.LowPart = offset.LowPart;
7060 LLength.HighPart = 0;
7061 LLength.LowPart = count;
7063 lock_ObtainWrite(&fidp->scp->rw);
7064 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7065 lock_ReleaseWrite(&fidp->scp->rw);
7068 smb_ReleaseFID(fidp);
7073 userp = smb_GetUserFromVCP(vcp, inp);
7076 * Work around bug in NT client
7078 * When copying a file, the NT client should first copy the data,
7079 * then copy the last write time. But sometimes the NT client does
7080 * these in the wrong order, so the data copies would inadvertently
7081 * cause the last write time to be overwritten. We try to detect this,
7082 * and don't set client mod time if we think that would go against the
7085 lock_ObtainMutex(&fidp->mx);
7086 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7087 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7088 fidp->scp->clientModTime = time(NULL);
7090 lock_ReleaseMutex(&fidp->mx);
7093 while ( code == 0 && count > 0 ) {
7094 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7095 if (code == 0 && written == 0)
7096 code = CM_ERROR_PARTIALWRITE;
7098 offset = LargeIntegerAdd(offset,
7099 ConvertLongToLargeInteger(written));
7102 total_written += written;
7106 /* Get a raw buffer */
7109 lock_ObtainMutex(&smb_RawBufLock);
7111 /* Get a raw buf, from head of list */
7112 rawBuf = smb_RawBufs;
7113 smb_RawBufs = *(char **)smb_RawBufs;
7116 code = CM_ERROR_USESTD;
7118 lock_ReleaseMutex(&smb_RawBufLock);
7121 /* Don't allow a premature Close */
7122 if (code == 0 && (writeMode & 1) == 0) {
7123 lock_ObtainMutex(&fidp->mx);
7124 fidp->raw_writers++;
7125 thrd_ResetEvent(fidp->raw_write_event);
7126 lock_ReleaseMutex(&fidp->mx);
7129 smb_ReleaseFID(fidp);
7130 cm_ReleaseUser(userp);
7133 smb_SetSMBParm(outp, 0, total_written);
7134 smb_SetSMBDataLength(outp, 0);
7135 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7140 offset = LargeIntegerAdd(offset,
7141 ConvertLongToLargeInteger(count));
7145 rwcp->offset.HighPart = offset.HighPart;
7146 rwcp->offset.LowPart = offset.LowPart;
7147 rwcp->count = totalCount - count;
7148 rwcp->writeMode = writeMode;
7149 rwcp->alreadyWritten = total_written;
7151 /* set the packet data length to 3 bytes for the data block header,
7152 * plus the size of the data.
7154 smb_SetSMBParm(outp, 0, 0xffff);
7155 smb_SetSMBDataLength(outp, 0);
7161 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7164 long count, finalCount;
7168 smb_t *smbp = (smb_t*) inp;
7173 fd = smb_GetSMBParm(inp, 0);
7174 count = smb_GetSMBParm(inp, 1);
7175 offset.HighPart = 0; /* too bad */
7176 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7178 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7179 fd, offset.LowPart, count);
7181 fd = smb_ChainFID(fd, inp);
7182 fidp = smb_FindFID(vcp, fd, 0);
7184 return CM_ERROR_BADFD;
7186 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7187 smb_CloseFID(vcp, fidp, NULL, 0);
7188 smb_ReleaseFID(fidp);
7189 return CM_ERROR_NOSUCHFILE;
7192 lock_ObtainMutex(&fidp->mx);
7193 if (fidp->flags & SMB_FID_IOCTL) {
7194 lock_ReleaseMutex(&fidp->mx);
7195 code = smb_IoctlRead(fidp, vcp, inp, outp);
7196 smb_ReleaseFID(fidp);
7199 lock_ReleaseMutex(&fidp->mx);
7202 LARGE_INTEGER LOffset, LLength;
7206 key = cm_GenerateKey(vcp->vcID, pid, fd);
7208 LOffset.HighPart = 0;
7209 LOffset.LowPart = offset.LowPart;
7210 LLength.HighPart = 0;
7211 LLength.LowPart = count;
7213 lock_ObtainWrite(&fidp->scp->rw);
7214 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
7215 lock_ReleaseWrite(&fidp->scp->rw);
7218 smb_ReleaseFID(fidp);
7222 userp = smb_GetUserFromVCP(vcp, inp);
7224 /* remember this for final results */
7225 smb_SetSMBParm(outp, 0, count);
7226 smb_SetSMBParm(outp, 1, 0);
7227 smb_SetSMBParm(outp, 2, 0);
7228 smb_SetSMBParm(outp, 3, 0);
7229 smb_SetSMBParm(outp, 4, 0);
7231 /* set the packet data length to 3 bytes for the data block header,
7232 * plus the size of the data.
7234 smb_SetSMBDataLength(outp, count+3);
7236 /* get op ptr after putting in the parms, since otherwise we don't
7237 * know where the data really is.
7239 op = smb_GetSMBData(outp, NULL);
7241 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7242 *op++ = 1; /* data block marker */
7243 *op++ = (unsigned char) (count & 0xff);
7244 *op++ = (unsigned char) ((count >> 8) & 0xff);
7246 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7248 /* fix some things up */
7249 smb_SetSMBParm(outp, 0, finalCount);
7250 smb_SetSMBDataLength(outp, finalCount+3);
7252 smb_ReleaseFID(fidp);
7254 cm_ReleaseUser(userp);
7258 /* SMB_COM_CREATE_DIRECTORY */
7259 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7266 cm_scache_t *dscp; /* dir we're dealing with */
7267 cm_scache_t *scp; /* file we're creating */
7269 int initialModeBits;
7279 /* compute initial mode bits based on read-only flag in attributes */
7280 initialModeBits = 0777;
7282 tp = smb_GetSMBData(inp, NULL);
7283 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7285 if (strcmp(pathp, "\\") == 0)
7286 return CM_ERROR_EXISTS;
7288 spacep = inp->spacep;
7289 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7291 userp = smb_GetUserFromVCP(vcp, inp);
7293 caseFold = CM_FLAG_CASEFOLD;
7295 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7297 cm_ReleaseUser(userp);
7298 return CM_ERROR_NOSUCHPATH;
7301 code = cm_NameI(cm_data.rootSCachep, spacep->data,
7302 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7303 userp, tidPathp, &req, &dscp);
7306 cm_ReleaseUser(userp);
7311 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7312 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7313 cm_ReleaseSCache(dscp);
7314 cm_ReleaseUser(userp);
7315 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7316 return CM_ERROR_PATH_NOT_COVERED;
7318 return CM_ERROR_BADSHARENAME;
7320 #endif /* DFS_SUPPORT */
7322 /* otherwise, scp points to the parent directory. Do a lookup, and
7323 * fail if we find it. Otherwise, we do the create.
7329 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7330 if (scp) cm_ReleaseSCache(scp);
7331 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7332 if (code == 0) code = CM_ERROR_EXISTS;
7333 cm_ReleaseSCache(dscp);
7334 cm_ReleaseUser(userp);
7338 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7339 setAttr.clientModTime = time(NULL);
7340 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
7341 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7342 smb_NotifyChange(FILE_ACTION_ADDED,
7343 FILE_NOTIFY_CHANGE_DIR_NAME,
7344 dscp, lastNamep, NULL, TRUE);
7346 /* we don't need this any longer */
7347 cm_ReleaseSCache(dscp);
7350 /* something went wrong creating or truncating the file */
7351 cm_ReleaseUser(userp);
7355 /* otherwise we succeeded */
7356 smb_SetSMBDataLength(outp, 0);
7357 cm_ReleaseUser(userp);
7362 BOOL smb_IsLegalFilename(char *filename)
7365 * Find the longest substring of filename that does not contain
7366 * any of the chars in illegalChars. If that substring is less
7367 * than the length of the whole string, then one or more of the
7368 * illegal chars is in filename.
7370 if (strcspn(filename, illegalChars) < strlen(filename))
7376 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
7377 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7385 cm_scache_t *dscp; /* dir we're dealing with */
7386 cm_scache_t *scp; /* file we're creating */
7388 int initialModeBits;
7396 int created = 0; /* the file was new */
7401 excl = (inp->inCom == 0x03)? 0 : 1;
7403 attributes = smb_GetSMBParm(inp, 0);
7404 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7406 /* compute initial mode bits based on read-only flag in attributes */
7407 initialModeBits = 0666;
7408 if (attributes & SMB_ATTR_READONLY)
7409 initialModeBits &= ~0222;
7411 tp = smb_GetSMBData(inp, NULL);
7412 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7414 spacep = inp->spacep;
7415 smb_StripLastComponent(spacep->data, &lastNamep, pathp);
7417 userp = smb_GetUserFromVCP(vcp, inp);
7419 caseFold = CM_FLAG_CASEFOLD;
7421 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7423 cm_ReleaseUser(userp);
7424 return CM_ERROR_NOSUCHPATH;
7426 code = cm_NameI(cm_data.rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
7427 userp, tidPathp, &req, &dscp);
7430 cm_ReleaseUser(userp);
7435 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7436 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->data);
7437 cm_ReleaseSCache(dscp);
7438 cm_ReleaseUser(userp);
7439 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7440 return CM_ERROR_PATH_NOT_COVERED;
7442 return CM_ERROR_BADSHARENAME;
7444 #endif /* DFS_SUPPORT */
7446 /* otherwise, scp points to the parent directory. Do a lookup, and
7447 * truncate the file if we find it, otherwise we create the file.
7454 if (!smb_IsLegalFilename(lastNamep))
7455 return CM_ERROR_BADNTFILENAME;
7457 osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
7458 #ifdef DEBUG_VERBOSE
7461 hexp = osi_HexifyString( lastNamep );
7462 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7467 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7468 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7469 cm_ReleaseSCache(dscp);
7470 cm_ReleaseUser(userp);
7474 /* if we get here, if code is 0, the file exists and is represented by
7475 * scp. Otherwise, we have to create it.
7479 /* oops, file shouldn't be there */
7480 cm_ReleaseSCache(dscp);
7481 cm_ReleaseSCache(scp);
7482 cm_ReleaseUser(userp);
7483 return CM_ERROR_EXISTS;
7486 setAttr.mask = CM_ATTRMASK_LENGTH;
7487 setAttr.length.LowPart = 0;
7488 setAttr.length.HighPart = 0;
7489 code = cm_SetAttr(scp, &setAttr, userp, &req);
7492 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7493 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7494 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7498 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7499 smb_NotifyChange(FILE_ACTION_ADDED,
7500 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7501 dscp, lastNamep, NULL, TRUE);
7502 } else if (!excl && code == CM_ERROR_EXISTS) {
7503 /* not an exclusive create, and someone else tried
7504 * creating it already, then we open it anyway. We
7505 * don't bother retrying after this, since if this next
7506 * fails, that means that the file was deleted after
7507 * we started this call.
7509 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7512 setAttr.mask = CM_ATTRMASK_LENGTH;
7513 setAttr.length.LowPart = 0;
7514 setAttr.length.HighPart = 0;
7515 code = cm_SetAttr(scp, &setAttr, userp, &req);
7520 /* we don't need this any longer */
7521 cm_ReleaseSCache(dscp);
7524 /* something went wrong creating or truncating the file */
7525 if (scp) cm_ReleaseSCache(scp);
7526 cm_ReleaseUser(userp);
7530 /* make sure we only open files */
7531 if (scp->fileType != CM_SCACHETYPE_FILE) {
7532 cm_ReleaseSCache(scp);
7533 cm_ReleaseUser(userp);
7534 return CM_ERROR_ISDIR;
7537 /* now all we have to do is open the file itself */
7538 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7539 osi_assertx(fidp, "null smb_fid_t");
7543 lock_ObtainMutex(&fidp->mx);
7544 /* always create it open for read/write */
7545 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7547 /* remember that the file was newly created */
7549 fidp->flags |= SMB_FID_CREATED;
7551 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7553 /* save a pointer to the vnode */
7555 lock_ObtainWrite(&scp->rw);
7556 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7557 lock_ReleaseWrite(&scp->rw);
7560 fidp->userp = userp;
7561 lock_ReleaseMutex(&fidp->mx);
7563 smb_SetSMBParm(outp, 0, fidp->fid);
7564 smb_SetSMBDataLength(outp, 0);
7566 cm_Open(scp, 0, userp);
7568 smb_ReleaseFID(fidp);
7569 cm_ReleaseUser(userp);
7570 /* leave scp held since we put it in fidp->scp */
7575 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7578 osi_hyper_t new_offset;
7589 fd = smb_GetSMBParm(inp, 0);
7590 whence = smb_GetSMBParm(inp, 1);
7591 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7593 /* try to find the file descriptor */
7594 fd = smb_ChainFID(fd, inp);
7595 fidp = smb_FindFID(vcp, fd, 0);
7597 return CM_ERROR_BADFD;
7599 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7600 smb_CloseFID(vcp, fidp, NULL, 0);
7601 smb_ReleaseFID(fidp);
7602 return CM_ERROR_NOSUCHFILE;
7605 lock_ObtainMutex(&fidp->mx);
7606 if (fidp->flags & SMB_FID_IOCTL) {
7607 lock_ReleaseMutex(&fidp->mx);
7608 smb_ReleaseFID(fidp);
7609 return CM_ERROR_BADFD;
7611 lock_ReleaseMutex(&fidp->mx);
7613 userp = smb_GetUserFromVCP(vcp, inp);
7615 lock_ObtainMutex(&fidp->mx);
7618 lock_ReleaseMutex(&fidp->mx);
7619 lock_ObtainWrite(&scp->rw);
7620 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7621 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7623 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7625 /* offset from current offset */
7626 new_offset = LargeIntegerAdd(fidp->offset,
7627 ConvertLongToLargeInteger(offset));
7629 else if (whence == 2) {
7630 /* offset from current EOF */
7631 new_offset = LargeIntegerAdd(scp->length,
7632 ConvertLongToLargeInteger(offset));
7634 new_offset = ConvertLongToLargeInteger(offset);
7637 fidp->offset = new_offset;
7638 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7639 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7640 smb_SetSMBDataLength(outp, 0);
7642 lock_ReleaseWrite(&scp->rw);
7643 smb_ReleaseFID(fidp);
7644 cm_ReleaseSCache(scp);
7645 cm_ReleaseUser(userp);
7649 /* dispatch all of the requests received in a packet. Due to chaining, this may
7650 * be more than one request.
7652 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7653 NCB *ncbp, raw_write_cont_t *rwcp)
7657 unsigned long code = 0;
7658 unsigned char *outWctp;
7659 int nparms; /* # of bytes of parameters */
7661 int nbytes; /* bytes of data, excluding count */
7664 unsigned short errCode;
7665 unsigned long NTStatus;
7667 unsigned char errClass;
7668 unsigned int oldGen;
7669 DWORD oldTime, newTime;
7671 /* get easy pointer to the data */
7672 smbp = (smb_t *) inp->data;
7674 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7675 /* setup the basic parms for the initial request in the packet */
7676 inp->inCom = smbp->com;
7677 inp->wctp = &smbp->wct;
7679 inp->ncb_length = ncbp->ncb_length;
7684 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7685 /* log it and discard it */
7686 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7687 __FILE__, __LINE__, ncbp->ncb_length);
7688 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7692 /* We are an ongoing op */
7693 thrd_Increment(&ongoingOps);
7695 /* set up response packet for receiving output */
7696 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7697 smb_FormatResponsePacket(vcp, inp, outp);
7698 outWctp = outp->wctp;
7700 /* Remember session generation number and time */
7701 oldGen = sessionGen;
7702 oldTime = GetTickCount();
7704 while (inp->inCom != 0xff) {
7705 dp = &smb_dispatchTable[inp->inCom];
7707 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7708 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7709 code = outp->resumeCode;
7713 /* process each request in the packet; inCom, wctp and inCount
7714 * are already set up.
7716 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7719 /* now do the dispatch */
7720 /* start by formatting the response record a little, as a default */
7721 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7723 outWctp[1] = 0xff; /* no operation */
7724 outWctp[2] = 0; /* padding */
7729 /* not a chained request, this is a more reasonable default */
7730 outWctp[0] = 0; /* wct of zero */
7731 outWctp[1] = 0; /* and bcc (word) of zero */
7735 /* once set, stays set. Doesn't matter, since we never chain
7736 * "no response" calls.
7738 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7742 /* we have a recognized operation */
7743 char * opName = myCrt_Dispatch(inp->inCom);
7745 if (inp->inCom == 0x1d)
7747 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7749 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
7750 opName,vcp,vcp->lana,vcp->lsn);
7751 code = (*(dp->procp)) (vcp, inp, outp);
7752 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",
7753 code,vcp,vcp->lana,vcp->lsn);
7755 if ( code == CM_ERROR_BADSMB ||
7756 code == CM_ERROR_BADOP )
7758 #endif /* LOG_PACKET */
7761 newTime = GetTickCount();
7762 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
7764 if (oldGen != sessionGen) {
7765 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7766 newTime - oldTime, ncbp->ncb_length);
7767 osi_Log3(smb_logp, "Request %s straddled session startup, "
7768 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
7771 FreeSMBStrings(inp);
7773 /* bad opcode, fail the request, after displaying it */
7774 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7777 #endif /* LOG_PACKET */
7780 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7781 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7782 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7783 if (code == IDCANCEL)
7786 code = CM_ERROR_BADOP;
7789 /* catastrophic failure: log as much as possible */
7790 if (code == CM_ERROR_BADSMB) {
7791 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7795 #endif /* LOG_PACKET */
7796 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7799 code = CM_ERROR_INVAL;
7802 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7803 thrd_Decrement(&ongoingOps);
7808 /* now, if we failed, turn the current response into an empty
7809 * one, and fill in the response packet's error code.
7812 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7813 smb_MapNTError(code, &NTStatus);
7814 outWctp = outp->wctp;
7815 smbp = (smb_t *) &outp->data;
7816 if (code != CM_ERROR_PARTIALWRITE
7817 && code != CM_ERROR_BUFFERTOOSMALL
7818 && code != CM_ERROR_GSSCONTINUE) {
7819 /* nuke wct and bcc. For a partial
7820 * write or an in-process authentication handshake,
7821 * assume they're OK.
7827 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7828 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7829 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7830 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7831 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7835 smb_MapCoreError(code, vcp, &errCode, &errClass);
7836 outWctp = outp->wctp;
7837 smbp = (smb_t *) &outp->data;
7838 if (code != CM_ERROR_PARTIALWRITE) {
7839 /* nuke wct and bcc. For a partial
7840 * write, assume they're OK.
7846 smbp->errLow = (unsigned char) (errCode & 0xff);
7847 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7848 smbp->rcls = errClass;
7851 } /* error occurred */
7853 /* if we're here, we've finished one request. Look to see if
7854 * this is a chained opcode. If it is, setup things to process
7855 * the chained request, and setup the output buffer to hold the
7856 * chained response. Start by finding the next input record.
7858 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7859 break; /* not a chained req */
7860 tp = inp->wctp; /* points to start of last request */
7861 /* in a chained request, the first two
7862 * parm fields are required, and are
7863 * AndXCommand/AndXReserved and
7865 if (tp[0] < 2) break;
7866 if (tp[1] == 0xff) break; /* no more chained opcodes */
7868 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7871 /* and now append the next output request to the end of this
7872 * last request. Begin by finding out where the last response
7873 * ends, since that's where we'll put our new response.
7875 outWctp = outp->wctp; /* ptr to out parameters */
7876 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7877 nparms = outWctp[0] << 1;
7878 tp = outWctp + nparms + 1; /* now points to bcc field */
7879 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7880 tp += 2 /* for the count itself */ + nbytes;
7881 /* tp now points to the new output record; go back and patch the
7882 * second parameter (off2) to point to the new record.
7884 temp = (unsigned int)(tp - outp->data);
7885 outWctp[3] = (unsigned char) (temp & 0xff);
7886 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7887 outWctp[2] = 0; /* padding */
7888 outWctp[1] = inp->inCom; /* next opcode */
7890 /* finally, setup for the next iteration */
7893 } /* while loop over all requests in the packet */
7895 /* now send the output packet, and return */
7897 smb_SendPacket(vcp, outp);
7898 thrd_Decrement(&ongoingOps);
7903 /* Wait for Netbios() calls to return, and make the results available to server
7904 * threads. Note that server threads can't wait on the NCBevents array
7905 * themselves, because NCB events are manual-reset, and the servers would race
7906 * each other to reset them.
7908 void smb_ClientWaiter(void *parmp)
7913 while (smbShutdownFlag == 0) {
7914 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7916 if (code == WAIT_OBJECT_0)
7919 /* error checking */
7920 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7922 int abandonIdx = code - WAIT_ABANDONED_0;
7923 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7926 if (code == WAIT_IO_COMPLETION)
7928 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
7932 if (code == WAIT_TIMEOUT)
7934 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
7937 if (code == WAIT_FAILED)
7939 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
7942 idx = code - WAIT_OBJECT_0;
7944 /* check idx range! */
7945 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
7947 /* this is fatal - log as much as possible */
7948 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
7949 osi_assertx(0, "invalid index");
7952 thrd_ResetEvent(NCBevents[idx]);
7953 thrd_SetEvent(NCBreturns[0][idx]);
7958 * Try to have one NCBRECV request waiting for every live session. Not more
7959 * than one, because if there is more than one, it's hard to handle Write Raw.
7961 void smb_ServerWaiter(void *parmp)
7964 int idx_session, idx_NCB;
7967 while (smbShutdownFlag == 0) {
7969 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
7971 if (code == WAIT_OBJECT_0)
7974 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
7976 int abandonIdx = code - WAIT_ABANDONED_0;
7977 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7980 if (code == WAIT_IO_COMPLETION)
7982 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
7986 if (code == WAIT_TIMEOUT)
7988 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
7991 if (code == WAIT_FAILED)
7993 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
7996 idx_session = code - WAIT_OBJECT_0;
7998 /* check idx range! */
7999 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8001 /* this is fatal - log as much as possible */
8002 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8003 osi_assertx(0, "invalid index");
8008 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8010 if (code == WAIT_OBJECT_0) {
8011 if (smbShutdownFlag == 1)
8017 /* error checking */
8018 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8020 int abandonIdx = code - WAIT_ABANDONED_0;
8021 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8024 if (code == WAIT_IO_COMPLETION)
8026 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8030 if (code == WAIT_TIMEOUT)
8032 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8035 if (code == WAIT_FAILED)
8037 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8040 idx_NCB = code - WAIT_OBJECT_0;
8042 /* check idx range! */
8043 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8045 /* this is fatal - log as much as possible */
8046 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8047 osi_assertx(0, "invalid index");
8050 /* Link them together */
8051 NCBsessions[idx_NCB] = idx_session;
8054 ncbp = NCBs[idx_NCB];
8055 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8056 ncbp->ncb_command = NCBRECV | ASYNCH;
8057 ncbp->ncb_lana_num = lanas[idx_session];
8058 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8059 ncbp->ncb_event = NCBevents[idx_NCB];
8060 ncbp->ncb_length = SMB_PACKETSIZE;
8066 * The top level loop for handling SMB request messages. Each server thread
8067 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8068 * NCB and buffer for the incoming request are loaned to us.
8070 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8071 * to immediately send a request for the rest of the data. This must come
8072 * before any other traffic for that session, so we delay setting the session
8073 * event until that data has come in.
8075 void smb_Server(VOID *parmp)
8077 INT_PTR myIdx = (INT_PTR) parmp;
8081 smb_packet_t *outbufp;
8083 int idx_NCB, idx_session;
8085 smb_vc_t *vcp = NULL;
8088 rx_StartClientThread();
8091 outbufp = GetPacket();
8092 outbufp->ncbp = outncbp;
8100 smb_ResetServerPriority();
8102 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8105 /* terminate silently if shutdown flag is set */
8106 if (code == WAIT_OBJECT_0) {
8107 if (smbShutdownFlag == 1) {
8108 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8114 /* error checking */
8115 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8117 int abandonIdx = code - WAIT_ABANDONED_0;
8118 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8121 if (code == WAIT_IO_COMPLETION)
8123 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8127 if (code == WAIT_TIMEOUT)
8129 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8132 if (code == WAIT_FAILED)
8134 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8137 idx_NCB = code - WAIT_OBJECT_0;
8139 /* check idx range! */
8140 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8142 /* this is fatal - log as much as possible */
8143 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8144 osi_assertx(0, "invalid index");
8147 ncbp = NCBs[idx_NCB];
8148 idx_session = NCBsessions[idx_NCB];
8149 rc = ncbp->ncb_retcode;
8151 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8152 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8156 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8160 /* Can this happen? Or is it just my UNIX paranoia? */
8161 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8166 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8169 /* Client closed session */
8170 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8172 lock_ObtainMutex(&vcp->mx);
8173 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8174 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8176 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8177 lock_ReleaseMutex(&vcp->mx);
8178 lock_ObtainWrite(&smb_globalLock);
8179 dead_sessions[vcp->session] = TRUE;
8180 lock_ReleaseWrite(&smb_globalLock);
8181 smb_CleanupDeadVC(vcp);
8185 lock_ReleaseMutex(&vcp->mx);
8191 /* Treat as transient error */
8192 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8195 "dispatch smb recv failed, message incomplete, ncb_length %d",
8198 "SMB message incomplete, "
8199 "length %d", ncbp->ncb_length);
8202 * We used to discard the packet.
8203 * Instead, try handling it normally.
8207 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8211 /* A weird error code. Log it, sleep, and continue. */
8212 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8214 lock_ObtainMutex(&vcp->mx);
8215 if (vcp && vcp->errorCount++ > 3) {
8216 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8217 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8218 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8220 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8221 lock_ReleaseMutex(&vcp->mx);
8222 lock_ObtainWrite(&smb_globalLock);
8223 dead_sessions[vcp->session] = TRUE;
8224 lock_ReleaseWrite(&smb_globalLock);
8225 smb_CleanupDeadVC(vcp);
8229 lock_ReleaseMutex(&vcp->mx);
8235 lock_ReleaseMutex(&vcp->mx);
8237 thrd_SetEvent(SessionEvents[idx_session]);
8242 /* Success, so now dispatch on all the data in the packet */
8244 smb_concurrentCalls++;
8245 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8246 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8249 * If at this point vcp is NULL (implies that packet was invalid)
8250 * then we are in big trouble. This means either :
8251 * a) we have the wrong NCB.
8252 * b) Netbios screwed up the call.
8253 * c) The VC was already marked dead before we were able to
8255 * Obviously this implies that
8256 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8257 * lanas[idx_session] != ncbp->ncb_lana_num )
8258 * Either way, we can't do anything with this packet.
8259 * Log, sleep and resume.
8262 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8266 ncbp->ncb_lana_num);
8268 /* Also log in the trace log. */
8269 osi_Log4(smb_logp, "Server: VCP does not exist!"
8270 "LSNs[idx_session]=[%d],"
8271 "lanas[idx_session]=[%d],"
8272 "ncbp->ncb_lsn=[%d],"
8273 "ncbp->ncb_lana_num=[%d]",
8277 ncbp->ncb_lana_num);
8279 /* thrd_Sleep(1000); Don't bother sleeping */
8280 thrd_SetEvent(SessionEvents[idx_session]);
8281 smb_concurrentCalls--;
8285 smb_SetRequestStartTime();
8287 vcp->errorCount = 0;
8288 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8289 smbp = (smb_t *)bufp->data;
8296 if (smbp->com == 0x1d) {
8297 /* Special handling for Write Raw */
8298 raw_write_cont_t rwc;
8299 EVENT_HANDLE rwevent;
8300 char eventName[MAX_PATH];
8302 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8303 if (rwc.code == 0) {
8304 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
8305 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8306 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8307 ncbp->ncb_command = NCBRECV | ASYNCH;
8308 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8309 ncbp->ncb_lana_num = vcp->lana;
8310 ncbp->ncb_buffer = rwc.buf;
8311 ncbp->ncb_length = 65535;
8312 ncbp->ncb_event = rwevent;
8314 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8315 thrd_CloseHandle(rwevent);
8317 thrd_SetEvent(SessionEvents[idx_session]);
8319 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8321 else if (smbp->com == 0xa0) {
8323 * Serialize the handling for NT Transact
8326 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8327 thrd_SetEvent(SessionEvents[idx_session]);
8329 thrd_SetEvent(SessionEvents[idx_session]);
8330 /* TODO: what else needs to be serialized? */
8331 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8335 __except( smb_ServerExceptionFilter() ) {
8339 smb_concurrentCalls--;
8342 thrd_SetEvent(NCBavails[idx_NCB]);
8349 * Exception filter for the server threads. If an exception occurs in the
8350 * dispatch routines, which is where exceptions are most common, then do a
8351 * force trace and give control to upstream exception handlers. Useful for
8354 DWORD smb_ServerExceptionFilter(void) {
8355 /* While this is not the best time to do a trace, if it succeeds, then
8356 * we have a trace (assuming tracing was enabled). Otherwise, this should
8357 * throw a second exception.
8359 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8360 afsd_ForceTrace(TRUE);
8361 buf_ForceTrace(TRUE);
8362 return EXCEPTION_CONTINUE_SEARCH;
8366 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8367 * If the number of server threads is M, and the number of live sessions is
8368 * N, then the number of NCB's in use at any time either waiting for, or
8369 * holding, received messages is M + N, so that is how many NCB's get created.
8371 void InitNCBslot(int idx)
8373 struct smb_packet *bufp;
8374 EVENT_HANDLE retHandle;
8376 char eventName[MAX_PATH];
8378 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8380 NCBs[idx] = GetNCB();
8381 sprintf(eventName,"NCBavails[%d]", idx);
8382 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8383 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8384 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8385 sprintf(eventName,"NCBevents[%d]", idx);
8386 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8387 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8388 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8389 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8390 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8391 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8392 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8393 for (i=0; i<smb_NumServerThreads; i++)
8394 NCBreturns[i][idx] = retHandle;
8396 bufp->spacep = cm_GetSpace();
8400 /* listen for new connections */
8401 void smb_Listener(void *parmp)
8407 afs_uint32 session, thread;
8408 smb_vc_t *vcp = NULL;
8410 char rname[NCBNAMSZ+1];
8411 char cname[MAX_COMPUTERNAME_LENGTH+1];
8412 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8413 INT_PTR lana = (INT_PTR) parmp;
8414 char eventName[MAX_PATH];
8416 sprintf(eventName,"smb_Listener_lana_%d", (char)lana);
8417 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8418 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8419 thrd_ResetEvent(ListenerShutdown[lana]);
8423 /* retrieve computer name */
8424 GetComputerName(cname, &cnamelen);
8427 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8428 memset(ncbp, 0, sizeof(NCB));
8431 ncbp->ncb_command = NCBLISTEN;
8432 ncbp->ncb_rto = 0; /* No receive timeout */
8433 ncbp->ncb_sto = 0; /* No send timeout */
8435 /* pad out with spaces instead of null termination */
8436 len = (long)strlen(smb_localNamep);
8437 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8438 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8440 strcpy(ncbp->ncb_callname, "*");
8441 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8443 ncbp->ncb_lana_num = (UCHAR)lana;
8445 code = Netbios(ncbp);
8447 if (code == NRC_NAMERR) {
8448 /* An smb shutdown or Vista resume must have taken place */
8450 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8451 ncbp->ncb_lana_num, code);
8453 if (lock_TryMutex(&smb_StartedLock)) {
8454 lana_list.lana[i] = LANA_INVALID;
8455 lock_ReleaseMutex(&smb_StartedLock);
8458 } else if (code == NRC_BRIDGE || code != 0) {
8459 int lanaRemaining = 0;
8461 while (!lock_TryMutex(&smb_StartedLock)) {
8462 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8468 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8469 ncbp->ncb_lana_num, ncb_error_string(code));
8471 for (i = 0; i < lana_list.length; i++) {
8472 if (lana_list.lana[i] == lana) {
8473 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8474 lana_list.lana[i] = LANA_INVALID;
8476 if (lana_list.lana[i] != LANA_INVALID)
8480 if (lanaRemaining == 0) {
8481 cm_VolStatus_Network_Stopped(cm_NetbiosName
8486 smb_ListenerState = SMB_LISTENER_STOPPED;
8487 smb_LANadapter = LANA_INVALID;
8488 lana_list.length = 0;
8490 lock_ReleaseMutex(&smb_StartedLock);
8494 else if (code != 0) {
8495 char tbuffer[AFSPATHMAX];
8497 /* terminate silently if shutdown flag is set */
8498 while (!lock_TryMutex(&smb_StartedLock)) {
8499 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8505 "NCBLISTEN lana=%d failed with code %d [%s]",
8506 ncbp->ncb_lana_num, code, ncb_error_string(code));
8508 "Client exiting due to network failure. Please restart client.\n");
8511 "Client exiting due to network failure. Please restart client.\n"
8512 "NCBLISTEN lana=%d failed with code %d [%s]",
8513 ncbp->ncb_lana_num, code, ncb_error_string(code));
8515 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8516 MB_OK|MB_SERVICE_NOTIFICATION);
8517 osi_panic(tbuffer, __FILE__, __LINE__);
8519 lock_ReleaseMutex(&smb_StartedLock);
8524 /* check for remote conns */
8525 /* first get remote name and insert null terminator */
8526 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8527 for (i=NCBNAMSZ; i>0; i--) {
8528 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8534 /* compare with local name */
8536 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8537 flags |= SMB_VCFLAG_REMOTECONN;
8540 lock_ObtainMutex(&smb_ListenerLock);
8542 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8543 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8545 /* now ncbp->ncb_lsn is the connection ID */
8546 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8547 if (vcp->session == 0) {
8548 /* New generation */
8549 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8552 /* Log session startup */
8554 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8555 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8556 #endif /* NOTSERVICE */
8557 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8558 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8560 if (reportSessionStartups) {
8561 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8564 lock_ObtainMutex(&vcp->mx);
8565 strcpy(vcp->rname, rname);
8566 vcp->flags |= flags;
8567 lock_ReleaseMutex(&vcp->mx);
8569 /* Allocate slot in session arrays */
8570 /* Re-use dead session if possible, otherwise add one more */
8571 /* But don't look at session[0], it is reserved */
8572 lock_ObtainWrite(&smb_globalLock);
8573 for (session = 1; session < numSessions; session++) {
8574 if (dead_sessions[session]) {
8575 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8576 dead_sessions[session] = FALSE;
8580 lock_ReleaseWrite(&smb_globalLock);
8582 /* We are re-using an existing VC because the lsn and lana
8584 session = vcp->session;
8586 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8588 /* Log session startup */
8590 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8591 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8592 #endif /* NOTSERVICE */
8593 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8594 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8596 if (reportSessionStartups) {
8597 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8601 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8602 unsigned long code = CM_ERROR_ALLBUSY;
8603 smb_packet_t * outp = GetPacket();
8604 unsigned char *outWctp;
8607 smb_FormatResponsePacket(vcp, NULL, outp);
8610 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8611 unsigned long NTStatus;
8612 smb_MapNTError(code, &NTStatus);
8613 outWctp = outp->wctp;
8614 smbp = (smb_t *) &outp->data;
8618 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8619 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8620 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8621 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8622 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8624 unsigned short errCode;
8625 unsigned char errClass;
8626 smb_MapCoreError(code, vcp, &errCode, &errClass);
8627 outWctp = outp->wctp;
8628 smbp = (smb_t *) &outp->data;
8632 smbp->errLow = (unsigned char) (errCode & 0xff);
8633 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8634 smbp->rcls = errClass;
8637 smb_SendPacket(vcp, outp);
8638 smb_FreePacket(outp);
8640 lock_ObtainMutex(&vcp->mx);
8641 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8642 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8644 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8645 lock_ReleaseMutex(&vcp->mx);
8646 lock_ObtainWrite(&smb_globalLock);
8647 dead_sessions[vcp->session] = TRUE;
8648 lock_ReleaseWrite(&smb_globalLock);
8649 smb_CleanupDeadVC(vcp);
8651 lock_ReleaseMutex(&vcp->mx);
8654 /* assert that we do not exceed the maximum number of sessions or NCBs.
8655 * we should probably want to wait for a session to be freed in case
8658 osi_assertx(session < SESSION_MAX - 1, "invalid session");
8659 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
8661 lock_ObtainMutex(&vcp->mx);
8662 vcp->session = session;
8663 lock_ReleaseMutex(&vcp->mx);
8664 lock_ObtainWrite(&smb_globalLock);
8665 LSNs[session] = ncbp->ncb_lsn;
8666 lanas[session] = ncbp->ncb_lana_num;
8667 lock_ReleaseWrite(&smb_globalLock);
8669 if (session == numSessions) {
8670 /* Add new NCB for new session */
8671 char eventName[MAX_PATH];
8673 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8675 InitNCBslot(numNCBs);
8676 lock_ObtainWrite(&smb_globalLock);
8678 lock_ReleaseWrite(&smb_globalLock);
8679 thrd_SetEvent(NCBavails[0]);
8680 thrd_SetEvent(NCBevents[0]);
8681 for (thread = 0; thread < smb_NumServerThreads; thread++)
8682 thrd_SetEvent(NCBreturns[thread][0]);
8683 /* Also add new session event */
8684 sprintf(eventName, "SessionEvents[%d]", session);
8685 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8686 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8687 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8688 lock_ObtainWrite(&smb_globalLock);
8690 lock_ReleaseWrite(&smb_globalLock);
8691 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8692 thrd_SetEvent(SessionEvents[0]);
8694 thrd_SetEvent(SessionEvents[session]);
8700 lock_ReleaseMutex(&smb_ListenerLock);
8701 } /* dispatch while loop */
8705 thrd_SetEvent(ListenerShutdown[lana]);
8710 smb_LanAdapterChangeThread(void *param)
8713 * Give the IPAddrDaemon thread a chance
8714 * to block before we trigger.
8717 smb_LanAdapterChange(0);
8720 void smb_SetLanAdapterChangeDetected(void)
8725 lock_ObtainMutex(&smb_StartedLock);
8727 if (!powerStateSuspended) {
8728 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
8729 NULL, 0, &lpid, "smb_LanAdapterChange");
8730 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
8731 thrd_CloseHandle(phandle);
8734 smb_LanAdapterChangeDetected = 1;
8735 lock_ReleaseMutex(&smb_StartedLock);
8738 void smb_LanAdapterChange(int locked) {
8739 lana_number_t lanaNum;
8741 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
8743 LANA_ENUM temp_list;
8748 afsi_log("smb_LanAdapterChange");
8751 lock_ObtainMutex(&smb_StartedLock);
8753 smb_LanAdapterChangeDetected = 0;
8755 if (!powerStateSuspended &&
8756 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
8757 LANA_NETBIOS_NAME_FULL)) &&
8758 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
8759 if ( isGateway != bGateway ||
8760 strcmp(cm_NetbiosName, NetbiosName) ) {
8763 NCB *ncbp = GetNCB();
8764 ncbp->ncb_command = NCBENUM;
8765 ncbp->ncb_buffer = (PUCHAR)&temp_list;
8766 ncbp->ncb_length = sizeof(temp_list);
8767 code = Netbios(ncbp);
8769 if (temp_list.length != lana_list.length)
8772 for (i=0; i<lana_list.length; i++) {
8773 if ( temp_list.lana[i] != lana_list.lana[i] ) {
8785 afsi_log("Lan Adapter Change detected");
8786 smb_StopListeners(1);
8787 smb_RestartListeners(1);
8790 lock_ReleaseMutex(&smb_StartedLock);
8793 /* initialize Netbios */
8794 int smb_NetbiosInit(int locked)
8797 int i, lana, code, l;
8799 int delname_tried=0;
8802 lana_number_t lanaNum;
8805 lock_ObtainMutex(&smb_StartedLock);
8807 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
8808 smb_ListenerState != SMB_LISTENER_STOPPED) {
8811 lock_ReleaseMutex(&smb_StartedLock);
8814 /* setup the NCB system */
8817 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8818 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8819 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8821 if (smb_LANadapter != LANA_INVALID)
8822 afsi_log("LAN adapter number %d", smb_LANadapter);
8824 afsi_log("LAN adapter number not determined");
8827 afsi_log("Set for gateway service");
8829 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8831 /* something went horribly wrong. We can't proceed without a netbios name */
8833 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8834 osi_panic(buf, __FILE__, __LINE__);
8837 /* remember the name */
8838 len = (int)strlen(cm_NetbiosName);
8840 free(smb_localNamep);
8841 smb_localNamep = malloc(len+1);
8842 strcpy(smb_localNamep, cm_NetbiosName);
8843 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8846 if (smb_LANadapter == LANA_INVALID) {
8847 ncbp->ncb_command = NCBENUM;
8848 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8849 ncbp->ncb_length = sizeof(lana_list);
8850 code = Netbios(ncbp);
8852 afsi_log("Netbios NCBENUM error code %d", code);
8853 osi_panic(s, __FILE__, __LINE__);
8857 lana_list.length = 1;
8858 lana_list.lana[0] = smb_LANadapter;
8861 for (i = 0; i < lana_list.length; i++) {
8862 /* reset the adaptor: in Win32, this is required for every process, and
8863 * acts as an init call, not as a real hardware reset.
8865 ncbp->ncb_command = NCBRESET;
8866 ncbp->ncb_callname[0] = 100;
8867 ncbp->ncb_callname[2] = 100;
8868 ncbp->ncb_lana_num = lana_list.lana[i];
8869 code = Netbios(ncbp);
8871 code = ncbp->ncb_retcode;
8873 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8874 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
8876 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8880 /* and declare our name so we can receive connections */
8881 memset(ncbp, 0, sizeof(*ncbp));
8882 len=lstrlen(smb_localNamep);
8883 memset(smb_sharename,' ',NCBNAMSZ);
8884 memcpy(smb_sharename,smb_localNamep,len);
8885 afsi_log("lana_list.length %d", lana_list.length);
8887 /* Keep the name so we can unregister it later */
8888 for (l = 0; l < lana_list.length; l++) {
8889 lana = lana_list.lana[l];
8891 ncbp->ncb_command = NCBADDNAME;
8892 ncbp->ncb_lana_num = lana;
8893 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8894 code = Netbios(ncbp);
8896 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8897 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8899 char name[NCBNAMSZ+1];
8901 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8902 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8906 code = ncbp->ncb_retcode;
8909 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8912 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8913 if (code == NRC_BRIDGE) { /* invalid LANA num */
8914 lana_list.lana[l] = LANA_INVALID;
8917 else if (code == NRC_DUPNAME) {
8918 afsi_log("Name already exists; try to delete it");
8919 memset(ncbp, 0, sizeof(*ncbp));
8920 ncbp->ncb_command = NCBDELNAME;
8921 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8922 ncbp->ncb_lana_num = lana;
8923 code = Netbios(ncbp);
8925 code = ncbp->ncb_retcode;
8927 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
8929 if (code != 0 || delname_tried) {
8930 lana_list.lana[l] = LANA_INVALID;
8932 else if (code == 0) {
8933 if (!delname_tried) {
8941 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8942 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
8946 smb_LANadapter = lana;
8947 lana_found = 1; /* at least one worked */
8951 osi_assertx(lana_list.length >= 0, "empty lana list");
8953 afsi_log("No valid LANA numbers found!");
8954 lana_list.length = 0;
8955 smb_LANadapter = LANA_INVALID;
8956 smb_ListenerState = SMB_LISTENER_STOPPED;
8957 cm_VolStatus_Network_Stopped(cm_NetbiosName
8964 /* we're done with the NCB now */
8967 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
8968 if (lana_list.length > 0)
8969 osi_assert(smb_LANadapter != LANA_INVALID);
8972 lock_ReleaseMutex(&smb_StartedLock);
8974 return (lana_list.length > 0 ? 1 : 0);
8977 void smb_StartListeners(int locked)
8984 lock_ObtainMutex(&smb_StartedLock);
8986 if (smb_ListenerState == SMB_LISTENER_STARTED) {
8988 lock_ReleaseMutex(&smb_StartedLock);
8992 afsi_log("smb_StartListeners");
8993 smb_ListenerState = SMB_LISTENER_STARTED;
8994 cm_VolStatus_Network_Started(cm_NetbiosName
9000 for (i = 0; i < lana_list.length; i++) {
9001 if (lana_list.lana[i] == LANA_INVALID)
9003 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
9004 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
9005 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
9006 thrd_CloseHandle(phandle);
9009 lock_ReleaseMutex(&smb_StartedLock);
9012 void smb_RestartListeners(int locked)
9015 lock_ObtainMutex(&smb_StartedLock);
9017 if (powerStateSuspended)
9018 afsi_log("smb_RestartListeners called while suspended");
9020 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
9021 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9022 if (smb_NetbiosInit(1))
9023 smb_StartListeners(1);
9024 } else if (smb_LanAdapterChangeDetected) {
9025 smb_LanAdapterChange(1);
9029 lock_ReleaseMutex(&smb_StartedLock);
9032 void smb_StopListener(NCB *ncbp, int lana, int wait)
9036 memset(ncbp, 0, sizeof(*ncbp));
9037 ncbp->ncb_command = NCBDELNAME;
9038 ncbp->ncb_lana_num = lana;
9039 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9040 code = Netbios(ncbp);
9042 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
9043 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9045 /* and then reset the LANA; this will cause the listener threads to exit */
9046 ncbp->ncb_command = NCBRESET;
9047 ncbp->ncb_callname[0] = 100;
9048 ncbp->ncb_callname[2] = 100;
9049 ncbp->ncb_lana_num = lana;
9050 code = Netbios(ncbp);
9052 code = ncbp->ncb_retcode;
9054 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
9056 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
9060 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
9063 void smb_StopListeners(int locked)
9069 lock_ObtainMutex(&smb_StartedLock);
9071 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9073 lock_ReleaseMutex(&smb_StartedLock);
9077 afsi_log("smb_StopListeners");
9078 smb_ListenerState = SMB_LISTENER_STOPPED;
9079 cm_VolStatus_Network_Stopped(cm_NetbiosName
9087 /* Unregister the SMB name */
9088 for (l = 0; l < lana_list.length; l++) {
9089 lana = lana_list.lana[l];
9091 if (lana != LANA_INVALID) {
9092 smb_StopListener(ncbp, lana, TRUE);
9094 /* mark the adapter invalid */
9095 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9099 /* force a re-evaluation of the network adapters */
9100 lana_list.length = 0;
9101 smb_LANadapter = LANA_INVALID;
9104 lock_ReleaseMutex(&smb_StartedLock);
9107 void smb_Init(osi_log_t *logp, int useV3,
9117 EVENT_HANDLE retHandle;
9118 char eventName[MAX_PATH];
9119 int startListeners = 0;
9121 smb_TlsRequestSlot = TlsAlloc();
9123 smb_MBfunc = aMBfunc;
9127 /* Initialize smb_localZero */
9128 myTime.tm_isdst = -1; /* compute whether on DST or not */
9129 myTime.tm_year = 70;
9135 smb_localZero = mktime(&myTime);
9137 #ifndef USE_NUMERIC_TIME_CONV
9138 /* Initialize kludge-GMT */
9139 smb_CalculateNowTZ();
9140 #endif /* USE_NUMERIC_TIME_CONV */
9141 #ifdef AFS_FREELANCE_CLIENT
9142 /* Make sure the root.afs volume has the correct time */
9143 cm_noteLocalMountPointChange();
9146 /* initialize the remote debugging log */
9149 /* and the global lock */
9150 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
9151 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
9153 /* Raw I/O data structures */
9154 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
9156 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
9157 lock_InitializeMutex(&smb_StartedLock, "smb started lock");
9159 /* 4 Raw I/O buffers */
9160 smb_RawBufs = calloc(65536,1);
9161 *((char **)smb_RawBufs) = NULL;
9162 for (i=0; i<3; i++) {
9163 char *rawBuf = calloc(65536,1);
9164 *((char **)rawBuf) = smb_RawBufs;
9165 smb_RawBufs = rawBuf;
9168 /* global free lists */
9169 smb_ncbFreeListp = NULL;
9170 smb_packetFreeListp = NULL;
9172 lock_ObtainMutex(&smb_StartedLock);
9173 startListeners = smb_NetbiosInit(1);
9175 /* Initialize listener and server structures */
9177 memset(dead_sessions, 0, sizeof(dead_sessions));
9178 sprintf(eventName, "SessionEvents[0]");
9179 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9180 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9181 afsi_log("Event Object Already Exists: %s", eventName);
9183 smb_NumServerThreads = nThreads;
9184 sprintf(eventName, "NCBavails[0]");
9185 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9186 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9187 afsi_log("Event Object Already Exists: %s", eventName);
9188 sprintf(eventName, "NCBevents[0]");
9189 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9190 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9191 afsi_log("Event Object Already Exists: %s", eventName);
9192 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
9193 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
9194 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9195 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9196 afsi_log("Event Object Already Exists: %s", eventName);
9197 for (i = 0; i < smb_NumServerThreads; i++) {
9198 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
9199 NCBreturns[i][0] = retHandle;
9202 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
9203 for (i = 0; i < smb_NumServerThreads; i++) {
9204 sprintf(eventName, "smb_ServerShutdown[%d]", i);
9205 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9206 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9207 afsi_log("Event Object Already Exists: %s", eventName);
9208 InitNCBslot((int)(i+1));
9210 numNCBs = smb_NumServerThreads + 1;
9212 /* Initialize dispatch table */
9213 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
9214 /* Prepare the table for unknown operations */
9215 for(i=0; i<= SMB_NOPCODES; i++) {
9216 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
9218 /* Fill in the ones we do know */
9219 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
9220 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
9221 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
9222 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
9223 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
9224 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
9225 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
9226 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
9227 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
9228 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
9229 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
9230 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
9231 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
9232 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
9233 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
9234 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
9235 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
9236 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
9237 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
9238 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
9239 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
9240 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9241 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
9242 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
9243 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
9244 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
9245 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
9246 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
9247 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9248 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
9249 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9250 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
9251 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
9252 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
9253 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9254 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
9255 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
9256 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
9257 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
9258 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
9259 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
9260 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
9261 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9262 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
9263 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9264 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
9265 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
9266 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
9267 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
9268 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
9269 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
9270 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
9271 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
9272 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
9273 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
9274 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
9275 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
9276 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
9277 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
9278 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
9279 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
9280 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
9281 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
9282 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
9283 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
9284 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9285 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
9286 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
9287 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
9288 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
9289 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
9290 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
9291 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
9292 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
9294 /* setup tran 2 dispatch table */
9295 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
9296 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
9297 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
9298 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
9299 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
9300 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
9301 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
9302 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
9303 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
9304 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
9305 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
9306 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
9307 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
9308 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
9309 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
9310 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
9311 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
9312 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
9314 /* setup the rap dispatch table */
9315 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
9316 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
9317 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9318 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9319 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9323 /* if we are doing SMB authentication we have register outselves as a logon process */
9324 if (smb_authType != SMB_AUTH_NONE) {
9325 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9326 LSA_STRING afsProcessName;
9327 LSA_OPERATIONAL_MODE dummy; /*junk*/
9329 afsProcessName.Buffer = "OpenAFSClientDaemon";
9330 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9331 afsProcessName.MaximumLength = afsProcessName.Length + 1;
9333 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9335 if (nts == STATUS_SUCCESS) {
9336 LSA_STRING packageName;
9337 /* we are registered. Find out the security package id */
9338 packageName.Buffer = MSV1_0_PACKAGE_NAME;
9339 packageName.Length = (USHORT)strlen(packageName.Buffer);
9340 packageName.MaximumLength = packageName.Length + 1;
9341 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9342 if (nts == STATUS_SUCCESS) {
9344 * This code forces Windows to authenticate against the Logon Cache
9345 * first instead of attempting to authenticate against the Domain
9346 * Controller. When the Windows logon cache is enabled this improves
9347 * performance by removing the network access and works around a bug
9348 * seen at sites which are using a MIT Kerberos principal to login
9349 * to machines joined to a non-root domain in a multi-domain forest.
9350 * MsV1_0SetProcessOption was added in Windows XP.
9352 PVOID pResponse = NULL;
9353 ULONG cbResponse = 0;
9354 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9356 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9357 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9358 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9359 OptionsRequest.DisableOptions = FALSE;
9361 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9364 sizeof(OptionsRequest),
9370 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9371 char message[AFSPATHMAX];
9372 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9374 OutputDebugString(message);
9377 OutputDebugString("MsV1_0SetProcessOption success");
9378 afsi_log("MsV1_0SetProcessOption success");
9380 /* END - code from Larry */
9382 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9383 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9384 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9386 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9388 /* something went wrong. We report the error and revert back to no authentication
9389 because we can't perform any auth requests without a successful lsa handle
9390 or sec package id. */
9391 afsi_log("Reverting to NO SMB AUTH");
9392 smb_authType = SMB_AUTH_NONE;
9395 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9397 /* something went wrong. We report the error and revert back to no authentication
9398 because we can't perform any auth requests without a successful lsa handle
9399 or sec package id. */
9400 afsi_log("Reverting to NO SMB AUTH");
9401 smb_authType = SMB_AUTH_NONE;
9405 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9406 * time prevents the failure of authentication when logged into Windows with an
9407 * external Kerberos principal mapped to a local account.
9409 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9410 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9411 * then the only option is NTLMSSP anyway; so just fallback.
9416 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9417 if (secBlobLength == 0) {
9418 smb_authType = SMB_AUTH_NTLM;
9419 afsi_log("Reverting to SMB AUTH NTLM");
9428 /* Now get ourselves a domain name. */
9429 /* For now we are using the local computer name as the domain name.
9430 * It is actually the domain for local logins, and we are acting as
9431 * a local SMB server.
9433 bufsize = sizeof(smb_ServerDomainName) - 1;
9434 GetComputerName(smb_ServerDomainName, &bufsize);
9435 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9436 afsi_log("Setting SMB server domain name to [%s]", smb_ServerDomainName);
9439 /* Start listeners, waiters, servers, and daemons */
9441 smb_StartListeners(1);
9443 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9444 NULL, 0, &lpid, "smb_ClientWaiter");
9445 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9446 thrd_CloseHandle(phandle);
9448 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9449 NULL, 0, &lpid, "smb_ServerWaiter");
9450 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9451 thrd_CloseHandle(phandle);
9453 for (i=0; i<smb_NumServerThreads; i++) {
9454 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9455 (void *) i, 0, &lpid, "smb_Server");
9456 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9457 thrd_CloseHandle(phandle);
9460 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9461 NULL, 0, &lpid, "smb_Daemon");
9462 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9463 thrd_CloseHandle(phandle);
9465 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9466 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9467 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9468 thrd_CloseHandle(phandle);
9470 lock_ReleaseMutex(&smb_StartedLock);
9474 void smb_Shutdown(void)
9481 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9483 /* setup the NCB system */
9486 /* Block new sessions by setting shutdown flag */
9487 smbShutdownFlag = 1;
9489 /* Hang up all sessions */
9490 memset((char *)ncbp, 0, sizeof(NCB));
9491 for (i = 1; i < numSessions; i++)
9493 if (dead_sessions[i])
9496 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9497 ncbp->ncb_command = NCBHANGUP;
9498 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9499 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9500 code = Netbios(ncbp);
9501 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9502 if (code == 0) code = ncbp->ncb_retcode;
9504 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9505 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9509 /* Trigger the shutdown of all SMB threads */
9510 for (i = 0; i < smb_NumServerThreads; i++)
9511 thrd_SetEvent(NCBreturns[i][0]);
9513 thrd_SetEvent(NCBevents[0]);
9514 thrd_SetEvent(SessionEvents[0]);
9515 thrd_SetEvent(NCBavails[0]);
9517 for (i = 0;i < smb_NumServerThreads; i++) {
9518 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
9519 if (code == WAIT_OBJECT_0) {
9522 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
9523 thrd_SetEvent(NCBreturns[i--][0]);
9527 /* Delete Netbios name */
9528 memset((char *)ncbp, 0, sizeof(NCB));
9529 for (i = 0; i < lana_list.length; i++) {
9530 if (lana_list.lana[i] == LANA_INVALID) continue;
9531 ncbp->ncb_command = NCBDELNAME;
9532 ncbp->ncb_lana_num = lana_list.lana[i];
9533 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9534 code = Netbios(ncbp);
9536 code = ncbp->ncb_retcode;
9538 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9539 ncbp->ncb_lana_num, code);
9544 /* Release the reference counts held by the VCs */
9545 lock_ObtainWrite(&smb_rctLock);
9546 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9551 if (vcp->magic != SMB_VC_MAGIC)
9552 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9553 __FILE__, __LINE__);
9555 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9557 if (fidp->scp != NULL) {
9560 lock_ObtainMutex(&fidp->mx);
9561 if (fidp->scp != NULL) {
9564 lock_ObtainWrite(&scp->rw);
9565 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9566 lock_ReleaseWrite(&scp->rw);
9567 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9568 cm_ReleaseSCache(scp);
9570 lock_ReleaseMutex(&fidp->mx);
9574 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9576 smb_ReleaseVCNoLock(tidp->vcp);
9578 cm_user_t *userp = tidp->userp;
9580 cm_ReleaseUser(userp);
9584 lock_ReleaseWrite(&smb_rctLock);
9586 TlsFree(smb_TlsRequestSlot);
9589 /* Get the UNC \\<servername>\<sharename> prefix. */
9590 char *smb_GetSharename()
9594 /* Make sure we have been properly initialized. */
9595 if (smb_localNamep == NULL)
9598 /* Allocate space for \\<servername>\<sharename>, plus the
9601 name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
9602 sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
9608 void smb_LogPacket(smb_packet_t *packet)
9612 unsigned length, paramlen, datalen, i, j;
9614 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9616 if (!packet) return;
9618 osi_Log0(smb_logp, "*** SMB packet dump ***");
9620 smbp = (smb_t *) packet->data;
9621 vp = (BYTE *) packet->data;
9623 paramlen = smbp->wct * 2;
9624 datalen = *((WORD *) (smbp->vdata + paramlen));
9625 length = sizeof(*smbp) + paramlen + 1 + datalen;
9627 for (i=0;i < length; i+=16)
9629 memset( buf, ' ', 80 );
9634 buf[strlen(buf)] = ' ';
9636 cp = (BYTE*) buf + 7;
9638 for (j=0;j < 16 && (i+j)<length; j++)
9640 *(cp++) = hex[vp[i+j] >> 4];
9641 *(cp++) = hex[vp[i+j] & 0xf];
9651 for (j=0;j < 16 && (i+j)<length;j++)
9653 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9664 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9667 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9669 #endif /* LOG_PACKET */
9672 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9680 lock_ObtainRead(&smb_rctLock);
9682 sprintf(output, "begin dumping smb_vc_t\r\n");
9683 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9685 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9689 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9690 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9691 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9693 sprintf(output, "begin dumping smb_fid_t\r\n");
9694 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9696 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9698 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",
9699 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9700 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9701 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9702 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9705 sprintf(output, "done dumping smb_fid_t\r\n");
9706 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9709 sprintf(output, "done dumping smb_vc_t\r\n");
9710 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9712 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9713 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9715 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9719 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9720 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9721 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9723 sprintf(output, "begin dumping smb_fid_t\r\n");
9724 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9726 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9728 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",
9729 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9730 fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL",
9731 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
9732 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9735 sprintf(output, "done dumping smb_fid_t\r\n");
9736 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9739 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9740 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9743 lock_ReleaseRead(&smb_rctLock);
9747 long smb_IsNetworkStarted(void)
9750 lock_ObtainWrite(&smb_globalLock);
9751 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
9752 lock_ReleaseWrite(&smb_globalLock);