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 clientchar_t *illegalChars = _C("\\/:*?\"<>|");
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 int showErrors = 0;
146 /* MessageBox or something like it */
147 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT)
151 * Time in Unix format of midnight, 1/1/1970 local time.
152 * When added to dosUTime, gives Unix (AFS) time.
154 time_t smb_localZero = 0;
156 #define USE_NUMERIC_TIME_CONV 1
158 #ifndef USE_NUMERIC_TIME_CONV
159 /* Time difference for converting to kludge-GMT */
160 afs_uint32 smb_NowTZ;
161 #endif /* USE_NUMERIC_TIME_CONV */
163 char *smb_localNamep = NULL;
165 smb_vc_t *smb_allVCsp;
166 smb_vc_t *smb_deadVCsp;
168 smb_username_t *usernamesp = NULL;
170 smb_waitingLockRequest_t *smb_allWaitingLocks;
172 DWORD smb_TlsRequestSlot = -1;
175 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
176 NCB *ncbp, raw_write_cont_t *rwcp);
177 int smb_NetbiosInit(int);
180 void smb_LogPacket(smb_packet_t *packet);
181 #endif /* LOG_PACKET */
183 clientchar_t smb_ServerDomainName[MAX_COMPUTERNAME_LENGTH + 1] = _C(""); /* domain name */
184 int smb_ServerDomainNameLength = 0;
185 clientchar_t smb_ServerOS[] = _C("Windows 5.0"); /* Faux OS String */
186 int smb_ServerOSLength = lengthof(smb_ServerOS);
187 clientchar_t smb_ServerLanManager[] = _C("Windows 2000 LAN Manager"); /* Faux LAN Manager string */
188 int smb_ServerLanManagerLength = lengthof(smb_ServerLanManager);
190 /* Faux server GUID. This is never checked. */
191 GUID smb_ServerGUID = { 0x40015cb8, 0x058a, 0x44fc, { 0xae, 0x7e, 0xbb, 0x29, 0x52, 0xee, 0x7e, 0xff }};
193 void smb_InitReq(cm_req_t *reqp)
196 reqp->flags |= CM_REQ_SOURCE_SMB;
199 void smb_ResetServerPriority()
201 void * p = TlsGetValue(smb_TlsRequestSlot);
204 TlsSetValue(smb_TlsRequestSlot, NULL);
205 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
209 void smb_SetRequestStartTime()
211 time_t * tp = TlsGetValue(smb_TlsRequestSlot);
213 tp = malloc(sizeof(time_t));
217 if (!TlsSetValue(smb_TlsRequestSlot, tp))
222 void smb_UpdateServerPriority()
224 time_t *tp = TlsGetValue(smb_TlsRequestSlot);
227 time_t now = osi_Time();
229 /* Give one priority boost for each 15 seconds */
230 SetThreadPriority(GetCurrentThread(), (int)((now - *tp) / 15));
235 const char * ncb_error_string(int code)
239 case 0x01: s = "llegal buffer length"; break;
240 case 0x03: s = "illegal command"; break;
241 case 0x05: s = "command timed out"; break;
242 case 0x06: s = "message incomplete, issue another command"; break;
243 case 0x07: s = "illegal buffer address"; break;
244 case 0x08: s = "session number out of range"; break;
245 case 0x09: s = "no resource available"; break;
246 case 0x0a: s = "session closed"; break;
247 case 0x0b: s = "command cancelled"; break;
248 case 0x0d: s = "duplicate name"; break;
249 case 0x0e: s = "name table full"; break;
250 case 0x0f: s = "no deletions, name has active sessions"; break;
251 case 0x11: s = "local session table full"; break;
252 case 0x12: s = "remote session table full"; break;
253 case 0x13: s = "illegal name number"; break;
254 case 0x14: s = "no callname"; break;
255 case 0x15: s = "cannot put * in NCB_NAME"; break;
256 case 0x16: s = "name in use on remote adapter"; break;
257 case 0x17: s = "name deleted"; break;
258 case 0x18: s = "session ended abnormally"; break;
259 case 0x19: s = "name conflict detected"; break;
260 case 0x21: s = "interface busy, IRET before retrying"; break;
261 case 0x22: s = "too many commands outstanding, retry later";break;
262 case 0x23: s = "ncb_lana_num field invalid"; break;
263 case 0x24: s = "command completed while cancel occurring "; break;
264 case 0x26: s = "command not valid to cancel"; break;
265 case 0x30: s = "name defined by anther local process"; break;
266 case 0x34: s = "environment undefined. RESET required"; break;
267 case 0x35: s = "required OS resources exhausted"; break;
268 case 0x36: s = "max number of applications exceeded"; break;
269 case 0x37: s = "no saps available for netbios"; break;
270 case 0x38: s = "requested resources are not available"; break;
271 case 0x39: s = "invalid ncb address or length > segment"; break;
272 case 0x3B: s = "invalid NCB DDID"; break;
273 case 0x3C: s = "lock of user area failed"; break;
274 case 0x3f: s = "NETBIOS not loaded"; break;
275 case 0x40: s = "system error"; break;
276 default: s = "unknown error";
282 char * myCrt_Dispatch(int i)
287 return "(00)ReceiveCoreMakeDir";
289 return "(01)ReceiveCoreRemoveDir";
291 return "(02)ReceiveCoreOpen";
293 return "(03)ReceiveCoreCreate";
295 return "(04)ReceiveCoreClose";
297 return "(05)ReceiveCoreFlush";
299 return "(06)ReceiveCoreUnlink";
301 return "(07)ReceiveCoreRename";
303 return "(08)ReceiveCoreGetFileAttributes";
305 return "(09)ReceiveCoreSetFileAttributes";
307 return "(0a)ReceiveCoreRead";
309 return "(0b)ReceiveCoreWrite";
311 return "(0c)ReceiveCoreLockRecord";
313 return "(0d)ReceiveCoreUnlockRecord";
315 return "(0e)SendCoreBadOp";
317 return "(0f)ReceiveCoreCreate";
319 return "(10)ReceiveCoreCheckPath";
321 return "(11)SendCoreBadOp";
323 return "(12)ReceiveCoreSeek";
325 return "(1a)ReceiveCoreReadRaw";
327 return "(1d)ReceiveCoreWriteRawDummy";
329 return "(22)ReceiveV3SetAttributes";
331 return "(23)ReceiveV3GetAttributes";
333 return "(24)ReceiveV3LockingX";
335 return "(25)ReceiveV3Trans";
337 return "(26)ReceiveV3Trans[aux]";
339 return "(29)SendCoreBadOp";
341 return "(2b)ReceiveCoreEcho";
343 return "(2d)ReceiveV3OpenX";
345 return "(2e)ReceiveV3ReadX";
347 return "(2f)ReceiveV3WriteX";
349 return "(32)ReceiveV3Tran2A";
351 return "(33)ReceiveV3Tran2A[aux]";
353 return "(34)ReceiveV3FindClose";
355 return "(35)ReceiveV3FindNotifyClose";
357 return "(70)ReceiveCoreTreeConnect";
359 return "(71)ReceiveCoreTreeDisconnect";
361 return "(72)ReceiveNegotiate";
363 return "(73)ReceiveV3SessionSetupX";
365 return "(74)ReceiveV3UserLogoffX";
367 return "(75)ReceiveV3TreeConnectX";
369 return "(80)ReceiveCoreGetDiskAttributes";
371 return "(81)ReceiveCoreSearchDir";
375 return "(83)FindUnique";
377 return "(84)FindClose";
379 return "(A0)ReceiveNTTransact";
381 return "(A2)ReceiveNTCreateX";
383 return "(A4)ReceiveNTCancel";
385 return "(A5)ReceiveNTRename";
387 return "(C0)OpenPrintFile";
389 return "(C1)WritePrintFile";
391 return "(C2)ClosePrintFile";
393 return "(C3)GetPrintQueue";
395 return "(D8)ReadBulk";
397 return "(D9)WriteBulk";
399 return "(DA)WriteBulkData";
401 return "unknown SMB op";
405 char * myCrt_2Dispatch(int i)
410 return "unknown SMB op-2";
412 return "S(00)CreateFile_ReceiveTran2Open";
414 return "S(01)FindFirst_ReceiveTran2SearchDir";
416 return "S(02)FindNext_ReceiveTran2SearchDir"; /* FindNext */
418 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
420 return "S(04)SetFileSystem_ReceiveTran2SetFSInfo";
422 return "S(05)QueryPathInfo_ReceiveTran2QPathInfo";
424 return "S(06)SetPathInfo_ReceiveTran2SetPathInfo";
426 return "S(07)QueryFileInfo_ReceiveTran2QFileInfo";
428 return "S(08)SetFileInfo_ReceiveTran2SetFileInfo";
430 return "S(09)_ReceiveTran2FSCTL";
432 return "S(0a)_ReceiveTran2IOCTL";
434 return "S(0b)_ReceiveTran2FindNotifyFirst";
436 return "S(0c)_ReceiveTran2FindNotifyNext";
438 return "S(0d)_ReceiveTran2CreateDirectory";
440 return "S(0e)_ReceiveTran2SessionSetup";
442 return "S(0f)_QueryFileSystemInformationFid";
444 return "S(10)_ReceiveTran2GetDfsReferral";
446 return "S(11)_ReceiveTran2ReportDfsInconsistency";
450 char * myCrt_RapDispatch(int i)
455 return "unknown RAP OP";
457 return "RAP(0)NetShareEnum";
459 return "RAP(1)NetShareGetInfo";
461 return "RAP(13)NetServerGetInfo";
463 return "RAP(63)NetWkStaGetInfo";
467 /* scache must be locked */
468 unsigned int smb_Attributes(cm_scache_t *scp)
472 if ( scp->fileType == CM_SCACHETYPE_DIRECTORY ||
473 scp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
474 scp->fileType == CM_SCACHETYPE_INVALID)
476 attrs = SMB_ATTR_DIRECTORY;
477 #ifdef SPECIAL_FOLDERS
478 attrs |= SMB_ATTR_SYSTEM; /* FILE_ATTRIBUTE_SYSTEM */
479 #endif /* SPECIAL_FOLDERS */
480 } else if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
481 attrs = SMB_ATTR_DIRECTORY | SMB_ATTR_SPARSE_FILE;
486 * We used to mark a file RO if it was in an RO volume, but that
487 * turns out to be impolitic in NT. See defect 10007.
490 if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
491 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
493 if ((scp->unixModeBits & 0222) == 0)
494 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
500 /* Check if the named file/dir is a dotfile/dotdir */
501 /* String pointed to by lastComp can have leading slashes, but otherwise should have
502 no other patch components */
503 unsigned int smb_IsDotFile(clientchar_t *lastComp) {
507 /* skip over slashes */
508 for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
513 /* nulls, curdir and parent dir doesn't count */
519 if(*(s+1) == _C('.') && !*(s + 2))
526 static int ExtractBits(WORD bits, short start, short len)
533 num = bits << (16 - end);
534 num = num >> ((16 - end) + start);
539 void ShowUnixTime(char *FuncName, time_t unixTime)
544 smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
546 if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
547 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
549 int day, month, year, sec, min, hour;
552 day = ExtractBits(wDate, 0, 5);
553 month = ExtractBits(wDate, 5, 4);
554 year = ExtractBits(wDate, 9, 7) + 1980;
556 sec = ExtractBits(wTime, 0, 5);
557 min = ExtractBits(wTime, 5, 6);
558 hour = ExtractBits(wTime, 11, 5);
560 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
561 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
565 /* Determine if we are observing daylight savings time */
566 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
568 TIME_ZONE_INFORMATION timeZoneInformation;
569 SYSTEMTIME utc, local, localDST;
571 /* Get the time zone info. NT uses this to calc if we are in DST. */
572 GetTimeZoneInformation(&timeZoneInformation);
574 /* Return the daylight bias */
575 *pDstBias = timeZoneInformation.DaylightBias;
577 /* Return the bias */
578 *pBias = timeZoneInformation.Bias;
580 /* Now determine if DST is being observed */
582 /* Get the UTC (GMT) time */
585 /* Convert UTC time to local time using the time zone info. If we are
586 observing DST, the calculated local time will include this.
588 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
590 /* Set the daylight bias to 0. The daylight bias is the amount of change
591 * in time that we use for daylight savings time. By setting this to 0
592 * we cause there to be no change in time during daylight savings time.
594 timeZoneInformation.DaylightBias = 0;
596 /* Convert the utc time to local time again, but this time without any
597 adjustment for daylight savings time.
599 SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
601 /* If the two times are different, then it means that the localDST that
602 we calculated includes the daylight bias, and therefore we are
603 observing daylight savings time.
605 *pDST = localDST.wHour != local.wHour;
609 void CompensateForSmbClientLastWriteTimeBugs(afs_uint32 *pLastWriteTime)
611 BOOL dst; /* Will be TRUE if observing DST */
612 LONG dstBias; /* Offset from local time if observing DST */
613 LONG bias; /* Offset from GMT for local time */
616 * This function will adjust the last write time to compensate
617 * for two bugs in the smb client:
619 * 1) During Daylight Savings Time, the LastWriteTime is ahead
620 * in time by the DaylightBias (ignoring the sign - the
621 * DaylightBias is always stored as a negative number). If
622 * the DaylightBias is -60, then the LastWriteTime will be
623 * ahead by 60 minutes.
625 * 2) If the local time zone is a positive offset from GMT, then
626 * the LastWriteTime will be the correct local time plus the
627 * Bias (ignoring the sign - a positive offset from GMT is
628 * always stored as a negative Bias). If the Bias is -120,
629 * then the LastWriteTime will be ahead by 120 minutes.
631 * These bugs can occur at the same time.
634 GetTimeZoneInfo(&dst, &dstBias, &bias);
636 /* First adjust for DST */
638 *pLastWriteTime -= (-dstBias * 60); /* Convert dstBias to seconds */
640 /* Now adjust for a positive offset from GMT (a negative bias). */
642 *pLastWriteTime -= (-bias * 60); /* Convert bias to seconds */
645 #ifndef USE_NUMERIC_TIME_CONV
647 * Calculate the difference (in seconds) between local time and GMT.
648 * This enables us to convert file times to kludge-GMT.
654 struct tm gmt_tm, local_tm;
655 int days, hours, minutes, seconds;
658 gmt_tm = *(gmtime(&t));
659 local_tm = *(localtime(&t));
661 days = local_tm.tm_yday - gmt_tm.tm_yday;
662 hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
663 minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
664 seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
668 #endif /* USE_NUMERIC_TIME_CONV */
670 #ifdef USE_NUMERIC_TIME_CONV
671 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
673 // Note that LONGLONG is a 64-bit value
676 ll = Int32x32To64(unixTime, 10000000) + 116444736000000000;
677 largeTimep->dwLowDateTime = (DWORD)(ll & 0xFFFFFFFF);
678 largeTimep->dwHighDateTime = (DWORD)(ll >> 32);
681 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, time_t unixTime)
686 time_t ersatz_unixTime;
689 * Must use kludge-GMT instead of real GMT.
690 * kludge-GMT is computed by adding time zone difference to localtime.
693 * ltp = gmtime(&unixTime);
695 ersatz_unixTime = unixTime - smb_NowTZ;
696 ltp = localtime(&ersatz_unixTime);
698 /* if we fail, make up something */
701 localJunk.tm_year = 89 - 20;
702 localJunk.tm_mon = 4;
703 localJunk.tm_mday = 12;
704 localJunk.tm_hour = 0;
705 localJunk.tm_min = 0;
706 localJunk.tm_sec = 0;
709 stm.wYear = ltp->tm_year + 1900;
710 stm.wMonth = ltp->tm_mon + 1;
711 stm.wDayOfWeek = ltp->tm_wday;
712 stm.wDay = ltp->tm_mday;
713 stm.wHour = ltp->tm_hour;
714 stm.wMinute = ltp->tm_min;
715 stm.wSecond = ltp->tm_sec;
716 stm.wMilliseconds = 0;
718 SystemTimeToFileTime(&stm, largeTimep);
720 #endif /* USE_NUMERIC_TIME_CONV */
722 #ifdef USE_NUMERIC_TIME_CONV
723 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
725 // Note that LONGLONG is a 64-bit value
728 ll = largeTimep->dwHighDateTime;
730 ll += largeTimep->dwLowDateTime;
732 ll -= 116444736000000000;
735 *unixTimep = (DWORD)ll;
737 #else /* USE_NUMERIC_TIME_CONV */
738 void smb_UnixTimeFromLargeSearchTime(time_t *unixTimep, FILETIME *largeTimep)
744 FileTimeToSystemTime(largeTimep, &stm);
746 lt.tm_year = stm.wYear - 1900;
747 lt.tm_mon = stm.wMonth - 1;
748 lt.tm_wday = stm.wDayOfWeek;
749 lt.tm_mday = stm.wDay;
750 lt.tm_hour = stm.wHour;
751 lt.tm_min = stm.wMinute;
752 lt.tm_sec = stm.wSecond;
755 save_timezone = _timezone;
756 _timezone += smb_NowTZ;
757 *unixTimep = mktime(<);
758 _timezone = save_timezone;
760 #endif /* USE_NUMERIC_TIME_CONV */
762 void smb_SearchTimeFromUnixTime(afs_uint32 *searchTimep, time_t unixTime)
772 /* if we fail, make up something */
775 localJunk.tm_year = 89 - 20;
776 localJunk.tm_mon = 4;
777 localJunk.tm_mday = 12;
778 localJunk.tm_hour = 0;
779 localJunk.tm_min = 0;
780 localJunk.tm_sec = 0;
783 dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
784 dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
785 *searchTimep = (dosDate<<16) | dosTime;
788 void smb_UnixTimeFromSearchTime(time_t *unixTimep, afs_uint32 searchTime)
790 unsigned short dosDate;
791 unsigned short dosTime;
794 dosDate = (unsigned short) (searchTime & 0xffff);
795 dosTime = (unsigned short) ((searchTime >> 16) & 0xffff);
797 localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
798 localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1; /* January is 0 in localTm */
799 localTm.tm_mday = (dosDate) & 0x1f;
800 localTm.tm_hour = (dosTime>>11) & 0x1f;
801 localTm.tm_min = (dosTime >> 5) & 0x3f;
802 localTm.tm_sec = (dosTime & 0x1f) * 2;
803 localTm.tm_isdst = -1; /* compute whether DST in effect */
805 *unixTimep = mktime(&localTm);
808 void smb_DosUTimeFromUnixTime(afs_uint32 *dosUTimep, time_t unixTime)
810 time_t diff_t = unixTime - smb_localZero;
811 #if defined(DEBUG) && !defined(_USE_32BIT_TIME_T)
812 osi_assertx(diff_t < _UI32_MAX, "time_t > _UI32_MAX");
814 *dosUTimep = (afs_uint32)diff_t;
817 void smb_UnixTimeFromDosUTime(time_t *unixTimep, afs_uint32 dosTime)
819 *unixTimep = dosTime + smb_localZero;
822 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
826 lock_ObtainWrite(&smb_globalLock); /* for numVCs */
827 lock_ObtainWrite(&smb_rctLock);
828 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
829 if (vcp->magic != SMB_VC_MAGIC)
830 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
833 if (lsn == vcp->lsn && lana == vcp->lana &&
834 !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
835 smb_HoldVCNoLock(vcp);
839 if (!vcp && (flags & SMB_FLAG_CREATE)) {
840 vcp = malloc(sizeof(*vcp));
841 memset(vcp, 0, sizeof(*vcp));
842 vcp->vcID = ++numVCs;
843 vcp->magic = SMB_VC_MAGIC;
844 vcp->refCount = 2; /* smb_allVCsp and caller */
847 vcp->uidCounter = 1; /* UID 0 is reserved for blank user */
848 vcp->nextp = smb_allVCsp;
850 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
855 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
856 /* We must obtain a challenge for extended auth
857 * in case the client negotiates smb v3
859 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
860 MSV1_0_LM20_CHALLENGE_REQUEST lsaReq;
861 PMSV1_0_LM20_CHALLENGE_RESPONSE lsaResp = NULL;
862 ULONG lsaRespSize = 0;
864 lsaReq.MessageType = MsV1_0Lm20ChallengeRequest;
866 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
873 if (nts != STATUS_SUCCESS || ntsEx != STATUS_SUCCESS) {
874 osi_Log4(smb_logp,"MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize is %u needs %u",
875 nts, ntsEx, sizeof(lsaReq), lsaRespSize);
876 afsi_log("MsV1_0Lm20ChallengeRequest failure: nts 0x%x ntsEx 0x%x respSize %u",
877 nts, ntsEx, lsaRespSize);
879 osi_assertx(nts == STATUS_SUCCESS, "LsaCallAuthenticationPackage failed"); /* this had better work! */
881 if (ntsEx == STATUS_SUCCESS) {
882 memcpy(vcp->encKey, lsaResp->ChallengeToClient, MSV1_0_CHALLENGE_LENGTH);
883 LsaFreeReturnBuffer(lsaResp);
886 * This will cause the subsequent authentication to fail but
887 * that is better than us dereferencing a NULL pointer and
890 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
894 memset(vcp->encKey, 0, MSV1_0_CHALLENGE_LENGTH);
896 if (numVCs >= CM_SESSION_RESERVED) {
898 osi_Log0(smb_logp, "WARNING: numVCs wrapping around");
901 lock_ReleaseWrite(&smb_rctLock);
902 lock_ReleaseWrite(&smb_globalLock);
906 int smb_IsStarMask(clientchar_t *maskp)
911 for(i=0; i<11; i++) {
913 if (tc == _C('?') || tc == _C('*') || tc == _C('>'))
919 void smb_ReleaseVCInternal(smb_vc_t *vcp)
926 if (vcp->refCount == 0) {
927 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
928 /* remove VCP from smb_deadVCsp */
929 for (vcpp = &smb_deadVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
935 lock_FinalizeMutex(&vcp->mx);
936 memset(vcp,0,sizeof(smb_vc_t));
939 for (avcp = smb_allVCsp; avcp; avcp = avcp->nextp) {
943 osi_Log3(smb_logp,"VCP not dead and %sin smb_allVCsp vcp %x ref %d",
944 avcp?"not ":"",vcp, vcp->refCount);
946 GenerateMiniDump(NULL);
948 /* This is a wrong. However, I suspect that there is an undercount
949 * and I don't want to release 1.4.1 in a state that will allow
950 * smb_vc_t objects to be deallocated while still in the
951 * smb_allVCsp list. The list is supposed to keep a reference
952 * to the smb_vc_t. Put it back.
956 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
957 /* The reference count is non-zero but the VC is dead.
958 * This implies that some FIDs, TIDs, etc on the VC have yet to
959 * be cleaned up. Add a reference that will be dropped by
960 * smb_CleanupDeadVC() and try to cleanup the VC again.
961 * Eventually the refCount will drop to zero when all of the
962 * active threads working with the VC end their task.
964 vcp->refCount++; /* put the refCount back */
965 lock_ReleaseWrite(&smb_rctLock);
966 smb_CleanupDeadVC(vcp);
967 lock_ObtainWrite(&smb_rctLock);
971 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
973 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
974 smb_ReleaseVCInternal(vcp);
977 void smb_ReleaseVC(smb_vc_t *vcp)
979 lock_ObtainWrite(&smb_rctLock);
980 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
981 smb_ReleaseVCInternal(vcp);
982 lock_ReleaseWrite(&smb_rctLock);
985 void smb_HoldVCNoLock(smb_vc_t *vcp)
988 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
991 void smb_HoldVC(smb_vc_t *vcp)
993 lock_ObtainWrite(&smb_rctLock);
995 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
996 lock_ReleaseWrite(&smb_rctLock);
999 void smb_CleanupDeadVC(smb_vc_t *vcp)
1001 smb_fid_t *fidpIter;
1002 smb_fid_t *fidpNext;
1004 smb_tid_t *tidpIter;
1005 smb_tid_t *tidpNext;
1007 smb_user_t *uidpIter;
1008 smb_user_t *uidpNext;
1010 afs_uint32 refCount = 0;
1012 lock_ObtainMutex(&vcp->mx);
1013 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1014 lock_ReleaseMutex(&vcp->mx);
1015 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1018 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1019 lock_ReleaseMutex(&vcp->mx);
1020 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1022 lock_ObtainWrite(&smb_rctLock);
1023 /* remove VCP from smb_allVCsp */
1024 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1025 if ((*vcpp)->magic != SMB_VC_MAGIC)
1026 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1027 __FILE__, __LINE__);
1030 vcp->nextp = smb_deadVCsp;
1032 /* Hold onto the reference until we are done with this function */
1037 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1038 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1040 if (fidpIter->deleteOk)
1043 fid = fidpIter->fid;
1044 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1046 smb_HoldFIDNoLock(fidpIter);
1047 lock_ReleaseWrite(&smb_rctLock);
1049 smb_CloseFID(vcp, fidpIter, NULL, 0);
1050 smb_ReleaseFID(fidpIter);
1052 lock_ObtainWrite(&smb_rctLock);
1053 fidpNext = vcp->fidsp;
1056 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1057 tidpNext = tidpIter->nextp;
1058 if (tidpIter->deleteOk)
1060 tidpIter->deleteOk = 1;
1062 tid = tidpIter->tid;
1063 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1065 smb_HoldTIDNoLock(tidpIter);
1066 smb_ReleaseTID(tidpIter, TRUE);
1067 tidpNext = vcp->tidsp;
1070 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1071 uidpNext = uidpIter->nextp;
1072 if (uidpIter->deleteOk)
1074 uidpIter->deleteOk = 1;
1076 /* do not add an additional reference count for the smb_user_t
1077 * as the smb_vc_t already is holding a reference */
1078 lock_ReleaseWrite(&smb_rctLock);
1080 smb_ReleaseUID(uidpIter);
1082 lock_ObtainWrite(&smb_rctLock);
1083 uidpNext = vcp->usersp;
1086 /* The vcp is now on the deadVCsp list. We intentionally drop the
1087 * reference so that the refcount can reach 0 and we can delete it */
1088 refCount = vcp->refCount;
1089 smb_ReleaseVCNoLock(vcp);
1092 * If the refCount == 1 going into the ReleaseVCNoLock call
1093 * the object will be freed and it won't be safe to clear
1097 lock_ObtainMutex(&vcp->mx);
1098 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1099 lock_ReleaseMutex(&vcp->mx);
1102 lock_ReleaseWrite(&smb_rctLock);
1103 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1106 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1110 lock_ObtainWrite(&smb_rctLock);
1112 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1113 if (tidp->refCount == 0 && tidp->deleteOk) {
1115 smb_ReleaseTID(tidp, TRUE);
1119 if (tid == tidp->tid) {
1124 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1125 tidp = malloc(sizeof(*tidp));
1126 memset(tidp, 0, sizeof(*tidp));
1127 tidp->nextp = vcp->tidsp;
1130 smb_HoldVCNoLock(vcp);
1132 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1135 lock_ReleaseWrite(&smb_rctLock);
1139 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1144 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1152 lock_ObtainWrite(&smb_rctLock);
1153 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1154 if (tidp->refCount == 0 && (tidp->deleteOk)) {
1155 ltpp = &tidp->vcp->tidsp;
1156 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1160 osi_assertx(tp != NULL, "null smb_tid_t");
1162 lock_FinalizeMutex(&tidp->mx);
1163 userp = tidp->userp; /* remember to drop ref later */
1165 smb_ReleaseVCNoLock(tidp->vcp);
1169 lock_ReleaseWrite(&smb_rctLock);
1171 cm_ReleaseUser(userp);
1174 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1176 smb_user_t *uidp = NULL;
1178 lock_ObtainWrite(&smb_rctLock);
1179 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1180 if (uid == uidp->userID) {
1182 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1184 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1188 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1189 uidp = malloc(sizeof(*uidp));
1190 memset(uidp, 0, sizeof(*uidp));
1191 uidp->nextp = vcp->usersp;
1192 uidp->refCount = 2; /* one for the vcp and one for the caller */
1194 smb_HoldVCNoLock(vcp);
1196 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1198 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1200 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1202 lock_ReleaseWrite(&smb_rctLock);
1206 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1209 smb_username_t *unp= NULL;
1211 lock_ObtainWrite(&smb_rctLock);
1212 for(unp = usernamesp; unp; unp = unp->nextp) {
1213 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1214 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1219 if (!unp && (flags & SMB_FLAG_CREATE)) {
1220 unp = malloc(sizeof(*unp));
1221 memset(unp, 0, sizeof(*unp));
1223 unp->nextp = usernamesp;
1224 unp->name = cm_ClientStrDup(usern);
1225 unp->machine = cm_ClientStrDup(machine);
1227 lock_InitializeMutex(&unp->mx, "username_t mutex");
1228 if (flags & SMB_FLAG_AFSLOGON)
1229 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1232 lock_ReleaseWrite(&smb_rctLock);
1236 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1238 smb_user_t *uidp= NULL;
1240 lock_ObtainWrite(&smb_rctLock);
1241 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1244 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1246 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1247 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1252 lock_ReleaseWrite(&smb_rctLock);
1256 void smb_ReleaseUsername(smb_username_t *unp)
1259 smb_username_t **lupp;
1260 cm_user_t *userp = NULL;
1261 time_t now = osi_Time();
1263 lock_ObtainWrite(&smb_rctLock);
1264 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1265 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1266 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1268 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1272 osi_assertx(up != NULL, "null smb_username_t");
1274 up->nextp = NULL; /* do not remove this */
1275 lock_FinalizeMutex(&unp->mx);
1281 lock_ReleaseWrite(&smb_rctLock);
1283 cm_ReleaseUser(userp);
1286 void smb_HoldUIDNoLock(smb_user_t *uidp)
1291 void smb_ReleaseUID(smb_user_t *uidp)
1295 smb_username_t *unp = NULL;
1297 lock_ObtainWrite(&smb_rctLock);
1298 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1299 if (uidp->refCount == 0) {
1300 lupp = &uidp->vcp->usersp;
1301 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1305 osi_assertx(up != NULL, "null smb_user_t");
1307 lock_FinalizeMutex(&uidp->mx);
1309 smb_ReleaseVCNoLock(uidp->vcp);
1313 lock_ReleaseWrite(&smb_rctLock);
1317 cm_ReleaseUserVCRef(unp->userp);
1318 smb_ReleaseUsername(unp);
1322 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1324 cm_user_t *up = NULL;
1329 lock_ObtainMutex(&uidp->mx);
1331 up = uidp->unp->userp;
1334 lock_ReleaseMutex(&uidp->mx);
1340 /* retrieve a held reference to a user structure corresponding to an incoming
1342 * corresponding release function is cm_ReleaseUser.
1344 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1347 cm_user_t *up = NULL;
1350 smbp = (smb_t *) inp;
1351 uidp = smb_FindUID(vcp, smbp->uid, 0);
1355 up = smb_GetUserFromUID(uidp);
1357 smb_ReleaseUID(uidp);
1362 * Return a pointer to a pathname extracted from a TID structure. The
1363 * TID structure is not held; assume it won't go away.
1365 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1370 tidp = smb_FindTID(vcp, tid, 0);
1374 if (tidp->flags & SMB_TIDFLAG_IPC) {
1375 code = CM_ERROR_TIDIPC;
1376 /* tidp->pathname would be NULL, but that's fine */
1378 *treepath = tidp->pathname;
1379 smb_ReleaseTID(tidp, FALSE);
1384 /* check to see if we have a chained fid, that is, a fid that comes from an
1385 * OpenAndX message that ran earlier in this packet. In this case, the fid
1386 * field in a read, for example, request, isn't set, since the value is
1387 * supposed to be inherited from the openAndX call.
1389 int smb_ChainFID(int fid, smb_packet_t *inp)
1391 if (inp->fid == 0 || inp->inCount == 0)
1397 /* are we a priv'd user? What does this mean on NT? */
1398 int smb_SUser(cm_user_t *userp)
1403 /* find a file ID. If we pass in 0 we select an unused File ID.
1404 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1405 * smb_fid_t data structure if desired File ID cannot be found.
1407 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1412 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1415 lock_ObtainWrite(&smb_rctLock);
1416 /* figure out if we need to allocate a new file ID */
1419 fid = vcp->fidCounter;
1423 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1424 if (fidp->refCount == 0 && fidp->deleteOk) {
1426 lock_ReleaseWrite(&smb_rctLock);
1427 smb_ReleaseFID(fidp);
1428 lock_ObtainWrite(&smb_rctLock);
1431 if (fid == fidp->fid) {
1434 if (fid == 0xFFFF) {
1436 "New FID number wraps on vcp 0x%x", vcp);
1446 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1447 char eventName[MAX_PATH];
1449 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1450 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1451 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1452 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1453 thrd_CloseHandle(event);
1455 if (fid == 0xFFFF) {
1456 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1462 fidp = malloc(sizeof(*fidp));
1463 memset(fidp, 0, sizeof(*fidp));
1464 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1467 smb_HoldVCNoLock(vcp);
1468 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1470 fidp->curr_chunk = fidp->prev_chunk = -2;
1471 fidp->raw_write_event = event;
1473 vcp->fidCounter = fid+1;
1474 if (vcp->fidCounter == 0xFFFF) {
1475 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1477 vcp->fidCounter = 1;
1482 lock_ReleaseWrite(&smb_rctLock);
1486 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1488 smb_fid_t *fidp = NULL;
1494 lock_ObtainWrite(&smb_rctLock);
1495 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1496 if (scp == fidp->scp) {
1501 lock_ReleaseWrite(&smb_rctLock);
1505 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1511 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1512 /* the sm_fid_t->mx and smb_rctLock must not be held */
1513 void smb_ReleaseFID(smb_fid_t *fidp)
1515 cm_scache_t *scp = NULL;
1516 cm_user_t *userp = NULL;
1517 smb_vc_t *vcp = NULL;
1518 smb_ioctl_t *ioctlp;
1520 lock_ObtainMutex(&fidp->mx);
1521 lock_ObtainWrite(&smb_rctLock);
1522 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1523 if (fidp->refCount == 0 && (fidp->deleteOk)) {
1526 scp = fidp->scp; /* release after lock is released */
1528 lock_ObtainWrite(&scp->rw);
1529 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1530 lock_ReleaseWrite(&scp->rw);
1531 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1534 userp = fidp->userp;
1538 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1539 thrd_CloseHandle(fidp->raw_write_event);
1541 /* and see if there is ioctl stuff to free */
1542 ioctlp = fidp->ioctlp;
1545 cm_FreeSpace(ioctlp->prefix);
1546 if (ioctlp->ioctl.inAllocp)
1547 free(ioctlp->ioctl.inAllocp);
1548 if (ioctlp->ioctl.outAllocp)
1549 free(ioctlp->ioctl.outAllocp);
1552 lock_ReleaseMutex(&fidp->mx);
1553 lock_FinalizeMutex(&fidp->mx);
1557 smb_ReleaseVCNoLock(vcp);
1559 lock_ReleaseMutex(&fidp->mx);
1561 lock_ReleaseWrite(&smb_rctLock);
1563 /* now release the scache structure */
1565 cm_ReleaseSCache(scp);
1568 cm_ReleaseUser(userp);
1572 * Case-insensitive search for one string in another;
1573 * used to find variable names in submount pathnames.
1575 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1577 clientchar_t *cursor;
1579 for (cursor = str1; *cursor; cursor++)
1580 if (cm_ClientStrCmpI(cursor, str2) == 0)
1587 * Substitute a variable value for its name in a submount pathname. Variable
1588 * name has been identified by smb_stristr() and is in substr. Variable name
1589 * length (plus one) is in substr_size. Variable value is in newstr.
1591 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1592 unsigned int substr_size, clientchar_t *newstr)
1594 clientchar_t temp[1024];
1596 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1597 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1598 cm_ClientStrCat(str1, cchstr1, temp);
1601 clientchar_t VNUserName[] = _C("%USERNAME%");
1602 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1603 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1604 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1606 typedef struct smb_findShare_rock {
1607 clientchar_t * shareName;
1608 clientchar_t * match;
1610 } smb_findShare_rock_t;
1612 #define SMB_FINDSHARE_EXACT_MATCH 1
1613 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1615 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1619 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1620 normchar_t normName[MAX_PATH];
1622 cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0]));
1624 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1625 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1626 matchType = SMB_FINDSHARE_EXACT_MATCH;
1628 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1629 if(vrock->match) free(vrock->match);
1630 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1631 vrock->matchType = matchType;
1633 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1634 return CM_ERROR_STOPNOW;
1640 /* find a shareName in the table of submounts */
1641 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1642 clientchar_t *shareName,
1643 clientchar_t **pathNamep)
1647 clientchar_t pathName[1024];
1650 clientchar_t *p, *q;
1651 fschar_t *cellname = NULL;
1654 DWORD allSubmount = 1;
1656 /* if allSubmounts == 0, only return the //mountRoot/all share
1657 * if in fact it has been been created in the subMounts table.
1658 * This is to allow sites that want to restrict access to the
1661 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1662 0, KEY_QUERY_VALUE, &parmKey);
1663 if (code == ERROR_SUCCESS) {
1664 cblen = sizeof(allSubmount);
1665 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1666 (BYTE *) &allSubmount, &cblen);
1667 if (code != ERROR_SUCCESS) {
1670 RegCloseKey (parmKey);
1673 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1678 /* In case, the all share is disabled we need to still be able
1679 * to handle ioctl requests
1681 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1682 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1686 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1687 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1688 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1689 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1690 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1696 /* Check for volume references
1698 * They look like <cell>{%,#}<volume>
1700 if (cm_ClientStrChr(shareName, '%') != NULL ||
1701 cm_ClientStrChr(shareName, '#') != NULL) {
1702 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1703 /* make room for '/@vol:' + mountchar + NULL terminator*/
1705 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1706 osi_LogSaveClientString(smb_logp, shareName));
1708 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1709 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1710 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1712 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1714 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1715 cm_ClientStrLwr(*pathNamep);
1716 osi_Log1(smb_logp, " returning pathname [%S]",
1717 osi_LogSaveClientString(smb_logp, *pathNamep));
1725 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1726 0, KEY_QUERY_VALUE, &parmKey);
1727 if (code == ERROR_SUCCESS) {
1728 cblen = sizeof(pathName);
1729 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1730 (BYTE *) pathName, &cblen);
1731 if (code != ERROR_SUCCESS)
1733 RegCloseKey (parmKey);
1737 cchlen = cblen / sizeof(clientchar_t);
1738 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1739 /* We can accept either unix or PC style AFS pathnames. Convert
1740 * Unix-style to PC style here for internal use.
1743 cchlen = lengthof(pathName);
1745 /* within this code block, we maintain, cchlen = writeable
1746 buffer length of p */
1748 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1749 p += cm_mountRootCLen; /* skip mount path */
1750 cchlen -= (p - pathName);
1755 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1761 clientchar_t temp[1024];
1763 if (var = smb_stristr(p, VNUserName)) {
1764 if (uidp && uidp->unp)
1765 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1767 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1769 else if (var = smb_stristr(p, VNLCUserName))
1771 if (uidp && uidp->unp)
1772 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1774 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1775 cm_ClientStrLwr(temp);
1776 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1778 else if (var = smb_stristr(p, VNComputerName))
1780 sizeTemp = lengthof(temp);
1781 GetComputerNameW(temp, &sizeTemp);
1782 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1784 else if (var = smb_stristr(p, VNLCComputerName))
1786 sizeTemp = lengthof(temp);
1787 GetComputerName((LPTSTR)temp, &sizeTemp);
1788 cm_ClientStrLwr(temp);
1789 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1794 *pathNamep = cm_ClientStrDup(p);
1799 /* First lookup shareName in root.afs */
1801 smb_findShare_rock_t vrock;
1803 fschar_t ftemp[1024];
1804 clientchar_t * p = shareName;
1807 /* attempt to locate a partial match in root.afs. This is because
1808 when using the ANSI RAP calls, the share name is limited to 13 chars
1809 and hence is truncated. Of course we prefer exact matches. */
1811 thyper.HighPart = 0;
1814 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1816 vrock.matchType = 0;
1818 cm_HoldSCache(cm_data.rootSCachep);
1819 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1820 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1821 cm_ReleaseSCache(cm_data.rootSCachep);
1823 free(vrock.shareName);
1824 vrock.shareName = NULL;
1826 if (vrock.matchType) {
1827 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1828 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1833 /* if we get here, there was no match for the share in root.afs */
1834 /* so try to create \\<netbiosName>\<cellname> */
1839 /* Get the full name for this cell */
1840 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1841 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1842 #ifdef AFS_AFSDB_ENV
1843 if (code && cm_dnsEnabled) {
1845 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1851 /* construct the path */
1853 clientchar_t temp[1024];
1855 cm_FsStringToClientString(ftemp, cm_FsStrLen(ftemp), temp, 1024);
1856 cm_ClientStrPrintfN(pathName, lengthof(pathName),
1857 rw ? _C("/.%S/") : _C("/%S/"), temp);
1858 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1867 /* Client-side offline caching policy types */
1868 #define CSC_POLICY_MANUAL 0
1869 #define CSC_POLICY_DOCUMENTS 1
1870 #define CSC_POLICY_PROGRAMS 2
1871 #define CSC_POLICY_DISABLE 3
1873 int smb_FindShareCSCPolicy(clientchar_t *shareName)
1876 clientchar_t policy[1024];
1879 int retval = CSC_POLICY_MANUAL;
1881 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1882 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1885 REG_OPTION_NON_VOLATILE,
1891 len = sizeof(policy);
1892 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
1894 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1896 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
1898 retval = CSC_POLICY_DOCUMENTS;
1900 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
1902 retval = CSC_POLICY_PROGRAMS;
1904 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
1906 retval = CSC_POLICY_DISABLE;
1909 RegCloseKey(hkCSCPolicy);
1913 /* find a dir search structure by cookie value, and return it held.
1914 * Must be called with smb_globalLock held.
1916 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1918 smb_dirSearch_t *dsp;
1920 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1921 if (dsp->cookie == cookie) {
1922 if (dsp != smb_firstDirSearchp) {
1923 /* move to head of LRU queue, too, if we're not already there */
1924 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1925 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1926 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1927 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1928 if (!smb_lastDirSearchp)
1929 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1931 lock_ObtainMutex(&dsp->mx);
1933 lock_ReleaseMutex(&dsp->mx);
1939 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1940 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1941 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1947 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1949 lock_ObtainWrite(&smb_globalLock);
1950 lock_ObtainMutex(&dsp->mx);
1951 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1952 dsp->cookie, dsp, dsp->scp);
1953 dsp->flags |= SMB_DIRSEARCH_DELETE;
1954 if (dsp->scp != NULL) {
1955 lock_ObtainWrite(&dsp->scp->rw);
1956 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1957 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1958 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1959 dsp->scp->bulkStatProgress = hzero;
1961 lock_ReleaseWrite(&dsp->scp->rw);
1963 lock_ReleaseMutex(&dsp->mx);
1964 lock_ReleaseWrite(&smb_globalLock);
1967 /* Must be called with the smb_globalLock held */
1968 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1970 cm_scache_t *scp = NULL;
1972 lock_ObtainMutex(&dsp->mx);
1973 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1974 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1975 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1976 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1977 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1978 lock_ReleaseMutex(&dsp->mx);
1979 lock_FinalizeMutex(&dsp->mx);
1981 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1982 dsp->cookie, dsp, scp);
1985 lock_ReleaseMutex(&dsp->mx);
1987 /* do this now to avoid spurious locking hierarchy creation */
1989 cm_ReleaseSCache(scp);
1992 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1994 lock_ObtainWrite(&smb_globalLock);
1995 smb_ReleaseDirSearchNoLock(dsp);
1996 lock_ReleaseWrite(&smb_globalLock);
1999 /* find a dir search structure by cookie value, and return it held */
2000 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2002 smb_dirSearch_t *dsp;
2004 lock_ObtainWrite(&smb_globalLock);
2005 dsp = smb_FindDirSearchNoLock(cookie);
2006 lock_ReleaseWrite(&smb_globalLock);
2010 /* GC some dir search entries, in the address space expected by the specific protocol.
2011 * Must be called with smb_globalLock held; release the lock temporarily.
2013 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2014 void smb_GCDirSearches(int isV3)
2016 smb_dirSearch_t *prevp;
2017 smb_dirSearch_t *tp;
2018 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2022 victimCount = 0; /* how many have we got so far */
2023 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
2024 /* we'll move tp from queue, so
2027 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
2028 /* if no one is using this guy, and we're either in the new protocol,
2029 * or we're in the old one and this is a small enough ID to be useful
2030 * to the old protocol, GC this guy.
2032 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
2033 /* hold and delete */
2034 lock_ObtainMutex(&tp->mx);
2035 tp->flags |= SMB_DIRSEARCH_DELETE;
2036 lock_ReleaseMutex(&tp->mx);
2037 victimsp[victimCount++] = tp;
2041 /* don't do more than this */
2042 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2046 /* now release them */
2047 for (i = 0; i < victimCount; i++) {
2048 smb_ReleaseDirSearchNoLock(victimsp[i]);
2052 /* function for allocating a dir search entry. We need these to remember enough context
2053 * since we don't get passed the path from call to call during a directory search.
2055 * Returns a held dir search structure, and bumps the reference count on the vnode,
2056 * since it saves a pointer to the vnode.
2058 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2060 smb_dirSearch_t *dsp;
2066 lock_ObtainWrite(&smb_globalLock);
2069 /* what's the biggest ID allowed in this version of the protocol */
2070 /* TODO: do we really want a non v3 dir search request to wrap
2071 smb_dirSearchCounter? */
2072 maxAllowed = isV3 ? 65535 : 255;
2073 if (smb_dirSearchCounter > maxAllowed)
2074 smb_dirSearchCounter = 1;
2076 start = smb_dirSearchCounter;
2079 /* twice so we have enough tries to find guys we GC after one pass;
2080 * 10 extra is just in case I mis-counted.
2082 if (++counter > 2*maxAllowed+10)
2083 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2085 if (smb_dirSearchCounter > maxAllowed) {
2086 smb_dirSearchCounter = 1;
2088 if (smb_dirSearchCounter == start) {
2090 smb_GCDirSearches(isV3);
2093 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2095 /* don't need to watch for refcount zero and deleted, since
2096 * we haven't dropped the global lock.
2098 lock_ObtainMutex(&dsp->mx);
2100 lock_ReleaseMutex(&dsp->mx);
2101 ++smb_dirSearchCounter;
2105 dsp = malloc(sizeof(*dsp));
2106 memset(dsp, 0, sizeof(*dsp));
2107 dsp->cookie = smb_dirSearchCounter;
2108 ++smb_dirSearchCounter;
2110 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2111 dsp->lastTime = osi_Time();
2112 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2113 if (!smb_lastDirSearchp)
2114 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2116 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2120 lock_ReleaseWrite(&smb_globalLock);
2124 static smb_packet_t *GetPacket(void)
2128 lock_ObtainWrite(&smb_globalLock);
2129 tbp = smb_packetFreeListp;
2131 smb_packetFreeListp = tbp->nextp;
2132 lock_ReleaseWrite(&smb_globalLock);
2134 tbp = calloc(sizeof(*tbp),1);
2135 tbp->magic = SMB_PACKETMAGIC;
2138 tbp->resumeCode = 0;
2144 tbp->ncb_length = 0;
2147 tbp->stringsp = NULL;
2149 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2154 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2158 memcpy(tbp, pkt, sizeof(smb_packet_t));
2159 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2160 tbp->stringsp = NULL;
2162 smb_HoldVC(tbp->vcp);
2166 static NCB *GetNCB(void)
2171 lock_ObtainWrite(&smb_globalLock);
2172 tbp = smb_ncbFreeListp;
2174 smb_ncbFreeListp = tbp->nextp;
2175 lock_ReleaseWrite(&smb_globalLock);
2177 tbp = calloc(sizeof(*tbp),1);
2178 tbp->magic = SMB_NCBMAGIC;
2181 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2183 memset(&tbp->ncb, 0, sizeof(NCB));
2188 static void FreeSMBStrings(smb_packet_t * pkt)
2193 for (s = pkt->stringsp; s; s = ns) {
2197 pkt->stringsp = NULL;
2200 void smb_FreePacket(smb_packet_t *tbp)
2202 smb_vc_t * vcp = NULL;
2203 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2205 lock_ObtainWrite(&smb_globalLock);
2206 tbp->nextp = smb_packetFreeListp;
2207 smb_packetFreeListp = tbp;
2208 tbp->magic = SMB_PACKETMAGIC;
2212 tbp->resumeCode = 0;
2218 tbp->ncb_length = 0;
2220 FreeSMBStrings(tbp);
2221 lock_ReleaseWrite(&smb_globalLock);
2227 static void FreeNCB(NCB *bufferp)
2231 tbp = (smb_ncb_t *) bufferp;
2232 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2234 lock_ObtainWrite(&smb_globalLock);
2235 tbp->nextp = smb_ncbFreeListp;
2236 smb_ncbFreeListp = tbp;
2237 lock_ReleaseWrite(&smb_globalLock);
2240 /* get a ptr to the data part of a packet, and its count */
2241 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2245 unsigned char *afterParmsp;
2247 parmBytes = *smbp->wctp << 1;
2248 afterParmsp = smbp->wctp + parmBytes + 1;
2250 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2251 if (nbytesp) *nbytesp = dataBytes;
2253 /* don't forget to skip the data byte count, since it follows
2254 * the parameters; that's where the "2" comes from below.
2256 return (unsigned char *) (afterParmsp + 2);
2259 /* must set all the returned parameters before playing around with the
2260 * data region, since the data region is located past the end of the
2261 * variable number of parameters.
2263 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2265 unsigned char *afterParmsp;
2267 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2269 *afterParmsp++ = dsize & 0xff;
2270 *afterParmsp = (dsize>>8) & 0xff;
2273 /* return the parm'th parameter in the smbp packet */
2274 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2277 unsigned char *parmDatap;
2279 parmCount = *smbp->wctp;
2281 if (parm >= parmCount) {
2284 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2285 parm, parmCount, smbp->ncb_length);
2286 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2287 parm, parmCount, smbp->ncb_length);
2288 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2289 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2290 osi_panic(s, __FILE__, __LINE__);
2292 parmDatap = smbp->wctp + (2*parm) + 1;
2294 return parmDatap[0] + (parmDatap[1] << 8);
2297 /* return the parm'th parameter in the smbp packet */
2298 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2301 unsigned char *parmDatap;
2303 parmCount = *smbp->wctp;
2305 if (parm >= parmCount) {
2308 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2309 parm, parmCount, smbp->ncb_length);
2310 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2311 parm, parmCount, smbp->ncb_length);
2312 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2313 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2314 osi_panic(s, __FILE__, __LINE__);
2316 parmDatap = smbp->wctp + (2*parm) + 1;
2318 return parmDatap[0];
2321 /* return the parm'th parameter in the smbp packet */
2322 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2325 unsigned char *parmDatap;
2327 parmCount = *smbp->wctp;
2329 if (parm + 1 >= parmCount) {
2332 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2333 parm, parmCount, smbp->ncb_length);
2334 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2335 parm, parmCount, smbp->ncb_length);
2336 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2337 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2338 osi_panic(s, __FILE__, __LINE__);
2340 parmDatap = smbp->wctp + (2*parm) + 1;
2342 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2345 /* return the parm'th parameter in the smbp packet */
2346 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2349 unsigned char *parmDatap;
2351 parmCount = *smbp->wctp;
2353 if (parm * 2 + offset >= parmCount * 2) {
2356 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2357 parm, offset, parmCount, smbp->ncb_length);
2358 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2359 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2360 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2361 parm, offset, parmCount, smbp->ncb_length);
2362 osi_panic(s, __FILE__, __LINE__);
2364 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2366 return parmDatap[0] + (parmDatap[1] << 8);
2369 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2371 unsigned char *parmDatap;
2373 /* make sure we have enough slots */
2374 if (*smbp->wctp <= slot)
2375 *smbp->wctp = slot+1;
2377 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2378 *parmDatap++ = parmValue & 0xff;
2379 *parmDatap = (parmValue>>8) & 0xff;
2382 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2384 unsigned char *parmDatap;
2386 /* make sure we have enough slots */
2387 if (*smbp->wctp <= slot)
2388 *smbp->wctp = slot+2;
2390 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2391 *parmDatap++ = parmValue & 0xff;
2392 *parmDatap++ = (parmValue>>8) & 0xff;
2393 *parmDatap++ = (parmValue>>16) & 0xff;
2394 *parmDatap = (parmValue>>24) & 0xff;
2397 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2399 unsigned char *parmDatap;
2402 /* make sure we have enough slots */
2403 if (*smbp->wctp <= slot)
2404 *smbp->wctp = slot+4;
2406 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2408 *parmDatap++ = *parmValuep++;
2411 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2413 unsigned char *parmDatap;
2415 /* make sure we have enough slots */
2416 if (*smbp->wctp <= slot) {
2417 if (smbp->oddByte) {
2419 *smbp->wctp = slot+1;
2424 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2425 *parmDatap++ = parmValue & 0xff;
2430 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2431 clientchar_t *inPathp)
2433 clientchar_t *lastSlashp;
2435 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2437 *lastComponentp = lastSlashp;
2440 if (inPathp == lastSlashp)
2442 *outPathp++ = *inPathp++;
2451 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2452 char **chainpp, int flags)
2460 if (!WANTS_UNICODE(pktp))
2461 flags |= SMB_STRF_FORCEASCII;
2464 cb = sizeof(pktp->data) - (inp - pktp->data);
2465 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2466 #ifdef DEBUG_UNICODE
2469 cb = sizeof(pktp->data);
2471 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2474 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2475 char ** chainpp, int flags)
2480 if (!WANTS_UNICODE(pktp))
2481 flags |= SMB_STRF_FORCEASCII;
2484 cb = sizeof(pktp->data) - (inp - pktp->data);
2485 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2486 #ifdef DEBUG_UNICODE
2489 cb = sizeof(pktp->data);
2491 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2494 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2495 size_t cb, char ** chainpp, int flags)
2498 if (!WANTS_UNICODE(pktp))
2499 flags |= SMB_STRF_FORCEASCII;
2502 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2505 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2506 size_t cch, char ** chainpp, int flags)
2511 if (!WANTS_UNICODE(pktp))
2512 flags |= SMB_STRF_FORCEASCII;
2514 cb = cch * sizeof(wchar_t);
2517 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2521 smb_ParseStringBuf(const unsigned char * bufbase,
2522 cm_space_t ** stringspp,
2523 unsigned char *inp, size_t *pcb_max,
2524 char **chainpp, int flags)
2527 if (!(flags & SMB_STRF_FORCEASCII)) {
2529 cm_space_t * spacep;
2532 if (bufbase && ((inp - bufbase) % 2) != 0) {
2533 inp++; /* unicode strings are always word aligned */
2537 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2539 cch_src = *pcb_max / sizeof(wchar_t);
2543 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2550 spacep = cm_GetSpace();
2551 spacep->nextp = *stringspp;
2552 *stringspp = spacep;
2556 *chainpp = inp + sizeof(wchar_t);
2559 *(spacep->wdata) = 0;
2560 return spacep->wdata;
2563 StringCchCopyNW(spacep->wdata,
2564 lengthof(spacep->wdata),
2565 (const clientchar_t *) inp, cch_src);
2568 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2570 return spacep->wdata;
2574 cm_space_t * spacep;
2577 /* Not using Unicode */
2579 *chainpp = inp + strlen(inp) + 1;
2582 spacep = cm_GetSpace();
2583 spacep->nextp = *stringspp;
2584 *stringspp = spacep;
2586 cchdest = lengthof(spacep->wdata);
2587 cm_Utf8ToUtf16(inp, *pcb_max, spacep->wdata, cchdest);
2589 return spacep->wdata;
2595 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2597 size_t * plen, int flags)
2603 /* we are only calculating the required size */
2610 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2612 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2613 if (!(flags & SMB_STRF_IGNORENULL))
2614 *plen += sizeof(wchar_t);
2616 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2626 cch_str = cm_ClientStrLen(str);
2627 cch_dest = cm_ClientStringToUtf8(str, cch_str, NULL, 0);
2630 *plen = ((flags & SMB_STRF_IGNORENULL)? cch_dest: cch_dest+1);
2638 /* if outp != NULL ... */
2640 /* Number of bytes left in the buffer.
2642 If outp lies inside the packet data buffer, we assume that the
2643 buffer is the packet data buffer. Otherwise we assume that the
2644 buffer is sizeof(packet->data).
2647 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2648 align = ((outp - pktp->data) % 2);
2649 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2651 align = (((size_t) outp) % 2);
2652 buffersize = sizeof(pktp->data);
2657 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2663 if (*str == _C('\0')) {
2665 if (buffersize < sizeof(wchar_t))
2668 *((wchar_t *) outp) = L'\0';
2669 if (plen && !(flags & SMB_STRF_IGNORENULL))
2670 *plen += sizeof(wchar_t);
2671 return outp + sizeof(wchar_t);
2674 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, buffersize / sizeof(wchar_t));
2676 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2677 osi_LogSaveClientString(smb_logp, str),
2683 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENULL)? nchars - 1: nchars);
2685 return outp + sizeof(wchar_t) * nchars;
2693 cch_dest = cm_ClientStringToUtf8(str, -1, outp, buffersize);
2696 *plen += ((flags & SMB_STRF_IGNORENULL)? cch_dest - 1: cch_dest);
2698 return outp + cch_dest;
2702 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2708 tlen = inp[0] + (inp[1]<<8);
2709 inp += 2; /* skip length field */
2712 *chainpp = inp + tlen;
2721 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2725 if (*inp++ != 0x1) return NULL;
2726 tlen = inp[0] + (inp[1]<<8);
2727 inp += 2; /* skip length field */
2730 *chainpp = inp + tlen;
2733 if (lengthp) *lengthp = tlen;
2738 /* format a packet as a response */
2739 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2744 outp = (smb_t *) op;
2746 /* zero the basic structure through the smb_wct field, and zero the data
2747 * size field, assuming that wct stays zero; otherwise, you have to
2748 * explicitly set the data size field, too.
2750 inSmbp = (smb_t *) inp;
2751 memset(outp, 0, sizeof(smb_t)+2);
2757 outp->com = inSmbp->com;
2758 outp->tid = inSmbp->tid;
2759 outp->pid = inSmbp->pid;
2760 outp->uid = inSmbp->uid;
2761 outp->mid = inSmbp->mid;
2762 outp->res[0] = inSmbp->res[0];
2763 outp->res[1] = inSmbp->res[1];
2764 op->inCom = inSmbp->com;
2766 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2767 #ifdef SEND_CANONICAL_PATHNAMES
2768 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2770 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2772 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2773 outp->flg2 |= SMB_FLAGS2_UNICODE;
2776 /* copy fields in generic packet area */
2777 op->wctp = &outp->wct;
2780 /* send a (probably response) packet; vcp tells us to whom to send it.
2781 * we compute the length by looking at wct and bcc fields.
2783 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2797 memset((char *)ncbp, 0, sizeof(NCB));
2799 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2800 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2801 extra += tp[0] + (tp[1]<<8);
2802 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2803 extra += 3; /* wct and length fields */
2805 ncbp->ncb_length = extra; /* bytes to send */
2806 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2807 ncbp->ncb_lana_num = vcp->lana;
2808 ncbp->ncb_command = NCBSEND; /* op means send data */
2809 ncbp->ncb_buffer = (char *) inp;/* packet */
2810 code = Netbios(ncbp);
2813 const char * s = ncb_error_string(code);
2814 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2815 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2817 lock_ObtainMutex(&vcp->mx);
2818 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2819 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2821 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2822 lock_ReleaseMutex(&vcp->mx);
2823 lock_ObtainWrite(&smb_globalLock);
2824 dead_sessions[vcp->session] = TRUE;
2825 lock_ReleaseWrite(&smb_globalLock);
2826 smb_CleanupDeadVC(vcp);
2828 lock_ReleaseMutex(&vcp->mx);
2836 void smb_MapNTError(long code, unsigned long *NTStatusp)
2838 unsigned long NTStatus;
2840 /* map CM_ERROR_* errors to NT 32-bit status codes */
2841 /* NT Status codes are listed in ntstatus.h not winerror.h */
2842 if (code == CM_ERROR_NOSUCHCELL) {
2843 NTStatus = 0xC000000FL; /* No such file */
2845 else if (code == CM_ERROR_NOSUCHVOLUME) {
2846 NTStatus = 0xC000000FL; /* No such file */
2848 else if (code == CM_ERROR_TIMEDOUT) {
2850 NTStatus = 0xC00000CFL; /* Sharing Paused */
2852 NTStatus = 0x00000102L; /* Timeout */
2855 else if (code == CM_ERROR_RETRY) {
2856 NTStatus = 0xC000022DL; /* Retry */
2858 else if (code == CM_ERROR_NOACCESS) {
2859 NTStatus = 0xC0000022L; /* Access denied */
2861 else if (code == CM_ERROR_READONLY) {
2862 NTStatus = 0xC00000A2L; /* Write protected */
2864 else if (code == CM_ERROR_NOSUCHFILE ||
2865 code == CM_ERROR_BPLUS_NOMATCH) {
2866 NTStatus = 0xC000000FL; /* No such file */
2868 else if (code == CM_ERROR_NOSUCHPATH) {
2869 NTStatus = 0xC000003AL; /* Object path not found */
2871 else if (code == CM_ERROR_TOOBIG) {
2872 NTStatus = 0xC000007BL; /* Invalid image format */
2874 else if (code == CM_ERROR_INVAL) {
2875 NTStatus = 0xC000000DL; /* Invalid parameter */
2877 else if (code == CM_ERROR_BADFD) {
2878 NTStatus = 0xC0000008L; /* Invalid handle */
2880 else if (code == CM_ERROR_BADFDOP) {
2881 NTStatus = 0xC0000022L; /* Access denied */
2883 else if (code == CM_ERROR_EXISTS) {
2884 NTStatus = 0xC0000035L; /* Object name collision */
2886 else if (code == CM_ERROR_NOTEMPTY) {
2887 NTStatus = 0xC0000101L; /* Directory not empty */
2889 else if (code == CM_ERROR_CROSSDEVLINK) {
2890 NTStatus = 0xC00000D4L; /* Not same device */
2892 else if (code == CM_ERROR_NOTDIR) {
2893 NTStatus = 0xC0000103L; /* Not a directory */
2895 else if (code == CM_ERROR_ISDIR) {
2896 NTStatus = 0xC00000BAL; /* File is a directory */
2898 else if (code == CM_ERROR_BADOP) {
2900 /* I have no idea where this comes from */
2901 NTStatus = 0xC09820FFL; /* SMB no support */
2903 NTStatus = 0xC00000BBL; /* Not supported */
2904 #endif /* COMMENT */
2906 else if (code == CM_ERROR_BADSHARENAME) {
2907 NTStatus = 0xC00000CCL; /* Bad network name */
2909 else if (code == CM_ERROR_NOIPC) {
2911 NTStatus = 0xC0000022L; /* Access Denied */
2913 NTStatus = 0xC000013DL; /* Remote Resources */
2916 else if (code == CM_ERROR_CLOCKSKEW) {
2917 NTStatus = 0xC0000133L; /* Time difference at DC */
2919 else if (code == CM_ERROR_BADTID) {
2920 NTStatus = 0xC0982005L; /* SMB bad TID */
2922 else if (code == CM_ERROR_USESTD) {
2923 NTStatus = 0xC09820FBL; /* SMB use standard */
2925 else if (code == CM_ERROR_QUOTA) {
2926 NTStatus = 0xC0000044L; /* Quota exceeded */
2928 else if (code == CM_ERROR_SPACE) {
2929 NTStatus = 0xC000007FL; /* Disk full */
2931 else if (code == CM_ERROR_ATSYS) {
2932 NTStatus = 0xC0000033L; /* Object name invalid */
2934 else if (code == CM_ERROR_BADNTFILENAME) {
2935 NTStatus = 0xC0000033L; /* Object name invalid */
2937 else if (code == CM_ERROR_WOULDBLOCK) {
2938 NTStatus = 0xC0000055L; /* Lock not granted */
2940 else if (code == CM_ERROR_SHARING_VIOLATION) {
2941 NTStatus = 0xC0000043L; /* Sharing violation */
2943 else if (code == CM_ERROR_LOCK_CONFLICT) {
2944 NTStatus = 0xC0000054L; /* Lock conflict */
2946 else if (code == CM_ERROR_PARTIALWRITE) {
2947 NTStatus = 0xC000007FL; /* Disk full */
2949 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2950 NTStatus = 0xC0000023L; /* Buffer too small */
2952 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2953 NTStatus = 0xC0000035L; /* Object name collision */
2955 else if (code == CM_ERROR_BADPASSWORD) {
2956 NTStatus = 0xC000006DL; /* unknown username or bad password */
2958 else if (code == CM_ERROR_BADLOGONTYPE) {
2959 NTStatus = 0xC000015BL; /* logon type not granted */
2961 else if (code == CM_ERROR_GSSCONTINUE) {
2962 NTStatus = 0xC0000016L; /* more processing required */
2964 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2966 NTStatus = 0xC0000280L; /* reparse point not resolved */
2968 NTStatus = 0xC0000022L; /* Access Denied */
2971 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2972 NTStatus = 0xC0000257L; /* Path Not Covered */
2974 else if (code == CM_ERROR_ALLBUSY) {
2975 NTStatus = 0xC000022DL; /* Retry */
2977 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2978 NTStatus = 0xC00000BEL; /* Bad Network Path */
2980 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
2981 NTStatus = 0xC0000322L; /* No Kerberos key */
2983 else if (code == CM_ERROR_BAD_LEVEL) {
2984 NTStatus = 0xC0000148L; /* Invalid Level */
2986 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
2987 NTStatus = 0xC000007EL; /* Range Not Locked */
2989 else if (code == CM_ERROR_NOSUCHDEVICE) {
2990 NTStatus = 0xC000000EL; /* No Such Device */
2992 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
2993 NTStatus = 0xC0000055L; /* Lock Not Granted */
2995 NTStatus = 0xC0982001L; /* SMB non-specific error */
2998 *NTStatusp = NTStatus;
2999 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3002 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3003 unsigned char *classp)
3005 unsigned char class;
3006 unsigned short error;
3008 /* map CM_ERROR_* errors to SMB errors */
3009 if (code == CM_ERROR_NOSUCHCELL) {
3011 error = 3; /* bad path */
3013 else if (code == CM_ERROR_NOSUCHVOLUME) {
3015 error = 3; /* bad path */
3017 else if (code == CM_ERROR_TIMEDOUT) {
3019 error = 81; /* server is paused */
3021 else if (code == CM_ERROR_RETRY) {
3022 class = 2; /* shouldn't happen */
3025 else if (code == CM_ERROR_NOACCESS) {
3027 error = 4; /* bad access */
3029 else if (code == CM_ERROR_READONLY) {
3031 error = 19; /* read only */
3033 else if (code == CM_ERROR_NOSUCHFILE ||
3034 code == CM_ERROR_BPLUS_NOMATCH) {
3036 error = 2; /* ENOENT! */
3038 else if (code == CM_ERROR_NOSUCHPATH) {
3040 error = 3; /* Bad path */
3042 else if (code == CM_ERROR_TOOBIG) {
3044 error = 11; /* bad format */
3046 else if (code == CM_ERROR_INVAL) {
3047 class = 2; /* server non-specific error code */
3050 else if (code == CM_ERROR_BADFD) {
3052 error = 6; /* invalid file handle */
3054 else if (code == CM_ERROR_BADFDOP) {
3055 class = 1; /* invalid op on FD */
3058 else if (code == CM_ERROR_EXISTS) {
3060 error = 80; /* file already exists */
3062 else if (code == CM_ERROR_NOTEMPTY) {
3064 error = 5; /* delete directory not empty */
3066 else if (code == CM_ERROR_CROSSDEVLINK) {
3068 error = 17; /* EXDEV */
3070 else if (code == CM_ERROR_NOTDIR) {
3071 class = 1; /* bad path */
3074 else if (code == CM_ERROR_ISDIR) {
3075 class = 1; /* access denied; DOS doesn't have a good match */
3078 else if (code == CM_ERROR_BADOP) {
3082 else if (code == CM_ERROR_BADSHARENAME) {
3086 else if (code == CM_ERROR_NOIPC) {
3088 error = 4; /* bad access */
3090 else if (code == CM_ERROR_CLOCKSKEW) {
3091 class = 1; /* invalid function */
3094 else if (code == CM_ERROR_BADTID) {
3098 else if (code == CM_ERROR_USESTD) {
3102 else if (code == CM_ERROR_REMOTECONN) {
3106 else if (code == CM_ERROR_QUOTA) {
3107 if (vcp->flags & SMB_VCFLAG_USEV3) {
3109 error = 39; /* disk full */
3113 error = 5; /* access denied */
3116 else if (code == CM_ERROR_SPACE) {
3117 if (vcp->flags & SMB_VCFLAG_USEV3) {
3119 error = 39; /* disk full */
3123 error = 5; /* access denied */
3126 else if (code == CM_ERROR_PARTIALWRITE) {
3128 error = 39; /* disk full */
3130 else if (code == CM_ERROR_ATSYS) {
3132 error = 2; /* ENOENT */
3134 else if (code == CM_ERROR_WOULDBLOCK) {
3136 error = 33; /* lock conflict */
3138 else if (code == CM_ERROR_LOCK_CONFLICT) {
3140 error = 33; /* lock conflict */
3142 else if (code == CM_ERROR_SHARING_VIOLATION) {
3144 error = 33; /* lock conflict */
3146 else if (code == CM_ERROR_NOFILES) {
3148 error = 18; /* no files in search */
3150 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3152 error = 183; /* Samba uses this */
3154 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3155 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3157 error = 2; /* bad password */
3159 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3161 error = 3; /* bad path */
3170 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3173 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3175 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3176 return CM_ERROR_BADOP;
3180 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3182 unsigned short EchoCount, i;
3183 char *data, *outdata;
3186 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3188 for (i=1; i<=EchoCount; i++) {
3189 data = smb_GetSMBData(inp, &dataSize);
3190 smb_SetSMBParm(outp, 0, i);
3191 smb_SetSMBDataLength(outp, dataSize);
3192 outdata = smb_GetSMBData(outp, NULL);
3193 memcpy(outdata, data, dataSize);
3194 smb_SendPacket(vcp, outp);
3200 /* SMB_COM_READ_RAW */
3201 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3204 long count, minCount, finalCount;
3208 smb_t *smbp = (smb_t*) inp;
3210 cm_user_t *userp = NULL;
3213 char *rawBuf = NULL;
3218 fd = smb_GetSMBParm(inp, 0);
3219 count = smb_GetSMBParm(inp, 3);
3220 minCount = smb_GetSMBParm(inp, 4);
3221 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3223 if (*inp->wctp == 10) {
3224 /* we were sent a request with 64-bit file offsets */
3225 #ifdef AFS_LARGEFILES
3226 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3228 if (LargeIntegerLessThanZero(offset)) {
3229 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3233 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3234 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3237 offset.HighPart = 0;
3241 /* we were sent a request with 32-bit file offsets */
3242 offset.HighPart = 0;
3245 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3246 fd, offset.HighPart, offset.LowPart, count);
3248 fidp = smb_FindFID(vcp, fd, 0);
3252 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3253 smb_CloseFID(vcp, fidp, NULL, 0);
3254 code = CM_ERROR_NOSUCHFILE;
3261 LARGE_INTEGER LOffset, LLength;
3264 key = cm_GenerateKey(vcp->vcID, pid, fd);
3266 LOffset.HighPart = offset.HighPart;
3267 LOffset.LowPart = offset.LowPart;
3268 LLength.HighPart = 0;
3269 LLength.LowPart = count;
3271 lock_ObtainWrite(&fidp->scp->rw);
3272 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3273 lock_ReleaseWrite(&fidp->scp->rw);
3279 lock_ObtainMutex(&smb_RawBufLock);
3281 /* Get a raw buf, from head of list */
3282 rawBuf = smb_RawBufs;
3283 smb_RawBufs = *(char **)smb_RawBufs;
3285 lock_ReleaseMutex(&smb_RawBufLock);
3289 lock_ObtainMutex(&fidp->mx);
3290 if (fidp->flags & SMB_FID_IOCTL)
3292 lock_ReleaseMutex(&fidp->mx);
3293 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3295 /* Give back raw buffer */
3296 lock_ObtainMutex(&smb_RawBufLock);
3297 *((char **) rawBuf) = smb_RawBufs;
3299 smb_RawBufs = rawBuf;
3300 lock_ReleaseMutex(&smb_RawBufLock);
3303 lock_ReleaseMutex(&fidp->mx);
3304 smb_ReleaseFID(fidp);
3307 lock_ReleaseMutex(&fidp->mx);
3309 userp = smb_GetUserFromVCP(vcp, inp);
3311 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3317 cm_ReleaseUser(userp);
3320 smb_ReleaseFID(fidp);
3324 memset((char *)ncbp, 0, sizeof(NCB));
3326 ncbp->ncb_length = (unsigned short) finalCount;
3327 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3328 ncbp->ncb_lana_num = vcp->lana;
3329 ncbp->ncb_command = NCBSEND;
3330 ncbp->ncb_buffer = rawBuf;
3332 code = Netbios(ncbp);
3334 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3337 /* Give back raw buffer */
3338 lock_ObtainMutex(&smb_RawBufLock);
3339 *((char **) rawBuf) = smb_RawBufs;
3341 smb_RawBufs = rawBuf;
3342 lock_ReleaseMutex(&smb_RawBufLock);
3348 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3350 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3355 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3357 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3362 /* SMB_COM_NEGOTIATE */
3363 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3370 int VistaProtoIndex;
3371 int protoIndex; /* index we're using */
3376 char protocol_array[10][1024]; /* protocol signature of the client */
3377 int caps; /* capabilities */
3380 TIME_ZONE_INFORMATION tzi;
3382 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3385 namep = smb_GetSMBData(inp, &dbytes);
3388 coreProtoIndex = -1; /* not found */
3391 VistaProtoIndex = -1;
3392 while(namex < dbytes) {
3393 osi_Log1(smb_logp, "Protocol %s",
3394 osi_LogSaveString(smb_logp, namep+1));
3395 strcpy(protocol_array[tcounter], namep+1);
3397 /* namep points at the first protocol, or really, a 0x02
3398 * byte preceding the null-terminated ASCII name.
3400 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3401 coreProtoIndex = tcounter;
3403 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3404 v3ProtoIndex = tcounter;
3406 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3407 NTProtoIndex = tcounter;
3409 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3410 VistaProtoIndex = tcounter;
3413 /* compute size of protocol entry */
3414 entryLength = (int)strlen(namep+1);
3415 entryLength += 2; /* 0x02 bytes and null termination */
3417 /* advance over this protocol entry */
3418 namex += entryLength;
3419 namep += entryLength;
3420 tcounter++; /* which proto entry we're looking at */
3423 lock_ObtainMutex(&vcp->mx);
3425 if (VistaProtoIndex != -1) {
3426 protoIndex = VistaProtoIndex;
3427 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3430 if (NTProtoIndex != -1) {
3431 protoIndex = NTProtoIndex;
3432 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3434 else if (v3ProtoIndex != -1) {
3435 protoIndex = v3ProtoIndex;
3436 vcp->flags |= SMB_VCFLAG_USEV3;
3438 else if (coreProtoIndex != -1) {
3439 protoIndex = coreProtoIndex;
3440 vcp->flags |= SMB_VCFLAG_USECORE;
3442 else protoIndex = -1;
3443 lock_ReleaseMutex(&vcp->mx);
3445 if (protoIndex == -1)
3446 return CM_ERROR_INVAL;
3447 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3448 smb_SetSMBParm(outp, 0, protoIndex);
3449 if (smb_authType != SMB_AUTH_NONE) {
3450 smb_SetSMBParmByte(outp, 1,
3451 NEGOTIATE_SECURITY_USER_LEVEL |
3452 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3454 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3456 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3457 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3458 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3459 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3460 /* The session key is not a well documented field however most clients
3461 * will echo back the session key to the server. Currently we are using
3462 * the same value for all sessions. We should generate a random value
3463 * and store it into the vcp
3465 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3466 smb_SetSMBParm(outp, 8, 1);
3468 * Tried changing the capabilities to support for W2K - defect 117695
3469 * Maybe something else needs to be changed here?
3473 smb_SetSMBParmLong(outp, 9, 0x43fd);
3475 smb_SetSMBParmLong(outp, 9, 0x251);
3478 * 32-bit error codes *
3484 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3486 NTNEGOTIATE_CAPABILITY_DFS |
3488 #ifdef AFS_LARGEFILES
3489 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3491 NTNEGOTIATE_CAPABILITY_NTFIND |
3492 NTNEGOTIATE_CAPABILITY_RAWMODE |
3493 NTNEGOTIATE_CAPABILITY_NTSMB;
3495 if ( smb_authType == SMB_AUTH_EXTENDED )
3496 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3499 if ( smb_UseUnicode ) {
3500 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3504 smb_SetSMBParmLong(outp, 9, caps);
3506 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3507 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3508 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3510 GetTimeZoneInformation(&tzi);
3511 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3513 if (smb_authType == SMB_AUTH_NTLM) {
3514 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3515 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3516 /* paste in encryption key */
3517 datap = smb_GetSMBData(outp, NULL);
3518 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3519 /* and the faux domain name */
3520 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3521 datap + MSV1_0_CHALLENGE_LENGTH,
3522 sizeof(outp->data)/sizeof(char) - (datap - outp->data));
3523 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3527 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3529 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3531 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3533 datap = smb_GetSMBData(outp, NULL);
3534 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3537 datap += sizeof(smb_ServerGUID);
3538 memcpy(datap, secBlob, secBlobLength);
3542 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3543 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3546 else if (v3ProtoIndex != -1) {
3547 smb_SetSMBParm(outp, 0, protoIndex);
3549 /* NOTE: Extended authentication cannot be negotiated with v3
3550 * therefore we fail over to NTLM
3552 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3553 smb_SetSMBParm(outp, 1,
3554 NEGOTIATE_SECURITY_USER_LEVEL |
3555 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3557 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3559 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3560 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3561 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3562 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3563 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3564 smb_SetSMBParm(outp, 7, 1);
3566 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3567 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3568 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3570 GetTimeZoneInformation(&tzi);
3571 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3573 /* NOTE: Extended authentication cannot be negotiated with v3
3574 * therefore we fail over to NTLM
3576 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3577 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3578 smb_SetSMBParm(outp, 12, 0); /* resvd */
3579 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3580 datap = smb_GetSMBData(outp, NULL);
3581 /* paste in a new encryption key */
3582 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3583 /* and the faux domain name */
3584 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3585 datap + MSV1_0_CHALLENGE_LENGTH,
3586 sizeof(outp->data)/sizeof(char) - (datap - outp->data));
3588 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3589 smb_SetSMBParm(outp, 12, 0); /* resvd */
3590 smb_SetSMBDataLength(outp, 0);
3593 else if (coreProtoIndex != -1) { /* not really supported anymore */
3594 smb_SetSMBParm(outp, 0, protoIndex);
3595 smb_SetSMBDataLength(outp, 0);
3600 void smb_CheckVCs(void)
3602 smb_vc_t * vcp, *nextp;
3603 smb_packet_t * outp = GetPacket();
3606 lock_ObtainWrite(&smb_rctLock);
3607 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3609 if (vcp->magic != SMB_VC_MAGIC)
3610 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3611 __FILE__, __LINE__);
3615 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3618 smb_HoldVCNoLock(vcp);
3620 smb_HoldVCNoLock(nextp);
3621 smb_FormatResponsePacket(vcp, NULL, outp);
3622 smbp = (smb_t *)outp;
3623 outp->inCom = smbp->com = 0x2b /* Echo */;
3631 smb_SetSMBParm(outp, 0, 0);
3632 smb_SetSMBDataLength(outp, 0);
3633 lock_ReleaseWrite(&smb_rctLock);
3635 smb_SendPacket(vcp, outp);
3637 lock_ObtainWrite(&smb_rctLock);
3638 smb_ReleaseVCNoLock(vcp);
3640 smb_ReleaseVCNoLock(nextp);
3642 lock_ReleaseWrite(&smb_rctLock);
3643 smb_FreePacket(outp);
3646 void smb_Daemon(void *parmp)
3648 afs_uint32 count = 0;
3649 smb_username_t **unpp;
3652 while(smbShutdownFlag == 0) {
3656 if (smbShutdownFlag == 1)
3659 if ((count % 72) == 0) { /* every five minutes */
3661 time_t old_localZero = smb_localZero;
3663 /* Initialize smb_localZero */
3664 myTime.tm_isdst = -1; /* compute whether on DST or not */
3665 myTime.tm_year = 70;
3671 smb_localZero = mktime(&myTime);
3673 #ifndef USE_NUMERIC_TIME_CONV
3674 smb_CalculateNowTZ();
3675 #endif /* USE_NUMERIC_TIME_CONV */
3676 #ifdef AFS_FREELANCE
3677 if ( smb_localZero != old_localZero )
3678 cm_noteLocalMountPointChange();
3684 /* GC smb_username_t objects that will no longer be used */
3686 lock_ObtainWrite(&smb_rctLock);
3687 for ( unpp=&usernamesp; *unpp; ) {
3689 smb_username_t *unp;
3691 lock_ObtainMutex(&(*unpp)->mx);
3692 if ( (*unpp)->refCount > 0 ||
3693 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3694 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3696 else if (!smb_LogoffTokenTransfer ||
3697 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3699 lock_ReleaseMutex(&(*unpp)->mx);
3707 lock_FinalizeMutex(&unp->mx);
3713 cm_ReleaseUser(userp);
3715 unpp = &(*unpp)->nextp;
3718 lock_ReleaseWrite(&smb_rctLock);
3720 /* XXX GC dir search entries */
3724 void smb_WaitingLocksDaemon()
3726 smb_waitingLockRequest_t *wlRequest, *nwlRequest;
3727 smb_waitingLock_t *wl, *wlNext;
3730 smb_packet_t *inp, *outp;
3734 while (smbShutdownFlag == 0) {
3735 lock_ObtainWrite(&smb_globalLock);
3736 nwlRequest = smb_allWaitingLocks;
3737 if (nwlRequest == NULL) {
3738 osi_SleepW((LONG_PTR)&smb_allWaitingLocks, &smb_globalLock);
3743 osi_Log0(smb_logp, "smb_WaitingLocksDaemon starting wait lock check");
3750 lock_ObtainWrite(&smb_globalLock);
3752 osi_Log1(smb_logp, " Checking waiting lock request %p", nwlRequest);
3754 wlRequest = nwlRequest;
3755 nwlRequest = (smb_waitingLockRequest_t *) osi_QNext(&wlRequest->q);
3756 lock_ReleaseWrite(&smb_globalLock);
3760 for (wl = wlRequest->locks; wl; wl = (smb_waitingLock_t *) osi_QNext(&wl->q)) {
3761 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3764 if (wl->state == SMB_WAITINGLOCKSTATE_CANCELLED) {
3765 code = CM_ERROR_LOCK_NOT_GRANTED;
3769 osi_assertx(wl->state != SMB_WAITINGLOCKSTATE_ERROR, "!SMB_WAITINGLOCKSTATE_ERROR");
3771 /* wl->state is either _DONE or _WAITING. _ERROR
3772 would no longer be on the queue. */
3773 code = cm_RetryLock( wl->lockp,
3774 !!(wlRequest->vcp->flags & SMB_VCFLAG_ALREADYDEAD) );
3777 wl->state = SMB_WAITINGLOCKSTATE_DONE;
3778 } else if (code != CM_ERROR_WOULDBLOCK) {
3779 wl->state = SMB_WAITINGLOCKSTATE_ERROR;
3784 if (code == CM_ERROR_WOULDBLOCK) {
3787 if (wlRequest->msTimeout != 0xffffffff
3788 && ((osi_Time() - wlRequest->start_t) * 1000 > wlRequest->msTimeout))
3800 osi_Log1(smb_logp, "smb_WaitingLocksDaemon discarding lock req %p",
3803 scp = wlRequest->scp;
3804 osi_Log2(smb_logp,"smb_WaitingLocksDaemon wlRequest 0x%p scp 0x%p", wlRequest, scp);
3808 lock_ObtainWrite(&scp->rw);
3810 for (wl = wlRequest->locks; wl; wl = wlNext) {
3811 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3813 if (wl->state == SMB_WAITINGLOCKSTATE_DONE)
3814 cm_Unlock(scp, wlRequest->lockType, wl->LOffset,
3815 wl->LLength, wl->key, NULL, &req);
3817 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3822 lock_ReleaseWrite(&scp->rw);
3826 osi_Log1(smb_logp, "smb_WaitingLocksDaemon granting lock req %p",
3829 for (wl = wlRequest->locks; wl; wl = wlNext) {
3830 wlNext = (smb_waitingLock_t *) osi_QNext(&wl->q);
3831 osi_QRemove((osi_queue_t **) &wlRequest->locks, &wl->q);
3836 vcp = wlRequest->vcp;
3837 inp = wlRequest->inp;
3838 outp = wlRequest->outp;
3840 ncbp->ncb_length = inp->ncb_length;
3841 inp->spacep = cm_GetSpace();
3843 /* Remove waitingLock from list */
3844 lock_ObtainWrite(&smb_globalLock);
3845 osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
3847 lock_ReleaseWrite(&smb_globalLock);
3849 /* Resume packet processing */
3851 smb_SetSMBDataLength(outp, 0);
3852 outp->flags |= SMB_PACKETFLAG_SUSPENDED;
3853 outp->resumeCode = code;
3855 smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
3858 cm_FreeSpace(inp->spacep);
3859 smb_FreePacket(inp);
3860 smb_FreePacket(outp);
3862 cm_ReleaseSCache(wlRequest->scp);
3865 } while (nwlRequest && smbShutdownFlag == 0);
3870 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3872 osi_Log0(smb_logp, "SMB receive get disk attributes");
3874 smb_SetSMBParm(outp, 0, 32000);
3875 smb_SetSMBParm(outp, 1, 64);
3876 smb_SetSMBParm(outp, 2, 1024);
3877 smb_SetSMBParm(outp, 3, 30000);
3878 smb_SetSMBParm(outp, 4, 0);
3879 smb_SetSMBDataLength(outp, 0);
3883 /* SMB_COM_TREE_CONNECT */
3884 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
3888 unsigned short newTid;
3889 clientchar_t shareName[AFSPATHMAX];
3890 clientchar_t *sharePath;
3893 clientchar_t *pathp;
3896 osi_Log0(smb_logp, "SMB receive tree connect");
3898 /* parse input parameters */
3901 tbp = smb_GetSMBData(inp, NULL);
3902 pathp = smb_ParseASCIIBlock(inp, tbp, &tbp, SMB_STRF_ANSIPATH);
3904 tp = cm_ClientStrRChr(pathp, '\\');
3906 return CM_ERROR_BADSMB;
3907 cm_ClientStrCpy(shareName, lengthof(shareName), tp+1);
3909 lock_ObtainMutex(&vcp->mx);
3910 newTid = vcp->tidCounter++;
3911 lock_ReleaseMutex(&vcp->mx);
3913 tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
3914 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
3915 userp = smb_GetUserFromUID(uidp);
3916 shareFound = smb_FindShare(vcp, uidp, shareName, &sharePath);
3918 smb_ReleaseUID(uidp);
3920 smb_ReleaseTID(tidp, FALSE);
3921 return CM_ERROR_BADSHARENAME;
3923 lock_ObtainMutex(&tidp->mx);
3924 tidp->userp = userp;
3925 tidp->pathname = sharePath;
3926 lock_ReleaseMutex(&tidp->mx);
3927 smb_ReleaseTID(tidp, FALSE);
3929 smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
3930 smb_SetSMBParm(rsp, 1, newTid);
3931 smb_SetSMBDataLength(rsp, 0);
3933 osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
3937 /* set maskp to the mask part of the incoming path.
3938 * Mask is 11 bytes long (8.3 with the dot elided).
3939 * Returns true if succeeds with a valid name, otherwise it does
3940 * its best, but returns false.
3942 int smb_Get8Dot3MaskFromPath(clientchar_t *maskp, clientchar_t *pathp)
3950 /* starts off valid */
3953 /* mask starts out all blanks */
3954 memset(maskp, ' ', 11);
3957 /* find last backslash, or use whole thing if there is none */
3958 tp = cm_ClientStrRChr(pathp, '\\');
3962 tp++; /* skip slash */
3966 /* names starting with a dot are illegal */
3974 if (tc == '.' || tc == '"')
3982 /* if we get here, tp point after the dot */
3983 up = maskp+8; /* ext goes here */
3990 if (tc == '.' || tc == '"')
3993 /* copy extension if not too long */
4003 int smb_Match8Dot3Mask(clientchar_t *unixNamep, clientchar_t *maskp)
4005 clientchar_t umask[11];
4013 /* XXX redo this, calling cm_MatchMask with a converted mask */
4015 valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
4019 /* otherwise, we have a valid 8.3 name; see if we have a match,
4020 * treating '?' as a wildcard in maskp (but not in the file name).
4022 tp1 = umask; /* real name, in mask format */
4023 tp2 = maskp; /* mask, in mask format */
4024 for(i=0; i<11; i++) {
4025 tc1 = *tp1++; /* clientchar_t from real name */
4026 tc2 = *tp2++; /* clientchar_t from mask */
4027 tc1 = (clientchar_t) cm_foldUpper[(clientchar_t)tc1];
4028 tc2 = (clientchar_t) cm_foldUpper[(clientchar_t)tc2];
4031 if (tc2 == '?' && tc1 != ' ')
4038 /* we got a match */
4042 clientchar_t *smb_FindMask(clientchar_t *pathp)
4046 tp = cm_ClientStrRChr(pathp, '\\'); /* find last slash */
4049 return tp+1; /* skip the slash */
4051 return pathp; /* no slash, return the entire path */
4054 /* SMB_COM_SEARCH for a volume label
4056 (This is called from smb_ReceiveCoreSearchDir() and not an actual
4057 dispatch function.) */
4058 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4060 clientchar_t *pathp;
4062 clientchar_t mask[12];
4063 unsigned char *statBlockp;
4064 unsigned char initStatBlock[21];
4067 osi_Log0(smb_logp, "SMB receive search volume");
4069 /* pull pathname and stat block out of request */
4070 tp = smb_GetSMBData(inp, NULL);
4071 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4072 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4073 osi_assertx(pathp != NULL, "null path");
4074 statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
4075 osi_assertx(statBlockp != NULL, "null statBlock");
4077 statBlockp = initStatBlock;
4081 /* for returning to caller */
4082 smb_Get8Dot3MaskFromPath(mask, pathp);
4084 smb_SetSMBParm(outp, 0, 1); /* we're returning one entry */
4085 tp = smb_GetSMBData(outp, NULL);
4087 *tp++ = 43; /* bytes in a dir entry */
4088 *tp++ = 0; /* high byte in counter */
4090 /* now marshall the dir entry, starting with the search status */
4091 *tp++ = statBlockp[0]; /* Reserved */
4092 memcpy(tp, mask, 11); tp += 11; /* FileName */
4094 /* now pass back server use info, with 1st byte non-zero */
4096 memset(tp, 0, 4); tp += 4; /* reserved for server use */
4098 memcpy(tp, statBlockp+17, 4); tp += 4; /* reserved for consumer */
4100 *tp++ = 0x8; /* attribute: volume */
4110 /* 4 byte file size */
4116 /* The filename is a UCHAR buffer that is ASCII even if Unicode
4119 /* finally, null-terminated 8.3 pathname, which we set to AFS */
4120 memset(tp, ' ', 13);
4123 /* set the length of the data part of the packet to 43 + 3, for the dir
4124 * entry plus the 5 and the length fields.
4126 smb_SetSMBDataLength(outp, 46);
4131 smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
4132 clientchar_t * tidPathp, clientchar_t * relPathp,
4133 cm_user_t *userp, cm_req_t *reqp)
4141 smb_dirListPatch_t *patchp;
4142 smb_dirListPatch_t *npatchp;
4143 clientchar_t path[AFSPATHMAX];
4145 for (patchp = *dirPatchespp; patchp; patchp =
4146 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
4148 dptr = patchp->dptr;
4150 cm_ClientStrPrintfN(path, AFSPATHMAX, _C("%s\\%s"),
4151 relPathp ? relPathp : _C(""), patchp->dep->name);
4152 reqp->relPathp = path;
4153 reqp->tidPathp = tidPathp;
4155 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
4156 reqp->relPathp = reqp->tidPathp = NULL;
4159 if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
4160 *dptr++ = SMB_ATTR_HIDDEN;
4163 lock_ObtainWrite(&scp->rw);
4164 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
4165 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4167 lock_ReleaseWrite(&scp->rw);
4168 cm_ReleaseSCache(scp);
4169 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4170 *dptr++ = SMB_ATTR_HIDDEN;
4174 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4176 lock_ConvertWToR(&scp->rw);
4177 attr = smb_Attributes(scp);
4178 /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
4179 if (patchp->flags & SMB_DIRLISTPATCH_DOTFILE)
4180 attr |= SMB_ATTR_HIDDEN;
4184 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
4187 shortTemp = (unsigned short) (dosTime & 0xffff);
4188 *((u_short *)dptr) = shortTemp;
4191 /* and copy out date */
4192 shortTemp = (unsigned short) ((dosTime>>16) & 0xffff);
4193 *((u_short *)dptr) = shortTemp;
4196 /* copy out file length */
4197 *((u_long *)dptr) = scp->length.LowPart;
4199 lock_ReleaseRead(&scp->rw);
4200 cm_ReleaseSCache(scp);
4203 /* now free the patches */
4204 for (patchp = *dirPatchespp; patchp; patchp = npatchp) {
4205 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
4209 /* and mark the list as empty */
4210 *dirPatchespp = NULL;
4215 /* SMB_COM_SEARCH */
4216 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4222 clientchar_t *pathp;
4223 cm_dirEntry_t *dep = 0;
4225 smb_dirListPatch_t *dirListPatchesp;
4226 smb_dirListPatch_t *curPatchp;
4230 osi_hyper_t dirLength;
4231 osi_hyper_t bufferOffset;
4232 osi_hyper_t curOffset;
4234 unsigned char *inCookiep;
4235 smb_dirSearch_t *dsp;
4239 unsigned long clientCookie;
4240 cm_pageHeader_t *pageHeaderp;
4241 cm_user_t *userp = NULL;
4243 clientchar_t mask[12];
4245 long nextEntryCookie;
4246 int numDirChunks; /* # of 32 byte dir chunks in this entry */
4247 char resByte; /* reserved byte from the cookie */
4248 char *op; /* output data ptr */
4249 char *origOp; /* original value of op */
4250 cm_space_t *spacep; /* for pathname buffer */
4254 clientchar_t *tidPathp = 0;
4261 maxCount = smb_GetSMBParm(inp, 0);
4263 dirListPatchesp = NULL;
4265 caseFold = CM_FLAG_CASEFOLD;
4267 tp = smb_GetSMBData(inp, NULL);
4268 pathp = smb_ParseASCIIBlock(inp, tp, &tp,
4269 SMB_STRF_ANSIPATH|SMB_STRF_FORCEASCII);
4270 inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
4272 /* bail out if request looks bad */
4273 if (!tp || !pathp) {
4274 return CM_ERROR_BADSMB;
4277 /* We can handle long names */
4278 if (vcp->flags & SMB_VCFLAG_USENT)
4279 ((smb_t *)outp)->flg2 |= SMB_FLAGS2_IS_LONG_NAME;
4281 /* make sure we got a whole search status */
4282 if (dataLength < 21) {
4283 nextCookie = 0; /* start at the beginning of the dir */
4286 attribute = smb_GetSMBParm(inp, 1);
4288 /* handle volume info in another function */
4289 if (attribute & 0x8)
4290 return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
4292 osi_Log2(smb_logp, "SMB receive search dir count %d [%S]",
4293 maxCount, osi_LogSaveClientString(smb_logp, pathp));
4295 if (*pathp == 0) { /* null pathp, treat as root dir */
4296 if (!(attribute & SMB_ATTR_DIRECTORY)) /* exclude dirs */
4297 return CM_ERROR_NOFILES;
4301 dsp = smb_NewDirSearch(0);
4302 dsp->attribute = attribute;
4303 smb_Get8Dot3MaskFromPath(mask, pathp);
4304 memcpy(dsp->mask, mask, 12);
4306 /* track if this is likely to match a lot of entries */
4307 if (smb_IsStarMask(mask))
4312 /* pull the next cookie value out of the search status block */
4313 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
4314 + (inCookiep[16]<<24);
4315 dsp = smb_FindDirSearch(inCookiep[12]);
4317 /* can't find dir search status; fatal error */
4318 osi_Log3(smb_logp, "SMB receive search dir bad cookie: cookie %d nextCookie %u [%S]",
4319 inCookiep[12], nextCookie, osi_LogSaveClientString(smb_logp, pathp));
4320 return CM_ERROR_BADFD;
4322 attribute = dsp->attribute;
4323 resByte = inCookiep[0];
4325 /* copy out client cookie, in host byte order. Don't bother
4326 * interpreting it, since we're just passing it through, anyway.
4328 memcpy(&clientCookie, &inCookiep[17], 4);
4330 memcpy(mask, dsp->mask, 12);
4332 /* assume we're doing a star match if it has continued for more
4338 osi_Log3(smb_logp, "SMB search dir cookie 0x%x, connection %d, attr 0x%x",
4339 nextCookie, dsp->cookie, attribute);
4341 userp = smb_GetUserFromVCP(vcp, inp);
4343 /* try to get the vnode for the path name next */
4344 lock_ObtainMutex(&dsp->mx);
4347 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (1) dsp 0x%p scp 0x%p", dsp, scp);
4351 spacep = inp->spacep;
4352 smb_StripLastComponent(spacep->wdata, NULL, pathp);
4353 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4355 lock_ReleaseMutex(&dsp->mx);
4356 cm_ReleaseUser(userp);
4357 smb_DeleteDirSearch(dsp);
4358 smb_ReleaseDirSearch(dsp);
4359 return CM_ERROR_NOFILES;
4361 cm_ClientStrCpy(dsp->tidPath, lengthof(dsp->tidPath), tidPathp ? tidPathp : _C("/"));
4362 cm_ClientStrCpy(dsp->relPath, lengthof(dsp->relPath), spacep->wdata);
4364 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
4365 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
4368 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
4371 pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, spacep->wdata);
4372 cm_ReleaseSCache(scp);
4373 lock_ReleaseMutex(&dsp->mx);
4374 cm_ReleaseUser(userp);
4375 smb_DeleteDirSearch(dsp);
4376 smb_ReleaseDirSearch(dsp);
4377 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4378 return CM_ERROR_PATH_NOT_COVERED;
4380 return CM_ERROR_BADSHARENAME;
4382 #endif /* DFS_SUPPORT */
4385 osi_Log2(smb_logp,"smb_ReceiveCoreSearchDir (2) dsp 0x%p scp 0x%p", dsp, scp);
4386 /* we need one hold for the entry we just stored into,
4387 * and one for our own processing. When we're done with this
4388 * function, we'll drop the one for our own processing.
4389 * We held it once from the namei call, and so we do another hold
4393 lock_ObtainWrite(&scp->rw);
4394 if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
4395 && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
4396 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
4397 dsp->flags |= SMB_DIRSEARCH_BULKST;
4398 dsp->scp->bulkStatProgress = hzero;
4400 lock_ReleaseWrite(&scp->rw);
4403 lock_ReleaseMutex(&dsp->mx);
4405 cm_ReleaseUser(userp);
4406 smb_DeleteDirSearch(dsp);
4407 smb_ReleaseDirSearch(dsp);
4411 /* reserves space for parameter; we'll adjust it again later to the
4412 * real count of the # of entries we returned once we've actually
4413 * assembled the directory listing.
4415 smb_SetSMBParm(outp, 0, 0);
4417 /* get the directory size */
4418 lock_ObtainWrite(&scp->rw);
4419 code = cm_SyncOp(scp, NULL, userp, &req, 0,
4420 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4422 lock_ReleaseWrite(&scp->rw);
4423 cm_ReleaseSCache(scp);
4424 cm_ReleaseUser(userp);
4425 smb_DeleteDirSearch(dsp);
4426 smb_ReleaseDirSearch(dsp);
4430 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4432 dirLength = scp->length;
4434 bufferOffset.LowPart = bufferOffset.HighPart = 0;
4435 curOffset.HighPart = 0;
4436 curOffset.LowPart = nextCookie;
4437 origOp = op = smb_GetSMBData(outp, NULL);
4438 /* and write out the basic header */
4439 *op++ = 5; /* variable block */
4440 op += 2; /* skip vbl block length; we'll fill it in later */
4444 clientchar_t *actualName;
4445 clientchar_t shortName[13];
4446 clientchar_t *shortNameEnd;
4448 /* make sure that curOffset.LowPart doesn't point to the first
4449 * 32 bytes in the 2nd through last dir page, and that it doesn't
4450 * point at the first 13 32-byte chunks in the first dir page,
4451 * since those are dir and page headers, and don't contain useful
4454 temp = curOffset.LowPart & (2048-1);
4455 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
4456 /* we're in the first page */
4457 if (temp < 13*32) temp = 13*32;
4460 /* we're in a later dir page */
4461 if (temp < 32) temp = 32;
4464 /* make sure the low order 5 bits are zero */
4467 /* now put temp bits back ito curOffset.LowPart */
4468 curOffset.LowPart &= ~(2048-1);
4469 curOffset.LowPart |= temp;
4471 /* check if we've returned all the names that will fit in the
4474 if (returnedNames >= maxCount) {
4475 osi_Log2(smb_logp, "SMB search dir returnedNames %d >= maxCount %d",
4476 returnedNames, maxCount);
4480 /* check if we've passed the dir's EOF */
4481 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
4483 /* see if we can use the bufferp we have now; compute in which page
4484 * the current offset would be, and check whether that's the offset
4485 * of the buffer we have. If not, get the buffer.
4487 thyper.HighPart = curOffset.HighPart;
4488 thyper.LowPart = curOffset.LowPart & ~(cm_data.buf_blockSize-1);
4489 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4492 buf_Release(bufferp);
4495 lock_ReleaseWrite(&scp->rw);
4496 code = buf_Get(scp, &thyper, &bufferp);
4497 lock_ObtainMutex(&dsp->mx);
4499 /* now, if we're doing a star match, do bulk fetching of all of
4500 * the status info for files in the dir.
4503 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4504 lock_ObtainWrite(&scp->rw);
4505 if ((dsp->flags & SMB_DIRSEARCH_BULKST) &&
4506 LargeIntegerGreaterThanOrEqualTo(thyper,
4507 scp->bulkStatProgress)) {
4508 /* Don't bulk stat if risking timeout */
4509 int now = GetTickCount();
4510 if (now - req.startTime > RDRtimeout * 1000) {
4511 scp->bulkStatProgress = thyper;
4512 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
4513 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
4514 dsp->scp->bulkStatProgress = hzero;
4516 code = cm_TryBulkStat(scp, &thyper, userp, &req);
4519 lock_ObtainWrite(&scp->rw);
4521 lock_ReleaseMutex(&dsp->mx);
4523 osi_Log2(smb_logp, "SMB search dir buf_Get scp %x failed %d", scp, code);
4527 bufferOffset = thyper;
4529 /* now get the data in the cache */
4531 code = cm_SyncOp(scp, bufferp, userp, &req,
4533 CM_SCACHESYNC_NEEDCALLBACK |
4534 CM_SCACHESYNC_READ);
4536 osi_Log2(smb_logp, "SMB search dir cm_SyncOp scp %x failed %d", scp, code);
4540 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
4542 if (cm_HaveBuffer(scp, bufferp, 0)) {
4543 osi_Log2(smb_logp, "SMB search dir !HaveBuffer scp %x bufferp %x", scp, bufferp);
4547 /* otherwise, load the buffer and try again */
4548 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4550 osi_Log3(smb_logp, "SMB search dir cm_GetBuffer failed scp %x bufferp %x code %d",
4551 scp, bufferp, code);
4556 buf_Release(bufferp);
4560 } /* if (wrong buffer) ... */
4562 /* now we have the buffer containing the entry we're interested in; copy
4563 * it out if it represents a non-deleted entry.
4565 entryInDir = curOffset.LowPart & (2048-1);
4566 entryInBuffer = curOffset.LowPart & (cm_data.buf_blockSize - 1);
4568 /* page header will help tell us which entries are free. Page header
4569 * can change more often than once per buffer, since AFS 3 dir page size
4570 * may be less than (but not more than a buffer package buffer.
4572 temp = curOffset.LowPart & (cm_data.buf_blockSize - 1); /* only look intra-buffer */
4573 temp &= ~(2048 - 1); /* turn off intra-page bits */
4574 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
4576 /* now determine which entry we're looking at in the page. If it is
4577 * free (there's a free bitmap at the start of the dir), we should
4578 * skip these 32 bytes.
4580 slotInPage = (entryInDir & 0x7e0) >> 5;
4581 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
4582 /* this entry is free */
4583 numDirChunks = 1; /* only skip this guy */
4587 tp = bufferp->datap + entryInBuffer;
4588 dep = (cm_dirEntry_t *) tp; /* now points to AFS3 dir entry */
4590 /* while we're here, compute the next entry's location, too,
4591 * since we'll need it when writing out the cookie into the dir
4594 * XXXX Probably should do more sanity checking.
4596 numDirChunks = cm_NameEntries(dep->name, NULL);
4598 /* compute the offset of the cookie representing the next entry */
4599 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
4601 /* Compute 8.3 name if necessary */
4602 actualName = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
4603 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
4605 cm_Gen8Dot3NameInt(dep->name, &dep->fid, shortName, &shortNameEnd);
4606 actualName = shortName;
4609 osi_Log3(smb_logp, "SMB search dir vn %d name %s (%S)",
4610 dep->fid.vnode, osi_LogSaveString(smb_logp, dep->name),
4611 osi_LogSaveClientString(smb_logp, actualName));
4613 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
4614 /* this is one of the entries to use: it is not deleted
4615 * and it matches the star pattern we're looking for.
4618 /* Eliminate entries that don't match requested
4621 /* no hidden files */
4622 if (smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName)) {
4623 osi_Log0(smb_logp, "SMB search dir skipping hidden");
4627 if (!(dsp->attribute & SMB_ATTR_DIRECTORY)) /* no directories */
4629 /* We have already done the cm_TryBulkStat above */
4630 cm_SetFid(&fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4631 fileType = cm_FindFileType(&fid);
4632 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
4633 "has filetype %d", osi_LogSaveString(smb_logp, dep->name),
4635 if (fileType == CM_SCACHETYPE_DIRECTORY ||
4636 fileType == CM_SCACHETYPE_MOUNTPOINT ||
4637 fileType == CM_SCACHETYPE_DFSLINK ||
4638 fileType == CM_SCACHETYPE_INVALID)
4639 osi_Log0(smb_logp, "SMB search dir skipping directory or bad link");
4644 memcpy(op, mask, 11); op += 11;
4645 *op++ = (unsigned char) dsp->cookie; /* they say it must be non-zero */
4646 *op++ = (unsigned char)(nextEntryCookie & 0xff);
4647 *op++ = (unsigned char)((nextEntryCookie>>8) & 0xff);
4648 *op++ = (unsigned char)((nextEntryCookie>>16) & 0xff);
4649 *op++ = (unsigned char)((nextEntryCookie>>24) & 0xff);
4650 memcpy(op, &clientCookie, 4); op += 4;
4652 /* now we emit the attribute. This is sort of tricky,
4653 * since we need to really stat the file to find out
4654 * what type of entry we've got. Right now, we're
4655 * copying out data from a buffer, while holding the
4656 * scp locked, so it isn't really convenient to stat
4657 * something now. We'll put in a place holder now,
4658 * and make a second pass before returning this to get
4659 * the real attributes. So, we just skip the data for
4660 * now, and adjust it later. We allocate a patch
4661 * record to make it easy to find this point later.
4662 * The replay will happen at a time when it is safe to
4663 * unlock the directory.
4665 curPatchp = malloc(sizeof(*curPatchp));
4666 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
4667 curPatchp->dptr = op;
4668 cm_SetFid(&curPatchp->fid, scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique));
4670 /* do hidden attribute here since name won't be around when applying
4674 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
4675 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
4677 curPatchp->flags = 0;
4679 op += 9; /* skip attr, time, date and size */
4681 /* zero out name area. The spec says to pad with
4682 * spaces, but Samba doesn't, and neither do we.
4686 /* finally, we get to copy out the name; we know that
4687 * it fits in 8.3 or the pattern wouldn't match, but it
4688 * never hurts to be sure.
4690 cm_ClientStringToUtf8(actualName, -1, op, 13);
4691 if (smb_StoreAnsiFilenames)
4693 /* This is a UCHAR field, which is ASCII even if Unicode
4696 /* Uppercase if requested by client */
4697 if (!KNOWS_LONG_NAMES(inp))
4702 /* now, adjust the # of entries copied */
4704 } /* if we're including this name */
4707 /* and adjust curOffset to be where the new cookie is */
4708 thyper.HighPart = 0;
4709 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
4710 curOffset = LargeIntegerAdd(thyper, curOffset);
4711 } /* while copying data for dir listing */
4713 /* release the mutex */
4714 lock_ReleaseWrite(&scp->rw);
4716 buf_Release(bufferp);
4720 /* apply and free last set of patches; if not doing a star match, this
4721 * will be empty, but better safe (and freeing everything) than sorry.
4723 smb_ApplyDirListPatches(&dirListPatchesp, dsp->tidPath, dsp->relPath, userp, &req);
4725 /* special return code for unsuccessful search */
4726 if (code == 0 && dataLength < 21 && returnedNames == 0)
4727 code = CM_ERROR_NOFILES;
4729 osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
4730 returnedNames, code);
4733 smb_DeleteDirSearch(dsp);
4734 smb_ReleaseDirSearch(dsp);
4735 cm_ReleaseSCache(scp);
4736 cm_ReleaseUser(userp);
4740 /* finalize the output buffer */
4741 smb_SetSMBParm(outp, 0, returnedNames);
4742 temp = (long) (op - origOp);
4743 smb_SetSMBDataLength(outp, temp);
4745 /* the data area is a variable block, which has a 5 (already there)
4746 * followed by the length of the # of data bytes. We now know this to
4747 * be "temp," although that includes the 3 bytes of vbl block header.
4748 * Deduct for them and fill in the length field.
4750 temp -= 3; /* deduct vbl block info */
4751 osi_assertx(temp == (43 * returnedNames), "unexpected data length");
4752 origOp[1] = (unsigned char)(temp & 0xff);
4753 origOp[2] = (unsigned char)((temp>>8) & 0xff);
4754 if (returnedNames == 0)
4755 smb_DeleteDirSearch(dsp);
4756 smb_ReleaseDirSearch(dsp);
4757 cm_ReleaseSCache(scp);
4758 cm_ReleaseUser(userp);
4763 /* verify that this is a valid path to a directory. I don't know why they
4764 * don't use the get file attributes call.
4766 * SMB_COM_CHECK_DIRECTORY
4768 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4770 clientchar_t *pathp;
4772 cm_scache_t *rootScp;
4773 cm_scache_t *newScp;
4777 clientchar_t *tidPathp;
4783 pdata = smb_GetSMBData(inp, NULL);
4784 pathp = smb_ParseASCIIBlock(inp, pdata, NULL, SMB_STRF_ANSIPATH);
4786 return CM_ERROR_BADFD;
4787 osi_Log1(smb_logp, "SMB receive check path %S",
4788 osi_LogSaveClientString(smb_logp, pathp));
4790 rootScp = cm_data.rootSCachep;
4792 userp = smb_GetUserFromVCP(vcp, inp);
4794 caseFold = CM_FLAG_CASEFOLD;
4796 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4798 cm_ReleaseUser(userp);
4799 return CM_ERROR_NOSUCHPATH;
4801 code = cm_NameI(rootScp, pathp,
4802 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
4803 userp, tidPathp, &req, &newScp);
4806 cm_ReleaseUser(userp);
4811 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4812 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4813 cm_ReleaseSCache(newScp);
4814 cm_ReleaseUser(userp);
4815 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4816 return CM_ERROR_PATH_NOT_COVERED;
4818 return CM_ERROR_BADSHARENAME;
4820 #endif /* DFS_SUPPORT */
4822 /* now lock the vnode with a callback; returns with newScp locked */
4823 lock_ObtainWrite(&newScp->rw);
4824 code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
4825 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4827 if (code != CM_ERROR_NOACCESS) {
4828 lock_ReleaseWrite(&newScp->rw);
4829 cm_ReleaseSCache(newScp);
4830 cm_ReleaseUser(userp);
4834 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4837 attrs = smb_Attributes(newScp);
4839 if (!(attrs & SMB_ATTR_DIRECTORY))
4840 code = CM_ERROR_NOTDIR;
4842 lock_ReleaseWrite(&newScp->rw);
4844 cm_ReleaseSCache(newScp);
4845 cm_ReleaseUser(userp);
4849 /* SMB_COM_SET_INFORMATION */
4850 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4852 clientchar_t *pathp;
4854 cm_scache_t *rootScp;
4855 unsigned short attribute;
4857 cm_scache_t *newScp;
4861 clientchar_t *tidPathp;
4867 /* decode basic attributes we're passed */
4868 attribute = smb_GetSMBParm(inp, 0);
4869 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4871 datap = smb_GetSMBData(inp, NULL);
4872 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
4874 return CM_ERROR_BADSMB;
4876 osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
4877 dosTime, attribute);
4879 rootScp = cm_data.rootSCachep;
4881 userp = smb_GetUserFromVCP(vcp, inp);
4883 caseFold = CM_FLAG_CASEFOLD;
4885 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
4887 cm_ReleaseUser(userp);
4888 return CM_ERROR_NOSUCHFILE;
4890 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
4891 tidPathp, &req, &newScp);
4894 cm_ReleaseUser(userp);
4899 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
4900 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
4901 cm_ReleaseSCache(newScp);
4902 cm_ReleaseUser(userp);
4903 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
4904 return CM_ERROR_PATH_NOT_COVERED;
4906 return CM_ERROR_BADSHARENAME;
4908 #endif /* DFS_SUPPORT */
4910 /* now lock the vnode with a callback; returns with newScp locked; we
4911 * need the current status to determine what the new status is, in some
4914 lock_ObtainWrite(&newScp->rw);
4915 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
4916 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
4918 lock_ReleaseWrite(&newScp->rw);
4919 cm_ReleaseSCache(newScp);
4920 cm_ReleaseUser(userp);
4924 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4926 /* Check for RO volume */
4927 if (newScp->flags & CM_SCACHEFLAG_RO) {
4928 lock_ReleaseWrite(&newScp->rw);
4929 cm_ReleaseSCache(newScp);
4930 cm_ReleaseUser(userp);
4931 return CM_ERROR_READONLY;
4934 /* prepare for setattr call */
4937 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
4938 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
4940 if ((newScp->unixModeBits & 0222) && (attribute & SMB_ATTR_READONLY) != 0) {
4941 /* we're told to make a writable file read-only */
4942 attr.unixModeBits = newScp->unixModeBits & ~0222;
4943 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4945 else if ((newScp->unixModeBits & 0222) == 0 && (attribute & SMB_ATTR_READONLY) == 0) {
4946 /* we're told to make a read-only file writable */
4947 attr.unixModeBits = newScp->unixModeBits | 0222;
4948 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
4950 lock_ReleaseWrite(&newScp->rw);
4952 /* now call setattr */
4954 code = cm_SetAttr(newScp, &attr, userp, &req);
4958 cm_ReleaseSCache(newScp);
4959 cm_ReleaseUser(userp);
4965 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4967 clientchar_t *pathp;
4969 cm_scache_t *rootScp;
4970 cm_scache_t *newScp, *dscp;
4975 clientchar_t *tidPathp;
4977 clientchar_t *lastComp;
4983 datap = smb_GetSMBData(inp, NULL);
4984 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
4986 return CM_ERROR_BADSMB;
4988 if (*pathp == 0) /* null path */
4991 osi_Log1(smb_logp, "SMB receive getfile attributes path %S",
4992 osi_LogSaveClientString(smb_logp, pathp));
4994 rootScp = cm_data.rootSCachep;
4996 userp = smb_GetUserFromVCP(vcp, inp);
4998 /* we shouldn't need this for V3 requests, but we seem to */
4999 caseFold = CM_FLAG_CASEFOLD;
5001 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5003 cm_ReleaseUser(userp);
5004 return CM_ERROR_NOSUCHFILE;
5008 * XXX Strange hack XXX
5010 * As of Patch 5 (16 July 97), we are having the following problem:
5011 * In NT Explorer 4.0, whenever we click on a directory, AFS gets
5012 * requests to look up "desktop.ini" in all the subdirectories.
5013 * This can cause zillions of timeouts looking up non-existent cells
5014 * and volumes, especially in the top-level directory.
5016 * We have not found any way to avoid this or work around it except
5017 * to explicitly ignore the requests for mount points that haven't
5018 * yet been evaluated and for directories that haven't yet been
5021 * We should modify this hack to provide a fake desktop.ini file
5022 * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
5024 spacep = inp->spacep;
5025 smb_StripLastComponent(spacep->wdata, &lastComp, pathp);
5026 #ifndef SPECIAL_FOLDERS
5027 if (lastComp && cm_ClientStrCmpIA(lastComp, _C("\\desktop.ini")) == 0) {
5028 code = cm_NameI(rootScp, spacep->wdata,
5029 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
5030 userp, tidPathp, &req, &dscp);
5033 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5034 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp,
5036 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5037 return CM_ERROR_PATH_NOT_COVERED;
5039 return CM_ERROR_BADSHARENAME;
5041 #endif /* DFS_SUPPORT */
5042 if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT && !dscp->mountRootFid.volume)
5043 code = CM_ERROR_NOSUCHFILE;
5044 else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
5045 cm_buf_t *bp = buf_Find(dscp, &hzero);
5050 code = CM_ERROR_NOSUCHFILE;
5052 cm_ReleaseSCache(dscp);
5054 cm_ReleaseUser(userp);
5059 #endif /* SPECIAL_FOLDERS */
5061 code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5062 tidPathp, &req, &newScp);
5064 cm_ReleaseUser(userp);
5069 if (newScp->fileType == CM_SCACHETYPE_DFSLINK) {
5070 int pnc = cm_VolStatus_Notify_DFS_Mapping(newScp, tidPathp, pathp);
5071 cm_ReleaseSCache(newScp);
5072 cm_ReleaseUser(userp);
5073 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5074 return CM_ERROR_PATH_NOT_COVERED;
5076 return CM_ERROR_BADSHARENAME;
5078 #endif /* DFS_SUPPORT */
5080 /* now lock the vnode with a callback; returns with newScp locked */
5081 lock_ObtainWrite(&newScp->rw);
5082 code = cm_SyncOp(newScp, NULL, userp, &req, 0,
5083 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
5085 lock_ReleaseWrite(&newScp->rw);
5086 cm_ReleaseSCache(newScp);
5087 cm_ReleaseUser(userp);
5091 cm_SyncOpDone(newScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5094 /* use smb_Attributes instead. Also the fact that a file is
5095 * in a readonly volume doesn't mean it shojuld be marked as RO
5097 if (newScp->fileType == CM_SCACHETYPE_DIRECTORY ||
5098 newScp->fileType == CM_SCACHETYPE_MOUNTPOINT ||
5099 newScp->fileType == CM_SCACHETYPE_INVALID)
5100 attrs = SMB_ATTR_DIRECTORY;
5103 if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
5104 attrs |= SMB_ATTR_READONLY; /* turn on read-only flag */
5106 attrs = smb_Attributes(newScp);
5109 smb_SetSMBParm(outp, 0, attrs);
5111 smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
5112 smb_SetSMBParm(outp, 1, (unsigned int)(dosTime & 0xffff));
5113 smb_SetSMBParm(outp, 2, (unsigned int)((dosTime>>16) & 0xffff));
5114 smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
5115 smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
5116 smb_SetSMBParm(outp, 5, 0);
5117 smb_SetSMBParm(outp, 6, 0);
5118 smb_SetSMBParm(outp, 7, 0);
5119 smb_SetSMBParm(outp, 8, 0);
5120 smb_SetSMBParm(outp, 9, 0);
5121 smb_SetSMBDataLength(outp, 0);
5122 lock_ReleaseWrite(&newScp->rw);
5124 cm_ReleaseSCache(newScp);
5125 cm_ReleaseUser(userp);
5130 /* SMB_COM_TREE_DISCONNECT */
5131 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5135 osi_Log0(smb_logp, "SMB receive tree disconnect");
5137 /* find the tree and free it */
5138 tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
5140 lock_ObtainWrite(&smb_rctLock);
5142 smb_ReleaseTID(tidp, TRUE);
5143 lock_ReleaseWrite(&smb_rctLock);
5150 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5153 clientchar_t *pathp;
5154 clientchar_t *lastNamep;
5163 clientchar_t *tidPathp;
5169 datap = smb_GetSMBData(inp, NULL);
5170 pathp = smb_ParseASCIIBlock(inp, datap, NULL, SMB_STRF_ANSIPATH);
5172 osi_Log1(smb_logp, "SMB receive open file [%S]", osi_LogSaveClientString(smb_logp, pathp));
5174 #ifdef DEBUG_VERBOSE
5178 hexpath = osi_HexifyString( pathp );
5179 DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
5184 share = smb_GetSMBParm(inp, 0);
5185 attribute = smb_GetSMBParm(inp, 1);
5187 spacep = inp->spacep;
5188 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5189 if (lastNamep && cm_ClientStrCmp(lastNamep, _C(SMB_IOCTL_FILENAME)) == 0) {
5190 /* special case magic file name for receiving IOCTL requests
5191 * (since IOCTL calls themselves aren't getting through).
5193 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5194 smb_SetupIoctlFid(fidp, spacep);
5195 smb_SetSMBParm(outp, 0, fidp->fid);
5196 smb_SetSMBParm(outp, 1, 0); /* attrs */
5197 smb_SetSMBParm(outp, 2, 0); /* next 2 are DOS time */
5198 smb_SetSMBParm(outp, 3, 0);
5199 smb_SetSMBParm(outp, 4, 0); /* next 2 are length */
5200 smb_SetSMBParm(outp, 5, 0x7fff);
5201 /* pass the open mode back */
5202 smb_SetSMBParm(outp, 6, (share & 0xf));
5203 smb_SetSMBDataLength(outp, 0);
5204 smb_ReleaseFID(fidp);
5208 userp = smb_GetUserFromVCP(vcp, inp);
5210 caseFold = CM_FLAG_CASEFOLD;
5212 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5214 cm_ReleaseUser(userp);
5215 return CM_ERROR_NOSUCHPATH;
5217 code = cm_NameI(cm_data.rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
5218 tidPathp, &req, &scp);
5221 cm_ReleaseUser(userp);
5226 if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
5227 int pnc = cm_VolStatus_Notify_DFS_Mapping(scp, tidPathp, pathp);
5228 cm_ReleaseSCache(scp);
5229 cm_ReleaseUser(userp);
5230 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5231 return CM_ERROR_PATH_NOT_COVERED;
5233 return CM_ERROR_BADSHARENAME;
5235 #endif /* DFS_SUPPORT */
5237 code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
5239 cm_ReleaseSCache(scp);
5240 cm_ReleaseUser(userp);
5244 /* don't need callback to check file type, since file types never
5245 * change, and namei and cm_Lookup all stat the object at least once on
5246 * a successful return.
5248 if (scp->fileType != CM_SCACHETYPE_FILE) {
5249 cm_ReleaseSCache(scp);
5250 cm_ReleaseUser(userp);
5251 return CM_ERROR_ISDIR;
5254 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5255 osi_assertx(fidp, "null smb_fid_t");
5257 /* save a pointer to the vnode */
5259 osi_Log2(smb_logp,"smb_ReceiveCoreOpen fidp 0x%p scp 0x%p", fidp, scp);
5260 lock_ObtainWrite(&scp->rw);
5261 scp->flags |= CM_SCACHEFLAG_SMB_FID;
5262 lock_ReleaseWrite(&scp->rw);
5266 fidp->userp = userp;
5268 lock_ObtainMutex(&fidp->mx);
5269 if ((share & 0xf) == 0)
5270 fidp->flags |= SMB_FID_OPENREAD_LISTDIR;
5271 else if ((share & 0xf) == 1)
5272 fidp->flags |= SMB_FID_OPENWRITE;
5274 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
5275 lock_ReleaseMutex(&fidp->mx);
5277 lock_ObtainRead(&scp->rw);
5278 smb_SetSMBParm(outp, 0, fidp->fid);
5279 smb_SetSMBParm(outp, 1, smb_Attributes(scp));
5280 smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
5281 smb_SetSMBParm(outp, 2, (unsigned int)(dosTime & 0xffff));
5282 smb_SetSMBParm(outp, 3, (unsigned int)((dosTime >> 16) & 0xffff));
5283 smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
5284 smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
5285 /* pass the open mode back; XXXX add access checks */
5286 smb_SetSMBParm(outp, 6, (share & 0xf));
5287 smb_SetSMBDataLength(outp, 0);
5288 lock_ReleaseRead(&scp->rw);
5291 cm_Open(scp, 0, userp);
5293 /* send and free packet */
5294 smb_ReleaseFID(fidp);
5295 cm_ReleaseUser(userp);
5296 /* don't release scp, since we've squirreled away the pointer in the fid struct */
5300 typedef struct smb_unlinkRock {
5305 clientchar_t *maskp; /* pointer to the star pattern */
5308 cm_dirEntryList_t * matches;
5311 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5314 smb_unlinkRock_t *rockp;
5317 normchar_t matchName[MAX_PATH];
5321 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5322 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5323 caseFold |= CM_FLAG_8DOT3;
5325 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
5326 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5328 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5329 !cm_Is8Dot3(matchName)) {
5330 cm_Gen8Dot3Name(dep, matchName, NULL);
5331 /* 8.3 matches are always case insensitive */
5332 match = cm_MatchMask(matchName, rockp->maskp, caseFold | CM_FLAG_CASEFOLD);
5335 osi_Log1(smb_logp, "Found match %S",
5336 osi_LogSaveClientString(smb_logp, matchName));
5338 cm_DirEntryListAdd(dep->name, &rockp->matches);
5342 /* If we made a case sensitive exact match, we might as well quit now. */
5343 if (!(rockp->flags & SMB_MASKFLAG_CASEFOLD) && !cm_ClientStrCmp(matchName, rockp->maskp))
5344 code = CM_ERROR_STOPNOW;
5353 /* SMB_COM_DELETE */
5354 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5358 clientchar_t *pathp;
5362 clientchar_t *lastNamep;
5363 smb_unlinkRock_t rock;
5367 clientchar_t *tidPathp;
5372 attribute = smb_GetSMBParm(inp, 0);
5374 tp = smb_GetSMBData(inp, NULL);
5375 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5377 osi_Log1(smb_logp, "SMB receive unlink %S",
5378 osi_LogSaveClientString(smb_logp, pathp));
5380 spacep = inp->spacep;
5381 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5383 userp = smb_GetUserFromVCP(vcp, inp);
5385 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5387 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5389 cm_ReleaseUser(userp);
5390 return CM_ERROR_NOSUCHPATH;
5392 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold, userp, tidPathp,
5395 cm_ReleaseUser(userp);
5400 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
5401 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
5402 cm_ReleaseSCache(dscp);
5403 cm_ReleaseUser(userp);
5404 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5405 return CM_ERROR_PATH_NOT_COVERED;
5407 return CM_ERROR_BADSHARENAME;
5409 #endif /* DFS_SUPPORT */
5411 /* otherwise, scp points to the parent directory. */
5418 rock.maskp = cm_ClientStringToNormStringAlloc(smb_FindMask(pathp), -1, NULL);
5419 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5422 thyper.HighPart = 0;
5427 rock.matches = NULL;
5429 /* Now, if we aren't dealing with a wildcard match, we first try an exact
5430 * match. If that fails, we do a case insensitve match.
5432 if (!(rock.flags & SMB_MASKFLAG_TILDE) &&
5433 !smb_IsStarMask(rock.maskp)) {
5434 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5437 thyper.HighPart = 0;
5438 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5443 code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
5445 if (code == CM_ERROR_STOPNOW)
5448 if (code == 0 && rock.matches) {
5449 cm_dirEntryList_t * entry;
5451 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
5452 normchar_t normalizedName[MAX_PATH];
5454 /* Note: entry->name is a non-normalized name */
5456 osi_Log1(smb_logp, "Unlinking %s",
5457 osi_LogSaveString(smb_logp, entry->name));
5459 cm_FsStringToNormString(entry->name, -1,
5460 normalizedName, lengthof(normalizedName));
5462 code = cm_Unlink(dscp, entry->name, normalizedName, userp, &req);
5464 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5465 smb_NotifyChange(FILE_ACTION_REMOVED,
5466 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
5467 dscp, normalizedName, NULL, TRUE);
5471 cm_DirEntryListFree(&rock.matches);
5473 cm_ReleaseUser(userp);
5475 cm_ReleaseSCache(dscp);
5479 if (code == 0 && !rock.any)
5480 code = CM_ERROR_NOSUCHFILE;
5484 typedef struct smb_renameRock {
5485 cm_scache_t *odscp; /* old dir */
5486 cm_scache_t *ndscp; /* new dir */
5487 cm_user_t *userp; /* user */
5488 cm_req_t *reqp; /* request struct */
5489 smb_vc_t *vcp; /* virtual circuit */
5490 normchar_t *maskp; /* pointer to star pattern of old file name */
5491 int flags; /* tilde, casefold, etc */
5492 clientchar_t *newNamep; /* ptr to the new file's name */
5493 fschar_t fsOldName[MAX_PATH]; /* raw FS name */
5494 clientchar_t clOldName[MAX_PATH]; /* client name */
5498 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5501 smb_renameRock_t *rockp;
5504 normchar_t matchName[MAX_PATH];
5506 rockp = (smb_renameRock_t *) vrockp;
5508 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
5509 caseFold = ((rockp->flags & SMB_MASKFLAG_CASEFOLD)? CM_FLAG_CASEFOLD : 0);
5510 if (!(rockp->vcp->flags & SMB_VCFLAG_USEV3))
5511 caseFold |= CM_FLAG_8DOT3;
5513 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5515 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5516 !cm_Is8Dot3(matchName)) {
5517 cm_Gen8Dot3Name(dep, matchName, NULL);
5518 match = cm_MatchMask(matchName, rockp->maskp, caseFold);
5523 StringCbCopyA(rockp->fsOldName, sizeof(rockp->fsOldName), dep->name);
5524 cm_ClientStrCpy(rockp->clOldName, lengthof(rockp->clOldName),
5526 code = CM_ERROR_STOPNOW;
5536 smb_Rename(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp, int attrs)
5539 cm_space_t *spacep = NULL;
5540 smb_renameRock_t rock;
5541 cm_scache_t *oldDscp = NULL;
5542 cm_scache_t *newDscp = NULL;
5543 cm_scache_t *tmpscp= NULL;
5544 cm_scache_t *tmpscp2 = NULL;
5545 clientchar_t *oldLastNamep;
5546 clientchar_t *newLastNamep;
5550 clientchar_t *tidPathp;
5554 userp = smb_GetUserFromVCP(vcp, inp);
5555 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5557 cm_ReleaseUser(userp);
5558 return CM_ERROR_NOSUCHPATH;
5562 spacep = inp->spacep;
5563 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5565 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5566 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5567 userp, tidPathp, &req, &oldDscp);
5569 cm_ReleaseUser(userp);
5574 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5575 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
5576 cm_ReleaseSCache(oldDscp);
5577 cm_ReleaseUser(userp);
5578 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5579 return CM_ERROR_PATH_NOT_COVERED;
5581 return CM_ERROR_BADSHARENAME;
5583 #endif /* DFS_SUPPORT */
5585 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
5586 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5587 userp, tidPathp, &req, &newDscp);
5590 cm_ReleaseSCache(oldDscp);
5591 cm_ReleaseUser(userp);
5596 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5597 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
5598 cm_ReleaseSCache(oldDscp);
5599 cm_ReleaseSCache(newDscp);
5600 cm_ReleaseUser(userp);
5601 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5602 return CM_ERROR_PATH_NOT_COVERED;
5604 return CM_ERROR_BADSHARENAME;
5606 #endif /* DFS_SUPPORT */
5609 /* otherwise, oldDscp and newDscp point to the corresponding directories.
5610 * next, get the component names, and lower case them.
5613 /* handle the old name first */
5615 oldLastNamep = oldPathp;
5619 /* and handle the new name, too */
5621 newLastNamep = newPathp;
5625 /* TODO: The old name could be a wildcard. The new name must not be */
5627 /* do the vnode call */
5628 rock.odscp = oldDscp;
5629 rock.ndscp = newDscp;
5633 rock.maskp = cm_ClientStringToNormStringAlloc(oldLastNamep, -1, NULL);
5634 rock.flags = ((cm_ClientStrChr(oldLastNamep, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
5635 rock.newNamep = newLastNamep;
5636 rock.fsOldName[0] = '\0';
5637 rock.clOldName[0] = '\0';
5640 /* Check if the file already exists; if so return error */
5641 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5642 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5643 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5645 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
5646 osi_LogSaveClientString(smb_logp, newLastNamep));
5648 /* Check if the old and the new names differ only in case. If so return
5649 * success, else return CM_ERROR_EXISTS
5651 if (!code && oldDscp == newDscp && !cm_ClientStrCmpI(oldLastNamep, newLastNamep)) {
5653 /* This would be a success only if the old file is *as same as* the new file */
5654 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH, userp, &req, &tmpscp2);
5656 if (tmpscp == tmpscp2)
5659 code = CM_ERROR_EXISTS;
5660 cm_ReleaseSCache(tmpscp2);
5663 code = CM_ERROR_NOSUCHFILE;
5666 /* file exist, do not rename, also fixes move */
5667 osi_Log0(smb_logp, "Can't rename. Target already exists");
5668 code = CM_ERROR_EXISTS;
5672 cm_ReleaseSCache(tmpscp);
5673 cm_ReleaseSCache(newDscp);
5674 cm_ReleaseSCache(oldDscp);
5675 cm_ReleaseUser(userp);
5682 /* Now search the directory for the pattern, and do the appropriate rename when found */
5683 thyper.LowPart = 0; /* search dir from here */
5684 thyper.HighPart = 0;
5686 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5687 if (code == 0 && !rock.any) {
5689 thyper.HighPart = 0;
5690 rock.flags |= SMB_MASKFLAG_CASEFOLD;
5691 code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
5693 osi_Log1(smb_logp, "smb_RenameProc returns %ld", code);
5695 if (code == CM_ERROR_STOPNOW && rock.fsOldName[0] != '\0') {
5696 code = cm_Rename(rock.odscp, rock.fsOldName, rock.clOldName,
5697 rock.ndscp, rock.newNamep, rock.userp,
5699 /* if the call worked, stop doing the search now, since we
5700 * really only want to rename one file.
5702 osi_Log1(smb_logp, "cm_Rename returns %ld", code);
5703 } else if (code == 0) {
5704 code = CM_ERROR_NOSUCHFILE;
5707 /* Handle Change Notification */
5709 * Being lazy, not distinguishing between files and dirs in this
5710 * filter, since we'd have to do a lookup.
5713 filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
5714 if (oldDscp == newDscp) {
5715 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5716 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5717 filter, oldDscp, rock.clOldName,
5718 newLastNamep, TRUE);
5720 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5721 smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
5722 filter, oldDscp, rock.clOldName,
5724 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5725 smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
5726 filter, newDscp, newLastNamep,
5732 cm_ReleaseSCache(tmpscp);
5733 cm_ReleaseUser(userp);
5734 cm_ReleaseSCache(oldDscp);
5735 cm_ReleaseSCache(newDscp);
5744 smb_Link(smb_vc_t *vcp, smb_packet_t *inp, clientchar_t * oldPathp, clientchar_t * newPathp)
5747 cm_space_t *spacep = NULL;
5748 cm_scache_t *oldDscp = NULL;
5749 cm_scache_t *newDscp = NULL;
5750 cm_scache_t *tmpscp= NULL;
5751 cm_scache_t *tmpscp2 = NULL;
5752 cm_scache_t *sscp = NULL;
5753 clientchar_t *oldLastNamep;
5754 clientchar_t *newLastNamep;
5757 clientchar_t *tidPathp;
5761 userp = smb_GetUserFromVCP(vcp, inp);
5763 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5765 cm_ReleaseUser(userp);
5766 return CM_ERROR_NOSUCHPATH;
5771 caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
5773 spacep = inp->spacep;
5774 smb_StripLastComponent(spacep->wdata, &oldLastNamep, oldPathp);
5776 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5777 userp, tidPathp, &req, &oldDscp);
5779 cm_ReleaseUser(userp);
5784 if (oldDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5785 int pnc = cm_VolStatus_Notify_DFS_Mapping(oldDscp, tidPathp, spacep->wdata);
5786 cm_ReleaseSCache(oldDscp);
5787 cm_ReleaseUser(userp);
5788 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5789 return CM_ERROR_PATH_NOT_COVERED;
5791 return CM_ERROR_BADSHARENAME;
5793 #endif /* DFS_SUPPORT */
5795 smb_StripLastComponent(spacep->wdata, &newLastNamep, newPathp);
5796 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold,
5797 userp, tidPathp, &req, &newDscp);
5799 cm_ReleaseSCache(oldDscp);
5800 cm_ReleaseUser(userp);
5805 if (newDscp->fileType == CM_SCACHETYPE_DFSLINK) {
5806 int pnc = cm_VolStatus_Notify_DFS_Mapping(newDscp, tidPathp, spacep->wdata);
5807 cm_ReleaseSCache(newDscp);
5808 cm_ReleaseSCache(oldDscp);
5809 cm_ReleaseUser(userp);
5810 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
5811 return CM_ERROR_PATH_NOT_COVERED;
5813 return CM_ERROR_BADSHARENAME;
5815 #endif /* DFS_SUPPORT */
5817 /* Now, although we did two lookups for the two directories (because the same
5818 * directory can be referenced through different paths), we only allow hard links
5819 * within the same directory. */
5820 if (oldDscp != newDscp) {
5821 cm_ReleaseSCache(oldDscp);
5822 cm_ReleaseSCache(newDscp);
5823 cm_ReleaseUser(userp);
5824 return CM_ERROR_CROSSDEVLINK;
5827 /* handle the old name first */
5829 oldLastNamep = oldPathp;
5833 /* and handle the new name, too */
5835 newLastNamep = newPathp;
5839 /* now lookup the old name */
5840 osi_Log1(smb_logp," looking up [%S]", osi_LogSaveClientString(smb_logp,oldLastNamep));
5841 code = cm_Lookup(oldDscp, oldLastNamep, CM_FLAG_CHECKPATH | CM_FLAG_CASEFOLD, userp, &req, &sscp);
5843 cm_ReleaseSCache(oldDscp);
5844 cm_ReleaseSCache(newDscp);
5845 cm_ReleaseUser(userp);
5849 /* Check if the file already exists; if so return error */
5850 code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
5851 if ((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_BPLUS_NOMATCH) &&
5852 (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) )
5854 osi_Log2(smb_logp, " lookup returns %ld for [%S]", code,
5855 osi_LogSaveClientString(smb_logp, newLastNamep));
5857 /* if the existing link is to the same file, then we return success */
5859 if(sscp == tmpscp) {
5862 osi_Log0(smb_logp, "Can't create hardlink. Target already exists");
5863 code = CM_ERROR_EXISTS;
5868 cm_ReleaseSCache(tmpscp);
5869 cm_ReleaseSCache(sscp);
5870 cm_ReleaseSCache(newDscp);
5871 cm_ReleaseSCache(oldDscp);
5872 cm_ReleaseUser(userp);
5876 /* now create the hardlink */
5877 osi_Log1(smb_logp," Attempting to create new link [%S]", osi_LogSaveClientString(smb_logp, newLastNamep));
5878 code = cm_Link(newDscp, newLastNamep, sscp, 0, userp, &req);
5879 osi_Log1(smb_logp," Link returns 0x%x", code);
5881 /* Handle Change Notification */
5883 filter = (sscp->fileType == CM_SCACHETYPE_FILE)? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
5884 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
5885 smb_NotifyChange(FILE_ACTION_ADDED,
5886 filter, newDscp, newLastNamep,
5891 cm_ReleaseSCache(tmpscp);
5892 cm_ReleaseUser(userp);
5893 cm_ReleaseSCache(sscp);
5894 cm_ReleaseSCache(oldDscp);
5895 cm_ReleaseSCache(newDscp);
5899 /* SMB_COM_RENAME */
5901 smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5903 clientchar_t *oldPathp;
5904 clientchar_t *newPathp;
5908 tp = smb_GetSMBData(inp, NULL);
5909 oldPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5910 newPathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5912 osi_Log2(smb_logp, "smb rename [%S] to [%S]",
5913 osi_LogSaveClientString(smb_logp, oldPathp),
5914 osi_LogSaveClientString(smb_logp, newPathp));
5916 code = smb_Rename(vcp,inp,oldPathp,newPathp,0);
5918 osi_Log1(smb_logp, "smb rename returns 0x%x", code);
5924 typedef struct smb_rmdirRock {
5928 normchar_t *maskp; /* pointer to the star pattern */
5931 cm_dirEntryList_t * matches;
5934 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
5937 smb_rmdirRock_t *rockp;
5939 normchar_t matchName[MAX_PATH];
5941 rockp = (smb_rmdirRock_t *) vrockp;
5943 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
5944 if (rockp->flags & SMB_MASKFLAG_CASEFOLD)
5945 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
5947 match = (cm_ClientStrCmp(matchName, rockp->maskp) == 0);
5949 (rockp->flags & SMB_MASKFLAG_TILDE) &&
5950 !cm_Is8Dot3(matchName)) {
5951 cm_Gen8Dot3Name(dep, matchName, NULL);
5952 match = (cm_ClientStrCmpI(matchName, rockp->maskp) == 0);
5957 cm_DirEntryListAdd(dep->name, &rockp->matches);
5964 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5967 clientchar_t *pathp;
5971 clientchar_t *lastNamep;
5972 smb_rmdirRock_t rock;
5976 clientchar_t *tidPathp;
5981 tp = smb_GetSMBData(inp, NULL);
5982 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
5984 spacep = inp->spacep;
5985 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
5987 userp = smb_GetUserFromVCP(vcp, inp);
5989 caseFold = CM_FLAG_CASEFOLD;
5991 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
5993 cm_ReleaseUser(userp);
5994 return CM_ERROR_NOSUCHPATH;
5996 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
5997 userp, tidPathp, &req, &dscp);
6000 cm_ReleaseUser(userp);
6005 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
6006 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
6007 cm_ReleaseSCache(dscp);
6008 cm_ReleaseUser(userp);
6009 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
6010 return CM_ERROR_PATH_NOT_COVERED;
6012 return CM_ERROR_BADSHARENAME;
6014 #endif /* DFS_SUPPORT */
6016 /* otherwise, scp points to the parent directory. */
6023 rock.maskp = cm_ClientStringToNormStringAlloc(lastNamep, -1, NULL);
6024 rock.flags = ((cm_ClientStrChr(rock.maskp, '~') != NULL) ? SMB_MASKFLAG_TILDE : 0);
6027 thyper.HighPart = 0;
6031 rock.matches = NULL;
6033 /* First do a case sensitive match, and if that fails, do a case insensitive match */
6034 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6035 if (code == 0 && !rock.any) {
6037 thyper.HighPart = 0;
6038 rock.flags |= SMB_MASKFLAG_CASEFOLD;
6039 code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
6042 if (code == 0 && rock.matches) {
6043 cm_dirEntryList_t * entry;
6045 for (entry = rock.matches; code == 0 && entry; entry = entry->nextp) {
6046 clientchar_t clientName[MAX_PATH];
6048 cm_FsStringToClientString(entry->name, -1, clientName, lengthof(clientName));
6050 osi_Log1(smb_logp, "Removing directory %s",
6051 osi_LogSaveString(smb_logp, entry->name));
6053 code = cm_RemoveDir(dscp, entry->name, clientName, userp, &req);
6055 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
6056 smb_NotifyChange(FILE_ACTION_REMOVED,
6057 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6058 dscp, clientName, NULL, TRUE);
6062 cm_DirEntryListFree(&rock.matches);
6064 cm_ReleaseUser(userp);
6066 cm_ReleaseSCache(dscp);
6068 if (code == 0 && !rock.any)
6069 code = CM_ERROR_NOSUCHFILE;
6078 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6088 fid = smb_GetSMBParm(inp, 0);
6090 osi_Log1(smb_logp, "SMB flush fid %d", fid);
6092 fid = smb_ChainFID(fid, inp);
6093 fidp = smb_FindFID(vcp, fid, 0);
6095 return CM_ERROR_BADFD;
6097 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6098 smb_CloseFID(vcp, fidp, NULL, 0);
6099 smb_ReleaseFID(fidp);
6100 return CM_ERROR_NOSUCHFILE;
6103 lock_ObtainMutex(&fidp->mx);
6104 if (fidp->flags & SMB_FID_IOCTL) {
6105 lock_ReleaseMutex(&fidp->mx);
6106 smb_ReleaseFID(fidp);
6107 return CM_ERROR_BADFD;
6109 lock_ReleaseMutex(&fidp->mx);
6111 userp = smb_GetUserFromVCP(vcp, inp);
6113 lock_ObtainMutex(&fidp->mx);
6114 if ((fidp->flags & SMB_FID_OPENWRITE) && smb_AsyncStore != 2) {
6115 cm_scache_t * scp = fidp->scp;
6117 lock_ReleaseMutex(&fidp->mx);
6118 code = cm_FSync(scp, userp, &req);
6119 cm_ReleaseSCache(scp);
6122 lock_ReleaseMutex(&fidp->mx);
6125 smb_ReleaseFID(fidp);
6127 cm_ReleaseUser(userp);
6132 struct smb_FullNameRock {
6135 clientchar_t *fullName;
6136 fschar_t *originalName;
6139 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
6142 normchar_t matchName[MAX_PATH];
6143 struct smb_FullNameRock *vrockp;
6145 vrockp = (struct smb_FullNameRock *)rockp;
6147 cm_FsStringToNormString(dep->name, -1, matchName, lengthof(matchName));
6149 if (!cm_Is8Dot3(matchName)) {
6150 clientchar_t shortName[13];
6152 cm_Gen8Dot3Name(dep, shortName, NULL);
6154 if (cm_ClientStrCmpIA(shortName, vrockp->name) == 0) {
6155 vrockp->fullName = cm_ClientStrDup(matchName);
6156 vrockp->originalName = cm_FsStrDup(dep->name);
6157 return CM_ERROR_STOPNOW;
6160 if (cm_ClientStrCmpI(matchName, vrockp->name) == 0 &&
6161 ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode &&
6162 ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
6163 vrockp->fullName = cm_ClientStrDup(matchName);
6164 vrockp->originalName = cm_FsStrDup(dep->name);
6165 return CM_ERROR_STOPNOW;
6170 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, clientchar_t *pathp,
6171 clientchar_t **newPathp, fschar_t ** originalPathp,
6172 cm_user_t *userp, cm_req_t *reqp)
6174 struct smb_FullNameRock rock;
6177 memset(&rock, 0, sizeof(rock));
6181 code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, userp, reqp, NULL);
6182 if (code == CM_ERROR_STOPNOW) {
6183 *newPathp = rock.fullName;
6184 *originalPathp = rock.originalName;
6186 *newPathp = cm_ClientStrDup(pathp);
6187 *originalPathp = cm_ClientStringToFsStringAlloc(pathp, -1, NULL);
6191 long smb_CloseFID(smb_vc_t *vcp, smb_fid_t *fidp, cm_user_t *userp,
6192 afs_uint32 dosTime) {
6195 cm_scache_t *dscp = NULL;
6196 clientchar_t *pathp = NULL;
6197 cm_scache_t * scp = NULL;
6198 cm_scache_t *delscp = NULL;
6199 int nullcreator = 0;
6201 osi_Log4(smb_logp, "smb_CloseFID Closing fidp 0x%x (fid=%d scp=0x%x vcp=0x%x)",
6202 fidp, fidp->fid, scp, vcp);
6205 lock_ObtainMutex(&fidp->mx);
6206 if (!fidp->userp && !(fidp->flags & SMB_FID_IOCTL)) {
6207 lock_ReleaseMutex(&fidp->mx);
6208 osi_Log0(smb_logp, " No user specified. Not closing fid");
6209 return CM_ERROR_BADFD;
6212 userp = fidp->userp; /* no hold required since fidp is held
6213 throughout the function */
6214 lock_ReleaseMutex(&fidp->mx);
6219 lock_ObtainWrite(&smb_rctLock);
6220 if (fidp->deleteOk) {
6221 osi_Log0(smb_logp, " Fid already closed.");
6222 lock_ReleaseWrite(&smb_rctLock);
6223 return CM_ERROR_BADFD;
6226 lock_ReleaseWrite(&smb_rctLock);
6228 lock_ObtainMutex(&fidp->mx);
6229 if (fidp->NTopen_dscp) {
6230 dscp = fidp->NTopen_dscp;
6231 cm_HoldSCache(dscp);
6234 if (fidp->NTopen_pathp) {
6235 pathp = cm_ClientStrDup(fidp->NTopen_pathp);
6243 /* Don't jump the gun on an async raw write */
6244 while (fidp->raw_writers) {
6245 lock_ReleaseMutex(&fidp->mx);
6246 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
6247 lock_ObtainMutex(&fidp->mx);
6250 /* watch for ioctl closes, and read-only opens */
6252 (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
6253 == SMB_FID_OPENWRITE) {
6254 if (dosTime != 0 && dosTime != -1) {
6255 scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6256 /* This fixes defect 10958 */
6257 CompensateForSmbClientLastWriteTimeBugs(&dosTime);
6258 smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
6260 if (smb_AsyncStore != 2) {
6261 lock_ReleaseMutex(&fidp->mx);
6262 code = cm_FSync(scp, userp, &req);
6263 lock_ObtainMutex(&fidp->mx);
6269 /* unlock any pending locks */
6270 if (!(fidp->flags & SMB_FID_IOCTL) && scp &&
6271 scp->fileType == CM_SCACHETYPE_FILE) {
6275 lock_ReleaseMutex(&fidp->mx);
6277 /* CM_UNLOCK_BY_FID doesn't look at the process ID. We pass
6279 key = cm_GenerateKey(vcp->vcID, 0, fidp->fid);
6280 lock_ObtainWrite(&scp->rw);
6282 tcode = cm_SyncOp(scp, NULL, userp, &req, 0,
6283 CM_SCACHESYNC_NEEDCALLBACK
6284 | CM_SCACHESYNC_GETSTATUS
6285 | CM_SCACHESYNC_LOCK);
6289 "smb CoreClose SyncOp failure code 0x%x", tcode);
6290 goto post_syncopdone;
6293 cm_UnlockByKey(scp, key, CM_UNLOCK_BY_FID, userp, &req);
6295 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
6299 lock_ReleaseWrite(&scp->rw);
6300 lock_ObtainMutex(&fidp->mx);
6303 if (fidp->flags & SMB_FID_DELONCLOSE) {
6304 clientchar_t *fullPathp = NULL;
6305 fschar_t *originalNamep = NULL;
6307 lock_ReleaseMutex(&fidp->mx);
6309 code = cm_Lookup(dscp, pathp, CM_FLAG_NOMOUNTCHASE, userp, &req, &delscp);
6314 smb_FullName(dscp, delscp, pathp, &fullPathp, &originalNamep, userp, &req);
6315 if (delscp->fileType == CM_SCACHETYPE_DIRECTORY) {
6316 code = cm_RemoveDir(dscp, originalNamep, fullPathp, userp, &req);
6318 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6319 smb_NotifyChange(FILE_ACTION_REMOVED,
6320 FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_CREATION,
6321 dscp, fullPathp, NULL, TRUE);
6324 code = cm_Unlink(dscp, originalNamep, fullPathp, userp, &req);
6326 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
6327 smb_NotifyChange(FILE_ACTION_REMOVED,
6328 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
6329 dscp, fullPathp, NULL, TRUE);
6336 free(originalNamep);
6338 lock_ObtainMutex(&fidp->mx);
6339 fidp->flags &= ~SMB_FID_DELONCLOSE;
6342 /* if this was a newly created file, then clear the creator
6343 * in the stat cache entry. */
6344 if (fidp->flags & SMB_FID_CREATED) {
6346 fidp->flags &= ~SMB_FID_CREATED;
6349 if (fidp->flags & SMB_FID_NTOPEN) {
6350 cm_ReleaseSCache(fidp->NTopen_dscp);
6351 fidp->NTopen_dscp = NULL;
6352 free(fidp->NTopen_pathp);
6353 fidp->NTopen_pathp = NULL;
6354 fidp->flags &= ~SMB_FID_NTOPEN;
6356 osi_assertx(fidp->NTopen_dscp == NULL, "null NTopen_dsc");
6357 osi_assertx(fidp->NTopen_pathp == NULL, "null NTopen_path");
6360 if (fidp->NTopen_wholepathp) {
6361 free(fidp->NTopen_wholepathp);
6362 fidp->NTopen_wholepathp = NULL;
6366 cm_ReleaseSCache(fidp->scp);
6369 lock_ReleaseMutex(&fidp->mx);
6372 cm_ReleaseSCache(dscp);
6375 cm_ReleaseSCache(delscp);
6379 lock_ObtainWrite(&scp->rw);
6380 if (nullcreator && scp->creator == userp)
6381 scp->creator = NULL;
6382 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
6383 lock_ReleaseWrite(&scp->rw);
6384 cm_ReleaseSCache(scp);
6394 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6402 fid = smb_GetSMBParm(inp, 0);
6403 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
6405 osi_Log1(smb_logp, "SMB ReceiveCoreClose fid %d", fid);
6407 fid = smb_ChainFID(fid, inp);
6408 fidp = smb_FindFID(vcp, fid, 0);
6410 return CM_ERROR_BADFD;
6413 userp = smb_GetUserFromVCP(vcp, inp);
6415 code = smb_CloseFID(vcp, fidp, userp, dosTime);
6417 smb_ReleaseFID(fidp);
6418 cm_ReleaseUser(userp);
6423 * smb_ReadData -- common code for Read, Read And X, and Raw Read
6425 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6426 cm_user_t *userp, long *readp)
6432 osi_hyper_t fileLength;
6434 osi_hyper_t lastByte;
6435 osi_hyper_t bufferOffset;
6439 int sequential = (fidp->flags & SMB_FID_SEQUENTIAL);
6442 osi_Log3(smb_logp, "smb_ReadData fid %d, off 0x%x, size 0x%x",
6443 fidp->fid, offsetp->LowPart, count);
6447 lock_ObtainMutex(&fidp->mx);
6448 /* make sure we have a readable FD */
6449 if (!(fidp->flags & SMB_FID_OPENREAD_LISTDIR)) {
6450 osi_Log2(smb_logp, "smb_ReadData fid %d not OPENREAD_LISTDIR flags 0x%x",
6451 fidp->fid, fidp->flags);
6452 lock_ReleaseMutex(&fidp->mx);
6453 code = CM_ERROR_BADFDOP;
6464 lock_ObtainWrite(&scp->rw);
6466 if (offset.HighPart == 0) {
6467 chunk = offset.LowPart >> cm_logChunkSize;
6468 if (chunk != fidp->curr_chunk) {
6469 fidp->prev_chunk = fidp->curr_chunk;
6470 fidp->curr_chunk = chunk;
6472 if (!(fidp->flags & SMB_FID_RANDOM) && (fidp->curr_chunk == fidp->prev_chunk + 1))
6475 lock_ReleaseMutex(&fidp->mx);
6477 /* start by looking up the file's end */
6478 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6479 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6483 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6485 /* now we have the entry locked, look up the length */
6486 fileLength = scp->length;
6488 /* adjust count down so that it won't go past EOF */
6489 thyper.LowPart = count;
6490 thyper.HighPart = 0;
6491 thyper = LargeIntegerAdd(offset, thyper); /* where read should end */
6493 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6494 /* we'd read past EOF, so just stop at fileLength bytes.
6495 * Start by computing how many bytes remain in the file.
6497 thyper = LargeIntegerSubtract(fileLength, offset);
6499 /* if we are past EOF, read 0 bytes */
6500 if (LargeIntegerLessThanZero(thyper))
6503 count = thyper.LowPart;
6508 /* now, copy the data one buffer at a time,
6509 * until we've filled the request packet
6512 /* if we've copied all the data requested, we're done */
6513 if (count <= 0) break;
6515 /* otherwise, load up a buffer of data */
6516 thyper.HighPart = offset.HighPart;
6517 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6518 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6521 buf_Release(bufferp);
6524 lock_ReleaseWrite(&scp->rw);
6526 code = buf_Get(scp, &thyper, &bufferp);
6528 lock_ObtainWrite(&scp->rw);
6529 if (code) goto done;
6530 bufferOffset = thyper;
6532 /* now get the data in the cache */
6534 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6535 CM_SCACHESYNC_NEEDCALLBACK |
6536 CM_SCACHESYNC_READ);
6540 cm_SyncOpDone(scp, bufferp, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_READ);
6542 if (cm_HaveBuffer(scp, bufferp, 0)) break;
6544 /* otherwise, load the buffer and try again */
6545 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
6549 buf_Release(bufferp);
6553 } /* if (wrong buffer) ... */
6555 /* now we have the right buffer loaded. Copy out the
6556 * data from here to the user's buffer.
6558 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6560 /* and figure out how many bytes we want from this buffer */
6561 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6562 if (nbytes > count) nbytes = count; /* don't go past EOF */
6564 /* now copy the data */
6565 memcpy(op, bufferp->datap + bufIndex, nbytes);
6567 /* adjust counters, pointers, etc. */
6570 thyper.LowPart = nbytes;
6571 thyper.HighPart = 0;
6572 offset = LargeIntegerAdd(thyper, offset);
6576 lock_ReleaseWrite(&scp->rw);
6578 buf_Release(bufferp);
6580 if (code == 0 && sequential)
6581 cm_ConsiderPrefetch(scp, &lastByte, *readp, userp, &req);
6583 cm_ReleaseSCache(scp);
6586 osi_Log3(smb_logp, "smb_ReadData fid %d returns 0x%x read %d bytes",
6587 fidp->fid, code, *readp);
6592 * smb_WriteData -- common code for Write and Raw Write
6594 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, afs_uint32 count, char *op,
6595 cm_user_t *userp, long *writtenp)
6597 osi_hyper_t offset = *offsetp;
6600 cm_scache_t *scp = NULL;
6601 osi_hyper_t fileLength; /* file's length at start of write */
6602 osi_hyper_t minLength; /* don't read past this */
6603 afs_uint32 nbytes; /* # of bytes to transfer this iteration */
6604 cm_buf_t *bufferp = NULL;
6605 osi_hyper_t thyper; /* hyper tmp variable */
6606 osi_hyper_t bufferOffset;
6607 afs_uint32 bufIndex; /* index in buffer where our data is */
6608 int doWriteBack = 0;
6609 osi_hyper_t writeBackOffset;/* offset of region to write back when I/O is done */
6613 osi_Log3(smb_logp, "smb_WriteData fid %d, off 0x%x, size 0x%x",
6614 fidp->fid, offsetp->LowPart, count);
6618 lock_ObtainMutex(&fidp->mx);
6619 /* make sure we have a writable FD */
6620 if (!(fidp->flags & SMB_FID_OPENWRITE)) {
6621 osi_Log2(smb_logp, "smb_WriteData fid %d not OPENWRITE flags 0x%x",
6622 fidp->fid, fidp->flags);
6623 lock_ReleaseMutex(&fidp->mx);
6624 code = CM_ERROR_BADFDOP;
6632 lock_ReleaseMutex(&fidp->mx);
6634 lock_ObtainWrite(&scp->rw);
6635 /* start by looking up the file's end */
6636 code = cm_SyncOp(scp, NULL, userp, &req, 0,
6637 CM_SCACHESYNC_NEEDCALLBACK
6638 | CM_SCACHESYNC_SETSTATUS
6639 | CM_SCACHESYNC_GETSTATUS);
6643 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_SETSTATUS | CM_SCACHESYNC_GETSTATUS);
6645 /* now we have the entry locked, look up the length */
6646 fileLength = scp->length;
6647 minLength = fileLength;
6648 if (LargeIntegerGreaterThan(minLength, scp->serverLength))
6649 minLength = scp->serverLength;
6651 /* adjust file length if we extend past EOF */
6652 thyper.LowPart = count;
6653 thyper.HighPart = 0;
6654 thyper = LargeIntegerAdd(offset, thyper); /* where write should end */
6655 if (LargeIntegerGreaterThan(thyper, fileLength)) {
6656 /* we'd write past EOF, so extend the file */
6657 scp->mask |= CM_SCACHEMASK_LENGTH;
6658 scp->length = thyper;
6659 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
6661 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
6663 /* now, if the new position (thyper) and the old (offset) are in
6664 * different storeback windows, remember to store back the previous
6665 * storeback window when we're done with the write.
6667 * the purpose of this logic is to slow down the CIFS client
6668 * in order to avoid the client disconnecting during the CLOSE
6669 * operation if there are too many dirty buffers left to write
6670 * than can be accomplished during 45 seconds. This used to be
6671 * based upon cm_chunkSize but we desire cm_chunkSize to be large
6672 * so that we can read larger amounts of data at a time.
6674 if (smb_AsyncStore == 1 &&
6675 (thyper.LowPart & ~(smb_AsyncStoreSize-1)) !=
6676 (offset.LowPart & ~(smb_AsyncStoreSize-1))) {
6677 /* they're different */
6679 writeBackOffset.HighPart = offset.HighPart;
6680 writeBackOffset.LowPart = offset.LowPart & ~(smb_AsyncStoreSize-1);
6685 /* now, copy the data one buffer at a time, until we've filled the
6688 /* if we've copied all the data requested, we're done */
6692 /* handle over quota or out of space */
6693 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
6694 *writtenp = written;
6695 code = (scp->flags & CM_SCACHEFLAG_OVERQUOTA) ? CM_ERROR_QUOTA : CM_ERROR_SPACE;
6699 /* otherwise, load up a buffer of data */
6700 thyper.HighPart = offset.HighPart;
6701 thyper.LowPart = offset.LowPart & ~(cm_data.buf_blockSize-1);
6702 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
6705 lock_ReleaseMutex(&bufferp->mx);
6706 buf_Release(bufferp);
6709 lock_ReleaseWrite(&scp->rw);
6711 code = buf_Get(scp, &thyper, &bufferp);
6713 lock_ObtainMutex(&bufferp->mx);
6714 lock_ObtainWrite(&scp->rw);
6715 if (code) goto done;
6717 bufferOffset = thyper;
6719 /* now get the data in the cache */
6721 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
6722 CM_SCACHESYNC_NEEDCALLBACK
6723 | CM_SCACHESYNC_WRITE
6724 | CM_SCACHESYNC_BUFLOCKED);
6728 cm_SyncOpDone(scp, bufferp,
6729 CM_SCACHESYNC_NEEDCALLBACK
6730 | CM_SCACHESYNC_WRITE
6731 | CM_SCACHESYNC_BUFLOCKED);
6733 /* If we're overwriting the entire buffer, or
6734 * if we're writing at or past EOF, mark the
6735 * buffer as current so we don't call
6736 * cm_GetBuffer. This skips the fetch from the
6737 * server in those cases where we're going to
6738 * obliterate all the data in the buffer anyway,
6739 * or in those cases where there is no useful
6740 * data at the server to start with.
6742 * Use minLength instead of scp->length, since
6743 * the latter has already been updated by this
6746 if (LargeIntegerGreaterThanOrEqualTo(bufferp->offset, minLength)
6747 || LargeIntegerEqualTo(offset, bufferp->offset)
6748 && (count >= cm_data.buf_blockSize
6749 || LargeIntegerGreaterThanOrEqualTo(LargeIntegerAdd(offset,
6750 ConvertLongToLargeInteger(count)),
6752 if (count < cm_data.buf_blockSize
6753 && bufferp->dataVersion == CM_BUF_VERSION_BAD)
6754 memset(bufferp->datap, 0,
6755 cm_data.buf_blockSize);
6756 bufferp->dataVersion = scp->dataVersion;
6759 if (cm_HaveBuffer(scp, bufferp, 1)) break;
6761 /* otherwise, load the buffer and try again */
6762 lock_ReleaseMutex(&bufferp->mx);
6763 code = cm_GetBuffer(scp, bufferp, NULL, userp,
6765 lock_ReleaseWrite(&scp->rw);
6766 lock_ObtainMutex(&bufferp->mx);
6767 lock_ObtainWrite(&scp->rw);
6771 lock_ReleaseMutex(&bufferp->mx);
6772 buf_Release(bufferp);
6776 } /* if (wrong buffer) ... */
6778 /* now we have the right buffer loaded. Copy out the
6779 * data from here to the user's buffer.
6781 bufIndex = offset.LowPart & (cm_data.buf_blockSize - 1);
6783 /* and figure out how many bytes we want from this buffer */
6784 nbytes = cm_data.buf_blockSize - bufIndex; /* what remains in buffer */
6786 nbytes = count; /* don't go past end of request */
6788 /* now copy the data */
6789 memcpy(bufferp->datap + bufIndex, op, nbytes);
6790 buf_SetDirty(bufferp, bufIndex, nbytes, userp);
6792 /* adjust counters, pointers, etc. */
6796 thyper.LowPart = nbytes;
6797 thyper.HighPart = 0;
6798 offset = LargeIntegerAdd(thyper, offset);
6802 lock_ReleaseWrite(&scp->rw);
6805 lock_ReleaseMutex(&bufferp->mx);
6806 buf_Release(bufferp);
6809 lock_ObtainMutex(&fidp->mx);
6810 if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
6811 && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
6812 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
6813 fidp->NTopen_dscp, fidp->NTopen_pathp,
6816 lock_ReleaseMutex(&fidp->mx);
6819 if (smb_AsyncStore > 0) {
6823 lock_ObtainWrite(&scp->rw);
6824 osi_Log1(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE",
6826 code2 = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
6827 osi_Log2(smb_logp, "smb_WriteData fid %d calling cm_SyncOp ASYNCSTORE returns 0x%x",
6829 lock_ReleaseWrite(&scp->rw);
6830 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
6831 writeBackOffset.HighPart,
6832 smb_AsyncStoreSize, 0, userp);
6833 /* cm_SyncOpDone is called at the completion of cm_BkgStore */
6836 cm_BufWrite(scp, offsetp, *writtenp, 0, userp, &req);
6840 cm_ReleaseSCache(scp);
6843 osi_Log3(smb_logp, "smb_WriteData fid %d returns 0x%x written %d bytes",
6844 fidp->fid, code, *writtenp);
6849 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
6852 unsigned short count;
6854 unsigned short hint;
6855 long written = 0, total_written = 0;
6858 smb_t* smbp = (smb_t*) inp;
6861 cm_attr_t truncAttr; /* attribute struct used for truncating file */
6863 int inDataBlockCount;
6865 fd = smb_GetSMBParm(inp, 0);
6866 count = smb_GetSMBParm(inp, 1);
6867 offset.HighPart = 0; /* too bad */
6868 offset.LowPart = smb_GetSMBParmLong(inp, 2);
6869 hint = smb_GetSMBParm(inp, 4);
6871 op = smb_GetSMBData(inp, NULL);
6872 op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
6874 osi_Log3(smb_logp, "smb_ReceiveCoreWrite fid %d, off 0x%x, size 0x%x",
6875 fd, offset.LowPart, count);
6877 fd = smb_ChainFID(fd, inp);
6878 fidp = smb_FindFID(vcp, fd, 0);
6880 osi_Log0(smb_logp, "smb_ReceiveCoreWrite fid not found");
6881 return CM_ERROR_BADFD;
6884 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
6885 smb_CloseFID(vcp, fidp, NULL, 0);
6886 smb_ReleaseFID(fidp);
6887 return CM_ERROR_NOSUCHFILE;
6890 lock_ObtainMutex(&fidp->mx);
6891 if (fidp->flags & SMB_FID_IOCTL) {
6892 lock_ReleaseMutex(&fidp->mx);
6893 code = smb_IoctlWrite(fidp, vcp, inp, outp);
6894 smb_ReleaseFID(fidp);
6895 osi_Log1(smb_logp, "smb_ReceiveCoreWrite ioctl code 0x%x", code);
6898 lock_ReleaseMutex(&fidp->mx);
6899 userp = smb_GetUserFromVCP(vcp, inp);
6903 LARGE_INTEGER LOffset;
6904 LARGE_INTEGER LLength;
6907 key = cm_GenerateKey(vcp->vcID, pid, fd);
6909 LOffset.HighPart = offset.HighPart;
6910 LOffset.LowPart = offset.LowPart;
6911 LLength.HighPart = 0;
6912 LLength.LowPart = count;
6914 lock_ObtainWrite(&fidp->scp->rw);
6915 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
6916 lock_ReleaseWrite(&fidp->scp->rw);
6919 osi_Log1(smb_logp, "smb_ReceiveCoreWrite lock check failure 0x%x", code);
6924 /* special case: 0 bytes transferred means truncate to this position */
6928 osi_Log1(smb_logp, "smb_ReceiveCoreWrite truncation to length 0x%x", offset.LowPart);
6932 truncAttr.mask = CM_ATTRMASK_LENGTH;
6933 truncAttr.length.LowPart = offset.LowPart;
6934 truncAttr.length.HighPart = 0;
6935 lock_ObtainMutex(&fidp->mx);
6936 code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
6937 fidp->flags |= SMB_FID_LENGTHSETDONE;
6938 lock_ReleaseMutex(&fidp->mx);
6939 smb_SetSMBParm(outp, 0, 0 /* count */);
6940 smb_SetSMBDataLength(outp, 0);
6945 * Work around bug in NT client
6947 * When copying a file, the NT client should first copy the data,
6948 * then copy the last write time. But sometimes the NT client does
6949 * these in the wrong order, so the data copies would inadvertently
6950 * cause the last write time to be overwritten. We try to detect this,
6951 * and don't set client mod time if we think that would go against the
6954 lock_ObtainMutex(&fidp->mx);
6955 if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
6956 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
6957 fidp->scp->clientModTime = time(NULL);
6959 lock_ReleaseMutex(&fidp->mx);
6962 while ( code == 0 && count > 0 ) {
6963 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
6964 if (code == 0 && written == 0)
6965 code = CM_ERROR_PARTIALWRITE;
6967 offset = LargeIntegerAdd(offset,
6968 ConvertLongToLargeInteger(written));
6969 count -= (unsigned short)written;
6970 total_written += written;
6974 osi_Log2(smb_logp, "smb_ReceiveCoreWrite total written 0x%x code 0x%x",
6975 total_written, code);
6977 /* set the packet data length to 3 bytes for the data block header,
6978 * plus the size of the data.
6980 smb_SetSMBParm(outp, 0, total_written);
6981 smb_SetSMBParmLong(outp, 1, offset.LowPart);
6982 smb_SetSMBParm(outp, 3, hint);
6983 smb_SetSMBDataLength(outp, 0);
6986 smb_ReleaseFID(fidp);
6987 cm_ReleaseUser(userp);
6992 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
6993 NCB *ncbp, raw_write_cont_t *rwcp)
7002 fd = smb_GetSMBParm(inp, 0);
7003 fidp = smb_FindFID(vcp, fd, 0);
7005 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7006 smb_CloseFID(vcp, fidp, NULL, 0);
7007 smb_ReleaseFID(fidp);
7011 osi_Log3(smb_logp, "Completing Raw Write offset 0x%x:%08x count %x",
7012 rwcp->offset.HighPart, rwcp->offset.LowPart, rwcp->count);
7014 userp = smb_GetUserFromVCP(vcp, inp);
7017 code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
7019 if (rwcp->writeMode & 0x1) { /* synchronous */
7022 smb_FormatResponsePacket(vcp, inp, outp);
7023 op = (smb_t *) outp;
7024 op->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7025 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
7026 smb_SetSMBDataLength(outp, 0);
7027 smb_SendPacket(vcp, outp);
7028 smb_FreePacket(outp);
7030 else { /* asynchronous */
7031 lock_ObtainMutex(&fidp->mx);
7032 fidp->raw_writers--;
7033 if (fidp->raw_writers == 0)
7034 thrd_SetEvent(fidp->raw_write_event);
7035 lock_ReleaseMutex(&fidp->mx);
7038 /* Give back raw buffer */
7039 lock_ObtainMutex(&smb_RawBufLock);
7040 *((char **)rawBuf) = smb_RawBufs;
7041 smb_RawBufs = rawBuf;
7042 lock_ReleaseMutex(&smb_RawBufLock);
7044 smb_ReleaseFID(fidp);
7045 cm_ReleaseUser(userp);
7048 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7053 /* SMB_COM_WRITE_RAW */
7054 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
7057 long count, written = 0, total_written = 0;
7061 smb_t *smbp = (smb_t*) inp;
7065 unsigned short writeMode;
7067 fd = smb_GetSMBParm(inp, 0);
7068 totalCount = smb_GetSMBParm(inp, 1);
7069 count = smb_GetSMBParm(inp, 10);
7070 writeMode = smb_GetSMBParm(inp, 7);
7072 op = (char *) inp->data;
7073 op += smb_GetSMBParm(inp, 11);
7075 offset.HighPart = 0;
7076 offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
7078 if (*inp->wctp == 14) {
7079 /* we received a 64-bit file offset */
7080 #ifdef AFS_LARGEFILES
7081 offset.HighPart = smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16);
7083 if (LargeIntegerLessThanZero(offset)) {
7085 "smb_ReceiveCoreWriteRaw received negative file offset 0x%x:%08x",
7086 offset.HighPart, offset.LowPart);
7087 return CM_ERROR_BADSMB;
7090 if ((smb_GetSMBParm(inp, 12) | (smb_GetSMBParm(inp, 13) << 16)) != 0) {
7092 "smb_ReceiveCoreWriteRaw received 64-bit file offset, but we don't support large files");
7093 return CM_ERROR_BADSMB;
7096 offset.HighPart = 0;
7099 offset.HighPart = 0; /* 32-bit file offset */
7103 "smb_ReceiveCoreWriteRaw fd %d, off 0x%x:%08x, size 0x%x",
7104 fd, offset.HighPart, offset.LowPart, count);
7106 " WriteRaw WriteMode 0x%x",
7109 fd = smb_ChainFID(fd, inp);
7110 fidp = smb_FindFID(vcp, fd, 0);
7112 return CM_ERROR_BADFD;
7115 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7116 smb_CloseFID(vcp, fidp, NULL, 0);
7117 smb_ReleaseFID(fidp);
7118 return CM_ERROR_NOSUCHFILE;
7124 LARGE_INTEGER LOffset;
7125 LARGE_INTEGER LLength;
7128 key = cm_GenerateKey(vcp->vcID, pid, fd);
7130 LOffset.HighPart = offset.HighPart;
7131 LOffset.LowPart = offset.LowPart;
7132 LLength.HighPart = 0;
7133 LLength.LowPart = count;
7135 lock_ObtainWrite(&fidp->scp->rw);
7136 code = cm_LockCheckWrite(fidp->scp, LOffset, LLength, key);
7137 lock_ReleaseWrite(&fidp->scp->rw);
7140 smb_ReleaseFID(fidp);
7145 userp = smb_GetUserFromVCP(vcp, inp);
7148 * Work around bug in NT client
7150 * When copying a file, the NT client should first copy the data,
7151 * then copy the last write time. But sometimes the NT client does
7152 * these in the wrong order, so the data copies would inadvertently
7153 * cause the last write time to be overwritten. We try to detect this,
7154 * and don't set client mod time if we think that would go against the
7157 lock_ObtainMutex(&fidp->mx);
7158 if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
7159 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
7160 fidp->scp->clientModTime = time(NULL);
7162 lock_ReleaseMutex(&fidp->mx);
7165 while ( code == 0 && count > 0 ) {
7166 code = smb_WriteData(fidp, &offset, count, op, userp, &written);
7167 if (code == 0 && written == 0)
7168 code = CM_ERROR_PARTIALWRITE;
7170 offset = LargeIntegerAdd(offset,
7171 ConvertLongToLargeInteger(written));
7174 total_written += written;
7178 /* Get a raw buffer */
7181 lock_ObtainMutex(&smb_RawBufLock);
7183 /* Get a raw buf, from head of list */
7184 rawBuf = smb_RawBufs;
7185 smb_RawBufs = *(char **)smb_RawBufs;
7188 code = CM_ERROR_USESTD;
7190 lock_ReleaseMutex(&smb_RawBufLock);
7193 /* Don't allow a premature Close */
7194 if (code == 0 && (writeMode & 1) == 0) {
7195 lock_ObtainMutex(&fidp->mx);
7196 fidp->raw_writers++;
7197 thrd_ResetEvent(fidp->raw_write_event);
7198 lock_ReleaseMutex(&fidp->mx);
7201 smb_ReleaseFID(fidp);
7202 cm_ReleaseUser(userp);
7205 smb_SetSMBParm(outp, 0, total_written);
7206 smb_SetSMBDataLength(outp, 0);
7207 ((smb_t *)outp)->com = 0x20; /* SMB_COM_WRITE_COMPLETE */
7212 offset = LargeIntegerAdd(offset,
7213 ConvertLongToLargeInteger(count));
7217 rwcp->offset.HighPart = offset.HighPart;
7218 rwcp->offset.LowPart = offset.LowPart;
7219 rwcp->count = totalCount - count;
7220 rwcp->writeMode = writeMode;
7221 rwcp->alreadyWritten = total_written;
7223 /* set the packet data length to 3 bytes for the data block header,
7224 * plus the size of the data.
7226 smb_SetSMBParm(outp, 0, 0xffff);
7227 smb_SetSMBDataLength(outp, 0);
7233 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7236 long count, finalCount;
7240 smb_t *smbp = (smb_t*) inp;
7245 fd = smb_GetSMBParm(inp, 0);
7246 count = smb_GetSMBParm(inp, 1);
7247 offset.HighPart = 0; /* too bad */
7248 offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7250 osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
7251 fd, offset.LowPart, count);
7253 fd = smb_ChainFID(fd, inp);
7254 fidp = smb_FindFID(vcp, fd, 0);
7256 return CM_ERROR_BADFD;
7258 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7259 smb_CloseFID(vcp, fidp, NULL, 0);
7260 smb_ReleaseFID(fidp);
7261 return CM_ERROR_NOSUCHFILE;
7264 lock_ObtainMutex(&fidp->mx);
7265 if (fidp->flags & SMB_FID_IOCTL) {
7266 lock_ReleaseMutex(&fidp->mx);
7267 code = smb_IoctlRead(fidp, vcp, inp, outp);
7268 smb_ReleaseFID(fidp);
7271 lock_ReleaseMutex(&fidp->mx);
7274 LARGE_INTEGER LOffset, LLength;
7278 key = cm_GenerateKey(vcp->vcID, pid, fd);
7280 LOffset.HighPart = 0;
7281 LOffset.LowPart = offset.LowPart;
7282 LLength.HighPart = 0;
7283 LLength.LowPart = count;
7285 lock_ObtainWrite(&fidp->scp->rw);
7286 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
7287 lock_ReleaseWrite(&fidp->scp->rw);
7290 smb_ReleaseFID(fidp);
7294 userp = smb_GetUserFromVCP(vcp, inp);
7296 /* remember this for final results */
7297 smb_SetSMBParm(outp, 0, count);
7298 smb_SetSMBParm(outp, 1, 0);
7299 smb_SetSMBParm(outp, 2, 0);
7300 smb_SetSMBParm(outp, 3, 0);
7301 smb_SetSMBParm(outp, 4, 0);
7303 /* set the packet data length to 3 bytes for the data block header,
7304 * plus the size of the data.
7306 smb_SetSMBDataLength(outp, count+3);
7308 /* get op ptr after putting in the parms, since otherwise we don't
7309 * know where the data really is.
7311 op = smb_GetSMBData(outp, NULL);
7313 /* now emit the data block header: 1 byte of type and 2 bytes of length */
7314 *op++ = 1; /* data block marker */
7315 *op++ = (unsigned char) (count & 0xff);
7316 *op++ = (unsigned char) ((count >> 8) & 0xff);
7318 code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
7320 /* fix some things up */
7321 smb_SetSMBParm(outp, 0, finalCount);
7322 smb_SetSMBDataLength(outp, finalCount+3);
7324 smb_ReleaseFID(fidp);
7326 cm_ReleaseUser(userp);
7330 /* SMB_COM_CREATE_DIRECTORY */
7331 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7333 clientchar_t *pathp;
7338 cm_scache_t *dscp; /* dir we're dealing with */
7339 cm_scache_t *scp; /* file we're creating */
7341 int initialModeBits;
7342 clientchar_t *lastNamep;
7344 clientchar_t *tidPathp;
7351 /* compute initial mode bits based on read-only flag in attributes */
7352 initialModeBits = 0777;
7354 tp = smb_GetSMBData(inp, NULL);
7355 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7357 if (cm_ClientStrCmp(pathp, _C("\\")) == 0)
7358 return CM_ERROR_EXISTS;
7360 spacep = inp->spacep;
7361 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7363 userp = smb_GetUserFromVCP(vcp, inp);
7365 caseFold = CM_FLAG_CASEFOLD;
7367 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7369 cm_ReleaseUser(userp);
7370 return CM_ERROR_NOSUCHPATH;
7373 code = cm_NameI(cm_data.rootSCachep, spacep->wdata,
7374 caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
7375 userp, tidPathp, &req, &dscp);
7378 cm_ReleaseUser(userp);
7383 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7384 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7385 cm_ReleaseSCache(dscp);
7386 cm_ReleaseUser(userp);
7387 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7388 return CM_ERROR_PATH_NOT_COVERED;
7390 return CM_ERROR_BADSHARENAME;
7392 #endif /* DFS_SUPPORT */
7394 /* otherwise, scp points to the parent directory. Do a lookup, and
7395 * fail if we find it. Otherwise, we do the create.
7401 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7402 if (scp) cm_ReleaseSCache(scp);
7403 if (code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7404 if (code == 0) code = CM_ERROR_EXISTS;
7405 cm_ReleaseSCache(dscp);
7406 cm_ReleaseUser(userp);
7410 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7411 setAttr.clientModTime = time(NULL);
7412 code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req, NULL);
7413 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
7414 smb_NotifyChange(FILE_ACTION_ADDED,
7415 FILE_NOTIFY_CHANGE_DIR_NAME,
7416 dscp, lastNamep, NULL, TRUE);
7418 /* we don't need this any longer */
7419 cm_ReleaseSCache(dscp);
7422 /* something went wrong creating or truncating the file */
7423 cm_ReleaseUser(userp);
7427 /* otherwise we succeeded */
7428 smb_SetSMBDataLength(outp, 0);
7429 cm_ReleaseUser(userp);
7434 BOOL smb_IsLegalFilename(clientchar_t *filename)
7437 * Find the longest substring of filename that does not contain
7438 * any of the chars in illegalChars. If that substring is less
7439 * than the length of the whole string, then one or more of the
7440 * illegal chars is in filename.
7442 if (cm_ClientStrCSpn(filename, illegalChars) < cm_ClientStrLen(filename))
7448 /* SMB_COM_CREATE and SMB_COM_CREATE_NEW */
7449 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7451 clientchar_t *pathp;
7457 cm_scache_t *dscp; /* dir we're dealing with */
7458 cm_scache_t *scp; /* file we're creating */
7460 int initialModeBits;
7463 clientchar_t *lastNamep;
7466 clientchar_t *tidPathp;
7468 int created = 0; /* the file was new */
7473 excl = (inp->inCom == 0x03)? 0 : 1;
7475 attributes = smb_GetSMBParm(inp, 0);
7476 dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
7478 /* compute initial mode bits based on read-only flag in attributes */
7479 initialModeBits = 0666;
7480 if (attributes & SMB_ATTR_READONLY)
7481 initialModeBits &= ~0222;
7483 tp = smb_GetSMBData(inp, NULL);
7484 pathp = smb_ParseASCIIBlock(inp, tp, &tp, SMB_STRF_ANSIPATH);
7486 spacep = inp->spacep;
7487 smb_StripLastComponent(spacep->wdata, &lastNamep, pathp);
7489 userp = smb_GetUserFromVCP(vcp, inp);
7491 caseFold = CM_FLAG_CASEFOLD;
7493 code = smb_LookupTIDPath(vcp, ((smb_t *)inp)->tid, &tidPathp);
7495 cm_ReleaseUser(userp);
7496 return CM_ERROR_NOSUCHPATH;
7498 code = cm_NameI(cm_data.rootSCachep, spacep->wdata, caseFold | CM_FLAG_FOLLOW,
7499 userp, tidPathp, &req, &dscp);
7502 cm_ReleaseUser(userp);
7507 if (dscp->fileType == CM_SCACHETYPE_DFSLINK) {
7508 int pnc = cm_VolStatus_Notify_DFS_Mapping(dscp, tidPathp, spacep->wdata);
7509 cm_ReleaseSCache(dscp);
7510 cm_ReleaseUser(userp);
7511 if ( WANTS_DFS_PATHNAMES(inp) || pnc )
7512 return CM_ERROR_PATH_NOT_COVERED;
7514 return CM_ERROR_BADSHARENAME;
7516 #endif /* DFS_SUPPORT */
7518 /* otherwise, scp points to the parent directory. Do a lookup, and
7519 * truncate the file if we find it, otherwise we create the file.
7526 if (!smb_IsLegalFilename(lastNamep))
7527 return CM_ERROR_BADNTFILENAME;
7529 osi_Log1(smb_logp, "SMB receive create [%S]", osi_LogSaveClientString( smb_logp, pathp ));
7530 #ifdef DEBUG_VERBOSE
7533 hexp = osi_HexifyString( lastNamep );
7534 DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
7539 code = cm_Lookup(dscp, lastNamep, 0, userp, &req, &scp);
7540 if (code && code != CM_ERROR_NOSUCHFILE && code != CM_ERROR_BPLUS_NOMATCH) {
7541 cm_ReleaseSCache(dscp);
7542 cm_ReleaseUser(userp);
7546 /* if we get here, if code is 0, the file exists and is represented by
7547 * scp. Otherwise, we have to create it.
7551 /* oops, file shouldn't be there */
7552 cm_ReleaseSCache(dscp);
7553 cm_ReleaseSCache(scp);
7554 cm_ReleaseUser(userp);
7555 return CM_ERROR_EXISTS;
7558 setAttr.mask = CM_ATTRMASK_LENGTH;
7559 setAttr.length.LowPart = 0;
7560 setAttr.length.HighPart = 0;
7561 code = cm_SetAttr(scp, &setAttr, userp, &req);
7564 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
7565 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
7566 code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
7570 if (dscp->flags & CM_SCACHEFLAG_ANYWATCH)
7571 smb_NotifyChange(FILE_ACTION_ADDED,
7572 FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_CREATION,
7573 dscp, lastNamep, NULL, TRUE);
7574 } else if (!excl && code == CM_ERROR_EXISTS) {
7575 /* not an exclusive create, and someone else tried
7576 * creating it already, then we open it anyway. We
7577 * don't bother retrying after this, since if this next
7578 * fails, that means that the file was deleted after
7579 * we started this call.
7581 code = cm_Lookup(dscp, lastNamep, caseFold, userp,
7584 setAttr.mask = CM_ATTRMASK_LENGTH;
7585 setAttr.length.LowPart = 0;
7586 setAttr.length.HighPart = 0;
7587 code = cm_SetAttr(scp, &setAttr, userp, &req);
7592 /* we don't need this any longer */
7593 cm_ReleaseSCache(dscp);
7596 /* something went wrong creating or truncating the file */
7597 if (scp) cm_ReleaseSCache(scp);
7598 cm_ReleaseUser(userp);
7602 /* make sure we only open files */
7603 if (scp->fileType != CM_SCACHETYPE_FILE) {
7604 cm_ReleaseSCache(scp);
7605 cm_ReleaseUser(userp);
7606 return CM_ERROR_ISDIR;
7609 /* now all we have to do is open the file itself */
7610 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
7611 osi_assertx(fidp, "null smb_fid_t");
7615 lock_ObtainMutex(&fidp->mx);
7616 /* always create it open for read/write */
7617 fidp->flags |= (SMB_FID_OPENREAD_LISTDIR | SMB_FID_OPENWRITE);
7619 /* remember that the file was newly created */
7621 fidp->flags |= SMB_FID_CREATED;
7623 osi_Log2(smb_logp,"smb_ReceiveCoreCreate fidp 0x%p scp 0x%p", fidp, scp);
7625 /* save a pointer to the vnode */
7627 lock_ObtainWrite(&scp->rw);
7628 scp->flags |= CM_SCACHEFLAG_SMB_FID;
7629 lock_ReleaseWrite(&scp->rw);
7632 fidp->userp = userp;
7633 lock_ReleaseMutex(&fidp->mx);
7635 smb_SetSMBParm(outp, 0, fidp->fid);
7636 smb_SetSMBDataLength(outp, 0);
7638 cm_Open(scp, 0, userp);
7640 smb_ReleaseFID(fidp);
7641 cm_ReleaseUser(userp);
7642 /* leave scp held since we put it in fidp->scp */
7647 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
7650 osi_hyper_t new_offset;
7661 fd = smb_GetSMBParm(inp, 0);
7662 whence = smb_GetSMBParm(inp, 1);
7663 offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
7665 /* try to find the file descriptor */
7666 fd = smb_ChainFID(fd, inp);
7667 fidp = smb_FindFID(vcp, fd, 0);
7669 return CM_ERROR_BADFD;
7671 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
7672 smb_CloseFID(vcp, fidp, NULL, 0);
7673 smb_ReleaseFID(fidp);
7674 return CM_ERROR_NOSUCHFILE;
7677 lock_ObtainMutex(&fidp->mx);
7678 if (fidp->flags & SMB_FID_IOCTL) {
7679 lock_ReleaseMutex(&fidp->mx);
7680 smb_ReleaseFID(fidp);
7681 return CM_ERROR_BADFD;
7683 lock_ReleaseMutex(&fidp->mx);
7685 userp = smb_GetUserFromVCP(vcp, inp);
7687 lock_ObtainMutex(&fidp->mx);
7690 lock_ReleaseMutex(&fidp->mx);
7691 lock_ObtainWrite(&scp->rw);
7692 code = cm_SyncOp(scp, NULL, userp, &req, 0,
7693 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7695 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
7697 /* offset from current offset */
7698 new_offset = LargeIntegerAdd(fidp->offset,
7699 ConvertLongToLargeInteger(offset));
7701 else if (whence == 2) {
7702 /* offset from current EOF */
7703 new_offset = LargeIntegerAdd(scp->length,
7704 ConvertLongToLargeInteger(offset));
7706 new_offset = ConvertLongToLargeInteger(offset);
7709 fidp->offset = new_offset;
7710 smb_SetSMBParm(outp, 0, new_offset.LowPart & 0xffff);
7711 smb_SetSMBParm(outp, 1, (new_offset.LowPart>>16) & 0xffff);
7712 smb_SetSMBDataLength(outp, 0);
7714 lock_ReleaseWrite(&scp->rw);
7715 smb_ReleaseFID(fidp);
7716 cm_ReleaseSCache(scp);
7717 cm_ReleaseUser(userp);
7721 /* dispatch all of the requests received in a packet. Due to chaining, this may
7722 * be more than one request.
7724 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
7725 NCB *ncbp, raw_write_cont_t *rwcp)
7729 unsigned long code = 0;
7730 unsigned char *outWctp;
7731 int nparms; /* # of bytes of parameters */
7733 int nbytes; /* bytes of data, excluding count */
7736 unsigned short errCode;
7737 unsigned long NTStatus;
7739 unsigned char errClass;
7740 unsigned int oldGen;
7741 DWORD oldTime, newTime;
7743 /* get easy pointer to the data */
7744 smbp = (smb_t *) inp->data;
7746 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
7747 /* setup the basic parms for the initial request in the packet */
7748 inp->inCom = smbp->com;
7749 inp->wctp = &smbp->wct;
7751 inp->ncb_length = ncbp->ncb_length;
7756 if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
7757 /* log it and discard it */
7758 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_TOO_SHORT,
7759 __FILE__, __LINE__, ncbp->ncb_length);
7760 osi_Log1(smb_logp, "SMB message too short, len %d", ncbp->ncb_length);
7764 /* We are an ongoing op */
7765 thrd_Increment(&ongoingOps);
7767 /* set up response packet for receiving output */
7768 if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
7769 smb_FormatResponsePacket(vcp, inp, outp);
7770 outWctp = outp->wctp;
7772 /* Remember session generation number and time */
7773 oldGen = sessionGen;
7774 oldTime = GetTickCount();
7776 while (inp->inCom != 0xff) {
7777 dp = &smb_dispatchTable[inp->inCom];
7779 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
7780 outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
7781 code = outp->resumeCode;
7785 /* process each request in the packet; inCom, wctp and inCount
7786 * are already set up.
7788 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
7791 /* now do the dispatch */
7792 /* start by formatting the response record a little, as a default */
7793 if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
7795 outWctp[1] = 0xff; /* no operation */
7796 outWctp[2] = 0; /* padding */
7801 /* not a chained request, this is a more reasonable default */
7802 outWctp[0] = 0; /* wct of zero */
7803 outWctp[1] = 0; /* and bcc (word) of zero */
7807 /* once set, stays set. Doesn't matter, since we never chain
7808 * "no response" calls.
7810 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
7814 /* we have a recognized operation */
7815 char * opName = myCrt_Dispatch(inp->inCom);
7817 if (inp->inCom == 0x1d)
7819 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp, rwcp);
7821 osi_Log4(smb_logp,"Dispatch %s vcp 0x%p lana %d lsn %d",
7822 opName,vcp,vcp->lana,vcp->lsn);
7823 code = (*(dp->procp)) (vcp, inp, outp);
7824 osi_Log4(smb_logp,"Dispatch return code 0x%x vcp 0x%p lana %d lsn %d",
7825 code,vcp,vcp->lana,vcp->lsn);
7827 if ( code == CM_ERROR_BADSMB ||
7828 code == CM_ERROR_BADOP )
7830 #endif /* LOG_PACKET */
7833 newTime = GetTickCount();
7834 osi_Log2(smb_logp, "Dispatch %s duration %d ms", opName, newTime - oldTime);
7836 if (oldGen != sessionGen) {
7837 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_WRONG_SESSION,
7838 newTime - oldTime, ncbp->ncb_length);
7839 osi_Log3(smb_logp, "Request %s straddled session startup, "
7840 "took %d ms, ncb length %d", opName, newTime - oldTime, ncbp->ncb_length);
7843 FreeSMBStrings(inp);
7845 /* bad opcode, fail the request, after displaying it */
7846 osi_Log1(smb_logp, "Received bad SMB req 0x%X", inp->inCom);
7849 #endif /* LOG_PACKET */
7852 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
7853 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
7854 MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
7855 if (code == IDCANCEL)
7858 code = CM_ERROR_BADOP;
7861 /* catastrophic failure: log as much as possible */
7862 if (code == CM_ERROR_BADSMB) {
7863 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INVALID,
7867 #endif /* LOG_PACKET */
7868 osi_Log1(smb_logp, "Invalid SMB message, length %d",
7871 code = CM_ERROR_INVAL;
7874 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
7875 thrd_Decrement(&ongoingOps);
7880 /* now, if we failed, turn the current response into an empty
7881 * one, and fill in the response packet's error code.
7884 if (vcp->flags & SMB_VCFLAG_STATUS32) {
7885 smb_MapNTError(code, &NTStatus);
7886 outWctp = outp->wctp;
7887 smbp = (smb_t *) &outp->data;
7888 if (code != CM_ERROR_PARTIALWRITE
7889 && code != CM_ERROR_BUFFERTOOSMALL
7890 && code != CM_ERROR_GSSCONTINUE) {
7891 /* nuke wct and bcc. For a partial
7892 * write or an in-process authentication handshake,
7893 * assume they're OK.
7899 smbp->rcls = (unsigned char) (NTStatus & 0xff);
7900 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
7901 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
7902 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
7903 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
7907 smb_MapCoreError(code, vcp, &errCode, &errClass);
7908 outWctp = outp->wctp;
7909 smbp = (smb_t *) &outp->data;
7910 if (code != CM_ERROR_PARTIALWRITE) {
7911 /* nuke wct and bcc. For a partial
7912 * write, assume they're OK.
7918 smbp->errLow = (unsigned char) (errCode & 0xff);
7919 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
7920 smbp->rcls = errClass;
7923 } /* error occurred */
7925 /* if we're here, we've finished one request. Look to see if
7926 * this is a chained opcode. If it is, setup things to process
7927 * the chained request, and setup the output buffer to hold the
7928 * chained response. Start by finding the next input record.
7930 if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
7931 break; /* not a chained req */
7932 tp = inp->wctp; /* points to start of last request */
7933 /* in a chained request, the first two
7934 * parm fields are required, and are
7935 * AndXCommand/AndXReserved and
7937 if (tp[0] < 2) break;
7938 if (tp[1] == 0xff) break; /* no more chained opcodes */
7940 inp->wctp = inp->data + tp[3] + (tp[4] << 8);
7943 /* and now append the next output request to the end of this
7944 * last request. Begin by finding out where the last response
7945 * ends, since that's where we'll put our new response.
7947 outWctp = outp->wctp; /* ptr to out parameters */
7948 osi_assert (outWctp[0] >= 2); /* need this for all chained requests */
7949 nparms = outWctp[0] << 1;
7950 tp = outWctp + nparms + 1; /* now points to bcc field */
7951 nbytes = tp[0] + (tp[1] << 8); /* # of data bytes */
7952 tp += 2 /* for the count itself */ + nbytes;
7953 /* tp now points to the new output record; go back and patch the
7954 * second parameter (off2) to point to the new record.
7956 temp = (unsigned int)(tp - outp->data);
7957 outWctp[3] = (unsigned char) (temp & 0xff);
7958 outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
7959 outWctp[2] = 0; /* padding */
7960 outWctp[1] = inp->inCom; /* next opcode */
7962 /* finally, setup for the next iteration */
7965 } /* while loop over all requests in the packet */
7967 /* now send the output packet, and return */
7969 smb_SendPacket(vcp, outp);
7970 thrd_Decrement(&ongoingOps);
7975 /* Wait for Netbios() calls to return, and make the results available to server
7976 * threads. Note that server threads can't wait on the NCBevents array
7977 * themselves, because NCB events are manual-reset, and the servers would race
7978 * each other to reset them.
7980 void smb_ClientWaiter(void *parmp)
7985 while (smbShutdownFlag == 0) {
7986 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
7988 if (code == WAIT_OBJECT_0)
7991 /* error checking */
7992 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
7994 int abandonIdx = code - WAIT_ABANDONED_0;
7995 osi_Log2(smb_logp, "Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
7998 if (code == WAIT_IO_COMPLETION)
8000 osi_Log0(smb_logp, "Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
8004 if (code == WAIT_TIMEOUT)
8006 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
8009 if (code == WAIT_FAILED)
8011 osi_Log1(smb_logp, "Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
8014 idx = code - WAIT_OBJECT_0;
8016 /* check idx range! */
8017 if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
8019 /* this is fatal - log as much as possible */
8020 osi_Log1(smb_logp, "Fatal: NCBevents idx [ %d ] out of range.\n", idx);
8021 osi_assertx(0, "invalid index");
8024 thrd_ResetEvent(NCBevents[idx]);
8025 thrd_SetEvent(NCBreturns[0][idx]);
8030 * Try to have one NCBRECV request waiting for every live session. Not more
8031 * than one, because if there is more than one, it's hard to handle Write Raw.
8033 void smb_ServerWaiter(void *parmp)
8036 int idx_session, idx_NCB;
8039 while (smbShutdownFlag == 0) {
8041 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
8043 if (code == WAIT_OBJECT_0)
8046 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
8048 int abandonIdx = code - WAIT_ABANDONED_0;
8049 osi_Log2(smb_logp, "Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8052 if (code == WAIT_IO_COMPLETION)
8054 osi_Log0(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
8058 if (code == WAIT_TIMEOUT)
8060 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
8063 if (code == WAIT_FAILED)
8065 osi_Log1(smb_logp, "Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
8068 idx_session = code - WAIT_OBJECT_0;
8070 /* check idx range! */
8071 if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
8073 /* this is fatal - log as much as possible */
8074 osi_Log1(smb_logp, "Fatal: session idx [ %d ] out of range.\n", idx_session);
8075 osi_assertx(0, "invalid index");
8080 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
8082 if (code == WAIT_OBJECT_0) {
8083 if (smbShutdownFlag == 1)
8089 /* error checking */
8090 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8092 int abandonIdx = code - WAIT_ABANDONED_0;
8093 osi_Log2(smb_logp, "Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
8096 if (code == WAIT_IO_COMPLETION)
8098 osi_Log0(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
8102 if (code == WAIT_TIMEOUT)
8104 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
8107 if (code == WAIT_FAILED)
8109 osi_Log1(smb_logp, "Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
8112 idx_NCB = code - WAIT_OBJECT_0;
8114 /* check idx range! */
8115 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
8117 /* this is fatal - log as much as possible */
8118 osi_Log1(smb_logp, "Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
8119 osi_assertx(0, "invalid index");
8122 /* Link them together */
8123 NCBsessions[idx_NCB] = idx_session;
8126 ncbp = NCBs[idx_NCB];
8127 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
8128 ncbp->ncb_command = NCBRECV | ASYNCH;
8129 ncbp->ncb_lana_num = lanas[idx_session];
8130 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
8131 ncbp->ncb_event = NCBevents[idx_NCB];
8132 ncbp->ncb_length = SMB_PACKETSIZE;
8138 * The top level loop for handling SMB request messages. Each server thread
8139 * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
8140 * NCB and buffer for the incoming request are loaned to us.
8142 * Write Raw trickery starts here. When we get a Write Raw, we are supposed
8143 * to immediately send a request for the rest of the data. This must come
8144 * before any other traffic for that session, so we delay setting the session
8145 * event until that data has come in.
8147 void smb_Server(VOID *parmp)
8149 INT_PTR myIdx = (INT_PTR) parmp;
8153 smb_packet_t *outbufp;
8155 int idx_NCB, idx_session;
8157 smb_vc_t *vcp = NULL;
8159 extern void rx_StartClientThread(void);
8161 rx_StartClientThread();
8164 outbufp = GetPacket();
8165 outbufp->ncbp = outncbp;
8173 smb_ResetServerPriority();
8175 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
8178 /* terminate silently if shutdown flag is set */
8179 if (code == WAIT_OBJECT_0) {
8180 if (smbShutdownFlag == 1) {
8181 thrd_SetEvent(smb_ServerShutdown[myIdx]);
8187 /* error checking */
8188 if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
8190 int abandonIdx = code - WAIT_ABANDONED_0;
8191 osi_Log3(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
8194 if (code == WAIT_IO_COMPLETION)
8196 osi_Log1(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
8200 if (code == WAIT_TIMEOUT)
8202 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
8205 if (code == WAIT_FAILED)
8207 osi_Log2(smb_logp, "Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
8210 idx_NCB = code - WAIT_OBJECT_0;
8212 /* check idx range! */
8213 if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
8215 /* this is fatal - log as much as possible */
8216 osi_Log1(smb_logp, "Fatal: idx_NCB %d out of range.\n", idx_NCB);
8217 osi_assertx(0, "invalid index");
8220 ncbp = NCBs[idx_NCB];
8221 idx_session = NCBsessions[idx_NCB];
8222 rc = ncbp->ncb_retcode;
8224 if (rc != NRC_PENDING && rc != NRC_GOODRET)
8225 osi_Log3(smb_logp, "NCBRECV failure lsn %d session %d: %s", ncbp->ncb_lsn, idx_session, ncb_error_string(rc));
8229 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8233 /* Can this happen? Or is it just my UNIX paranoia? */
8234 osi_Log2(smb_logp, "NCBRECV pending lsn %d session %d", ncbp->ncb_lsn, idx_session);
8239 LogEvent(EVENTLOG_WARNING_TYPE, MSG_UNEXPECTED_SMB_SESSION_CLOSE, ncb_error_string(rc));
8242 /* Client closed session */
8243 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8245 lock_ObtainMutex(&vcp->mx);
8246 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8247 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8249 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8250 lock_ReleaseMutex(&vcp->mx);
8251 lock_ObtainWrite(&smb_globalLock);
8252 dead_sessions[vcp->session] = TRUE;
8253 lock_ReleaseWrite(&smb_globalLock);
8254 smb_CleanupDeadVC(vcp);
8258 lock_ReleaseMutex(&vcp->mx);
8264 /* Treat as transient error */
8265 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_SMB_INCOMPLETE,
8268 "dispatch smb recv failed, message incomplete, ncb_length %d",
8271 "SMB message incomplete, "
8272 "length %d", ncbp->ncb_length);
8275 * We used to discard the packet.
8276 * Instead, try handling it normally.
8280 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8284 /* A weird error code. Log it, sleep, and continue. */
8285 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
8287 lock_ObtainMutex(&vcp->mx);
8288 if (vcp && vcp->errorCount++ > 3) {
8289 osi_Log2(smb_logp, "session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
8290 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8291 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8293 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8294 lock_ReleaseMutex(&vcp->mx);
8295 lock_ObtainWrite(&smb_globalLock);
8296 dead_sessions[vcp->session] = TRUE;
8297 lock_ReleaseWrite(&smb_globalLock);
8298 smb_CleanupDeadVC(vcp);
8302 lock_ReleaseMutex(&vcp->mx);
8308 lock_ReleaseMutex(&vcp->mx);
8310 thrd_SetEvent(SessionEvents[idx_session]);
8315 /* Success, so now dispatch on all the data in the packet */
8317 smb_concurrentCalls++;
8318 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
8319 smb_maxObsConcurrentCalls = smb_concurrentCalls;
8322 * If at this point vcp is NULL (implies that packet was invalid)
8323 * then we are in big trouble. This means either :
8324 * a) we have the wrong NCB.
8325 * b) Netbios screwed up the call.
8326 * c) The VC was already marked dead before we were able to
8328 * Obviously this implies that
8329 * ( LSNs[idx_session] != ncbp->ncb_lsn ||
8330 * lanas[idx_session] != ncbp->ncb_lana_num )
8331 * Either way, we can't do anything with this packet.
8332 * Log, sleep and resume.
8335 LogEvent(EVENTLOG_WARNING_TYPE, MSG_BAD_VCP,
8339 ncbp->ncb_lana_num);
8341 /* Also log in the trace log. */
8342 osi_Log4(smb_logp, "Server: VCP does not exist!"
8343 "LSNs[idx_session]=[%d],"
8344 "lanas[idx_session]=[%d],"
8345 "ncbp->ncb_lsn=[%d],"
8346 "ncbp->ncb_lana_num=[%d]",
8350 ncbp->ncb_lana_num);
8352 /* thrd_Sleep(1000); Don't bother sleeping */
8353 thrd_SetEvent(SessionEvents[idx_session]);
8354 smb_concurrentCalls--;
8358 smb_SetRequestStartTime();
8360 vcp->errorCount = 0;
8361 bufp = (struct smb_packet *) ncbp->ncb_buffer;
8362 smbp = (smb_t *)bufp->data;
8369 if (smbp->com == 0x1d) {
8370 /* Special handling for Write Raw */
8371 raw_write_cont_t rwc;
8372 EVENT_HANDLE rwevent;
8373 char eventName[MAX_PATH];
8375 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
8376 if (rwc.code == 0) {
8377 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
8378 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8379 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8380 ncbp->ncb_command = NCBRECV | ASYNCH;
8381 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
8382 ncbp->ncb_lana_num = vcp->lana;
8383 ncbp->ncb_buffer = rwc.buf;
8384 ncbp->ncb_length = 65535;
8385 ncbp->ncb_event = rwevent;
8387 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
8388 thrd_CloseHandle(rwevent);
8390 thrd_SetEvent(SessionEvents[idx_session]);
8392 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
8394 else if (smbp->com == 0xa0) {
8396 * Serialize the handling for NT Transact
8399 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8400 thrd_SetEvent(SessionEvents[idx_session]);
8402 thrd_SetEvent(SessionEvents[idx_session]);
8403 /* TODO: what else needs to be serialized? */
8404 smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
8408 __except( smb_ServerExceptionFilter() ) {
8412 smb_concurrentCalls--;
8415 thrd_SetEvent(NCBavails[idx_NCB]);
8422 * Exception filter for the server threads. If an exception occurs in the
8423 * dispatch routines, which is where exceptions are most common, then do a
8424 * force trace and give control to upstream exception handlers. Useful for
8427 DWORD smb_ServerExceptionFilter(void) {
8428 /* While this is not the best time to do a trace, if it succeeds, then
8429 * we have a trace (assuming tracing was enabled). Otherwise, this should
8430 * throw a second exception.
8432 LogEvent(EVENTLOG_ERROR_TYPE, MSG_UNHANDLED_EXCEPTION);
8433 afsd_ForceTrace(TRUE);
8434 buf_ForceTrace(TRUE);
8435 return EXCEPTION_CONTINUE_SEARCH;
8439 * Create a new NCB and associated events, packet buffer, and "space" buffer.
8440 * If the number of server threads is M, and the number of live sessions is
8441 * N, then the number of NCB's in use at any time either waiting for, or
8442 * holding, received messages is M + N, so that is how many NCB's get created.
8444 void InitNCBslot(int idx)
8446 struct smb_packet *bufp;
8447 EVENT_HANDLE retHandle;
8449 char eventName[MAX_PATH];
8451 osi_assertx( idx < (sizeof(NCBs) / sizeof(NCBs[0])), "invalid index" );
8453 NCBs[idx] = GetNCB();
8454 sprintf(eventName,"NCBavails[%d]", idx);
8455 NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8456 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8457 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8458 sprintf(eventName,"NCBevents[%d]", idx);
8459 NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
8460 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8461 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8462 sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
8463 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8464 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8465 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8466 for (i=0; i<smb_NumServerThreads; i++)
8467 NCBreturns[i][idx] = retHandle;
8469 bufp->spacep = cm_GetSpace();
8473 /* listen for new connections */
8474 void smb_Listener(void *parmp)
8480 afs_uint32 session, thread;
8481 smb_vc_t *vcp = NULL;
8483 char rname[NCBNAMSZ+1];
8484 char cname[MAX_COMPUTERNAME_LENGTH+1];
8485 int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
8486 INT_PTR lana = (INT_PTR) parmp;
8487 char eventName[MAX_PATH];
8489 sprintf(eventName,"smb_Listener_lana_%d", (unsigned char)lana);
8490 ListenerShutdown[lana] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
8491 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8492 thrd_ResetEvent(ListenerShutdown[lana]);
8496 /* retrieve computer name */
8497 GetComputerName(cname, &cnamelen);
8500 while (smb_ListenerState == SMB_LISTENER_STARTED) {
8501 memset(ncbp, 0, sizeof(NCB));
8504 ncbp->ncb_command = NCBLISTEN;
8505 ncbp->ncb_rto = 0; /* No receive timeout */
8506 ncbp->ncb_sto = 0; /* No send timeout */
8508 /* pad out with spaces instead of null termination */
8509 len = (long)strlen(smb_localNamep);
8510 strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
8511 for (i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
8513 strcpy(ncbp->ncb_callname, "*");
8514 for (i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
8516 ncbp->ncb_lana_num = (UCHAR)lana;
8518 code = Netbios(ncbp);
8520 if (code == NRC_NAMERR) {
8521 /* An smb shutdown or Vista resume must have taken place */
8523 "NCBLISTEN lana=%d failed with NRC_NAMERR.",
8524 ncbp->ncb_lana_num, code);
8526 if (lock_TryMutex(&smb_StartedLock)) {
8527 lana_list.lana[i] = LANA_INVALID;
8528 lock_ReleaseMutex(&smb_StartedLock);
8531 } else if (code == NRC_BRIDGE || code != 0) {
8532 int lanaRemaining = 0;
8534 while (!lock_TryMutex(&smb_StartedLock)) {
8535 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8541 "NCBLISTEN lana=%d failed with %s. Listener thread exiting.",
8542 ncbp->ncb_lana_num, ncb_error_string(code));
8544 for (i = 0; i < lana_list.length; i++) {
8545 if (lana_list.lana[i] == lana) {
8546 smb_StopListener(ncbp, lana_list.lana[i], FALSE);
8547 lana_list.lana[i] = LANA_INVALID;
8549 if (lana_list.lana[i] != LANA_INVALID)
8553 if (lanaRemaining == 0) {
8554 cm_VolStatus_Network_Stopped(cm_NetbiosName
8559 smb_ListenerState = SMB_LISTENER_STOPPED;
8560 smb_LANadapter = LANA_INVALID;
8561 lana_list.length = 0;
8563 lock_ReleaseMutex(&smb_StartedLock);
8567 else if (code != 0) {
8568 char tbuffer[AFSPATHMAX];
8570 /* terminate silently if shutdown flag is set */
8571 while (!lock_TryMutex(&smb_StartedLock)) {
8572 if (smb_ListenerState == SMB_LISTENER_STOPPED || smbShutdownFlag == 1)
8578 "NCBLISTEN lana=%d failed with code %d [%s]",
8579 ncbp->ncb_lana_num, code, ncb_error_string(code));
8581 "Client exiting due to network failure. Please restart client.\n");
8584 "Client exiting due to network failure. Please restart client.\n"
8585 "NCBLISTEN lana=%d failed with code %d [%s]",
8586 ncbp->ncb_lana_num, code, ncb_error_string(code));
8588 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
8589 MB_OK|MB_SERVICE_NOTIFICATION);
8590 osi_panic(tbuffer, __FILE__, __LINE__);
8592 lock_ReleaseMutex(&smb_StartedLock);
8597 /* check for remote conns */
8598 /* first get remote name and insert null terminator */
8599 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
8600 for (i=NCBNAMSZ; i>0; i--) {
8601 if (rname[i-1] != ' ' && rname[i-1] != 0) {
8607 /* compare with local name */
8609 if (strncmp(rname, cname, NCBNAMSZ) != 0)
8610 flags |= SMB_VCFLAG_REMOTECONN;
8613 lock_ObtainMutex(&smb_ListenerLock);
8615 osi_Log1(smb_logp, "NCBLISTEN completed, call from %s", osi_LogSaveString(smb_logp, rname));
8616 osi_Log1(smb_logp, "SMB session startup, %d ongoing ops", ongoingOps);
8618 /* now ncbp->ncb_lsn is the connection ID */
8619 vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
8620 if (vcp->session == 0) {
8621 /* New generation */
8622 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
8625 /* Log session startup */
8627 fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8628 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8629 #endif /* NOTSERVICE */
8630 osi_Log4(smb_logp, "New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8631 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8633 if (reportSessionStartups) {
8634 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8637 lock_ObtainMutex(&vcp->mx);
8638 cm_Utf8ToUtf16(rname, -1, vcp->rname, lengthof(vcp->rname));
8639 vcp->flags |= flags;
8640 lock_ReleaseMutex(&vcp->mx);
8642 /* Allocate slot in session arrays */
8643 /* Re-use dead session if possible, otherwise add one more */
8644 /* But don't look at session[0], it is reserved */
8645 lock_ObtainWrite(&smb_globalLock);
8646 for (session = 1; session < numSessions; session++) {
8647 if (dead_sessions[session]) {
8648 osi_Log1(smb_logp, "connecting to dead session [ %d ]", session);
8649 dead_sessions[session] = FALSE;
8653 lock_ReleaseWrite(&smb_globalLock);
8655 /* We are re-using an existing VC because the lsn and lana
8657 session = vcp->session;
8659 osi_Log1(smb_logp, "Re-using session lsn %d", ncbp->ncb_lsn);
8661 /* Log session startup */
8663 fprintf(stderr, "Re-using session(ncb_lsn,ncb_lana_num) %d,%d starting from host %s\n",
8664 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
8665 #endif /* NOTSERVICE */
8666 osi_Log4(smb_logp, "Re-using session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
8667 ncbp->ncb_lsn,ncbp->ncb_lana_num, osi_LogSaveString(smb_logp, rname), ongoingOps);
8669 if (reportSessionStartups) {
8670 LogEvent(EVENTLOG_INFORMATION_TYPE, MSG_SMB_SESSION_START, ongoingOps);
8674 if (session >= SESSION_MAX - 1 || numNCBs >= NCB_MAX - 1) {
8675 unsigned long code = CM_ERROR_ALLBUSY;
8676 smb_packet_t * outp = GetPacket();
8677 unsigned char *outWctp;
8680 smb_FormatResponsePacket(vcp, NULL, outp);
8683 if (vcp->flags & SMB_VCFLAG_STATUS32) {
8684 unsigned long NTStatus;
8685 smb_MapNTError(code, &NTStatus);
8686 outWctp = outp->wctp;
8687 smbp = (smb_t *) &outp->data;
8691 smbp->rcls = (unsigned char) (NTStatus & 0xff);
8692 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
8693 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
8694 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
8695 smbp->flg2 |= SMB_FLAGS2_32BIT_STATUS;
8697 unsigned short errCode;
8698 unsigned char errClass;
8699 smb_MapCoreError(code, vcp, &errCode, &errClass);
8700 outWctp = outp->wctp;
8701 smbp = (smb_t *) &outp->data;
8705 smbp->errLow = (unsigned char) (errCode & 0xff);
8706 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
8707 smbp->rcls = errClass;
8710 smb_SendPacket(vcp, outp);
8711 smb_FreePacket(outp);
8713 lock_ObtainMutex(&vcp->mx);
8714 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
8715 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
8717 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
8718 lock_ReleaseMutex(&vcp->mx);
8719 lock_ObtainWrite(&smb_globalLock);
8720 dead_sessions[vcp->session] = TRUE;
8721 lock_ReleaseWrite(&smb_globalLock);
8722 smb_CleanupDeadVC(vcp);
8724 lock_ReleaseMutex(&vcp->mx);
8727 /* assert that we do not exceed the maximum number of sessions or NCBs.
8728 * we should probably want to wait for a session to be freed in case
8731 osi_assertx(session < SESSION_MAX - 1, "invalid session");
8732 osi_assertx(numNCBs < NCB_MAX - 1, "invalid numNCBs"); /* if we pass this test we can allocate one more */
8734 lock_ObtainMutex(&vcp->mx);
8735 vcp->session = session;
8736 lock_ReleaseMutex(&vcp->mx);
8737 lock_ObtainWrite(&smb_globalLock);
8738 LSNs[session] = ncbp->ncb_lsn;
8739 lanas[session] = ncbp->ncb_lana_num;
8740 lock_ReleaseWrite(&smb_globalLock);
8742 if (session == numSessions) {
8743 /* Add new NCB for new session */
8744 char eventName[MAX_PATH];
8746 osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
8748 InitNCBslot(numNCBs);
8749 lock_ObtainWrite(&smb_globalLock);
8751 lock_ReleaseWrite(&smb_globalLock);
8752 thrd_SetEvent(NCBavails[0]);
8753 thrd_SetEvent(NCBevents[0]);
8754 for (thread = 0; thread < smb_NumServerThreads; thread++)
8755 thrd_SetEvent(NCBreturns[thread][0]);
8756 /* Also add new session event */
8757 sprintf(eventName, "SessionEvents[%d]", session);
8758 SessionEvents[session] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
8759 if ( GetLastError() == ERROR_ALREADY_EXISTS )
8760 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
8761 lock_ObtainWrite(&smb_globalLock);
8763 lock_ReleaseWrite(&smb_globalLock);
8764 osi_Log2(smb_logp, "increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
8765 thrd_SetEvent(SessionEvents[0]);
8767 thrd_SetEvent(SessionEvents[session]);
8773 lock_ReleaseMutex(&smb_ListenerLock);
8774 } /* dispatch while loop */
8778 thrd_SetEvent(ListenerShutdown[lana]);
8783 smb_LanAdapterChangeThread(void *param)
8786 * Give the IPAddrDaemon thread a chance
8787 * to block before we trigger.
8790 smb_LanAdapterChange(0);
8793 void smb_SetLanAdapterChangeDetected(void)
8798 lock_ObtainMutex(&smb_StartedLock);
8800 if (!powerStateSuspended) {
8801 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_LanAdapterChangeThread,
8802 NULL, 0, &lpid, "smb_LanAdapterChange");
8803 osi_assertx(phandle != NULL, "smb_LanAdapterChangeThread thread creation failure");
8804 thrd_CloseHandle(phandle);
8807 smb_LanAdapterChangeDetected = 1;
8808 lock_ReleaseMutex(&smb_StartedLock);
8811 void smb_LanAdapterChange(int locked) {
8812 lana_number_t lanaNum;
8814 char NetbiosName[MAX_NB_NAME_LENGTH] = "";
8816 LANA_ENUM temp_list;
8821 afsi_log("smb_LanAdapterChange");
8824 lock_ObtainMutex(&smb_StartedLock);
8826 smb_LanAdapterChangeDetected = 0;
8828 if (!powerStateSuspended &&
8829 SUCCEEDED(lana_GetUncServerNameEx(NetbiosName, &lanaNum, &bGateway,
8830 LANA_NETBIOS_NAME_FULL)) &&
8831 lanaNum != LANA_INVALID && smb_LANadapter != lanaNum) {
8832 if ( isGateway != bGateway ||
8833 strcmp(cm_NetbiosName, NetbiosName) ) {
8836 NCB *ncbp = GetNCB();
8837 ncbp->ncb_command = NCBENUM;
8838 ncbp->ncb_buffer = (PUCHAR)&temp_list;
8839 ncbp->ncb_length = sizeof(temp_list);
8840 code = Netbios(ncbp);
8842 if (temp_list.length != lana_list.length)
8845 for (i=0; i<lana_list.length; i++) {
8846 if ( temp_list.lana[i] != lana_list.lana[i] ) {
8858 afsi_log("Lan Adapter Change detected");
8859 smb_StopListeners(1);
8860 smb_RestartListeners(1);
8863 lock_ReleaseMutex(&smb_StartedLock);
8866 /* initialize Netbios */
8867 int smb_NetbiosInit(int locked)
8870 int i, lana, code, l;
8872 int delname_tried=0;
8875 lana_number_t lanaNum;
8878 lock_ObtainMutex(&smb_StartedLock);
8880 if (smb_ListenerState != SMB_LISTENER_UNINITIALIZED &&
8881 smb_ListenerState != SMB_LISTENER_STOPPED) {
8884 lock_ReleaseMutex(&smb_StartedLock);
8887 /* setup the NCB system */
8890 /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */
8891 if (SUCCEEDED(code = lana_GetUncServerNameEx(cm_NetbiosName, &lanaNum, &isGateway, LANA_NETBIOS_NAME_FULL))) {
8892 smb_LANadapter = (lanaNum == LANA_INVALID)? -1: lanaNum;
8894 if (smb_LANadapter != LANA_INVALID)
8895 afsi_log("LAN adapter number %d", smb_LANadapter);
8897 afsi_log("LAN adapter number not determined");
8900 afsi_log("Set for gateway service");
8902 afsi_log("Using >%s< as SMB server name", cm_NetbiosName);
8904 /* something went horribly wrong. We can't proceed without a netbios name */
8906 StringCbPrintfA(buf,sizeof(buf),"Netbios name could not be determined: %li", code);
8907 osi_panic(buf, __FILE__, __LINE__);
8910 /* remember the name */
8911 len = (int)strlen(cm_NetbiosName);
8913 free(smb_localNamep);
8914 smb_localNamep = malloc(len+1);
8915 strcpy(smb_localNamep, cm_NetbiosName);
8916 afsi_log("smb_localNamep is >%s<", smb_localNamep);
8918 /* Also copy the value to the client character encoded string */
8919 cm_Utf8ToClientString(cm_NetbiosName, -1, cm_NetbiosNameC, MAX_NB_NAME_LENGTH);
8921 if (smb_LANadapter == LANA_INVALID) {
8922 ncbp->ncb_command = NCBENUM;
8923 ncbp->ncb_buffer = (PUCHAR)&lana_list;
8924 ncbp->ncb_length = sizeof(lana_list);
8925 code = Netbios(ncbp);
8927 afsi_log("Netbios NCBENUM error code %d", code);
8928 osi_panic(s, __FILE__, __LINE__);
8932 lana_list.length = 1;
8933 lana_list.lana[0] = smb_LANadapter;
8936 for (i = 0; i < lana_list.length; i++) {
8937 /* reset the adaptor: in Win32, this is required for every process, and
8938 * acts as an init call, not as a real hardware reset.
8940 ncbp->ncb_command = NCBRESET;
8941 ncbp->ncb_callname[0] = 100;
8942 ncbp->ncb_callname[2] = 100;
8943 ncbp->ncb_lana_num = lana_list.lana[i];
8944 code = Netbios(ncbp);
8946 code = ncbp->ncb_retcode;
8948 afsi_log("Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
8949 lana_list.lana[i] = LANA_INVALID; /* invalid lana */
8951 afsi_log("Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
8955 /* and declare our name so we can receive connections */
8956 memset(ncbp, 0, sizeof(*ncbp));
8957 len=lstrlen(smb_localNamep);
8958 memset(smb_sharename,' ',NCBNAMSZ);
8959 memcpy(smb_sharename,smb_localNamep,len);
8960 afsi_log("lana_list.length %d", lana_list.length);
8962 /* Keep the name so we can unregister it later */
8963 for (l = 0; l < lana_list.length; l++) {
8964 lana = lana_list.lana[l];
8966 ncbp->ncb_command = NCBADDNAME;
8967 ncbp->ncb_lana_num = lana;
8968 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8969 code = Netbios(ncbp);
8971 afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
8972 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
8974 char name[NCBNAMSZ+1];
8976 memcpy(name,ncbp->ncb_name,NCBNAMSZ);
8977 afsi_log("Netbios NCBADDNAME added new name >%s<",name);
8981 code = ncbp->ncb_retcode;
8984 afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
8987 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
8988 if (code == NRC_BRIDGE) { /* invalid LANA num */
8989 lana_list.lana[l] = LANA_INVALID;
8992 else if (code == NRC_DUPNAME) {
8993 afsi_log("Name already exists; try to delete it");
8994 memset(ncbp, 0, sizeof(*ncbp));
8995 ncbp->ncb_command = NCBDELNAME;
8996 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
8997 ncbp->ncb_lana_num = lana;
8998 code = Netbios(ncbp);
9000 code = ncbp->ncb_retcode;
9002 afsi_log("Netbios NCBDELNAME lana %d error code %d\n", lana, code);
9004 if (code != 0 || delname_tried) {
9005 lana_list.lana[l] = LANA_INVALID;
9007 else if (code == 0) {
9008 if (!delname_tried) {
9016 afsi_log("Netbios NCBADDNAME lana %d error code %d", lana, code);
9017 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9021 smb_LANadapter = lana;
9022 lana_found = 1; /* at least one worked */
9026 osi_assertx(lana_list.length >= 0, "empty lana list");
9028 afsi_log("No valid LANA numbers found!");
9029 lana_list.length = 0;
9030 smb_LANadapter = LANA_INVALID;
9031 smb_ListenerState = SMB_LISTENER_STOPPED;
9032 cm_VolStatus_Network_Stopped(cm_NetbiosName
9039 /* we're done with the NCB now */
9042 afsi_log("smb_NetbiosInit smb_LANadapter=%d",smb_LANadapter);
9043 if (lana_list.length > 0)
9044 osi_assert(smb_LANadapter != LANA_INVALID);
9047 lock_ReleaseMutex(&smb_StartedLock);
9049 return (lana_list.length > 0 ? 1 : 0);
9052 void smb_StartListeners(int locked)
9059 lock_ObtainMutex(&smb_StartedLock);
9061 if (smb_ListenerState == SMB_LISTENER_STARTED) {
9063 lock_ReleaseMutex(&smb_StartedLock);
9067 afsi_log("smb_StartListeners");
9068 smb_ListenerState = SMB_LISTENER_STARTED;
9069 cm_VolStatus_Network_Started(cm_NetbiosName
9075 for (i = 0; i < lana_list.length; i++) {
9076 if (lana_list.lana[i] == LANA_INVALID)
9078 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
9079 (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
9080 osi_assertx(phandle != NULL, "smb_Listener thread creation failure");
9081 thrd_CloseHandle(phandle);
9084 lock_ReleaseMutex(&smb_StartedLock);
9087 void smb_RestartListeners(int locked)
9090 lock_ObtainMutex(&smb_StartedLock);
9092 if (powerStateSuspended)
9093 afsi_log("smb_RestartListeners called while suspended");
9095 if (!powerStateSuspended && smb_ListenerState != SMB_LISTENER_UNINITIALIZED) {
9096 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9097 if (smb_NetbiosInit(1))
9098 smb_StartListeners(1);
9099 } else if (smb_LanAdapterChangeDetected) {
9100 smb_LanAdapterChange(1);
9104 lock_ReleaseMutex(&smb_StartedLock);
9107 void smb_StopListener(NCB *ncbp, int lana, int wait)
9111 memset(ncbp, 0, sizeof(*ncbp));
9112 ncbp->ncb_command = NCBDELNAME;
9113 ncbp->ncb_lana_num = lana;
9114 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9115 code = Netbios(ncbp);
9117 afsi_log("Netbios NCBDELNAME lana=%d code=%d retcode=%d complete=%d",
9118 lana, code, ncbp->ncb_retcode, ncbp->ncb_cmd_cplt);
9120 /* and then reset the LANA; this will cause the listener threads to exit */
9121 ncbp->ncb_command = NCBRESET;
9122 ncbp->ncb_callname[0] = 100;
9123 ncbp->ncb_callname[2] = 100;
9124 ncbp->ncb_lana_num = lana;
9125 code = Netbios(ncbp);
9127 code = ncbp->ncb_retcode;
9129 afsi_log("Netbios NCBRESET lana %d error code %d", lana, code);
9131 afsi_log("Netbios NCBRESET lana %d succeeded", lana);
9135 thrd_WaitForSingleObject_Event(ListenerShutdown[lana], INFINITE);
9138 void smb_StopListeners(int locked)
9144 lock_ObtainMutex(&smb_StartedLock);
9146 if (smb_ListenerState == SMB_LISTENER_STOPPED) {
9148 lock_ReleaseMutex(&smb_StartedLock);
9152 afsi_log("smb_StopListeners");
9153 smb_ListenerState = SMB_LISTENER_STOPPED;
9154 cm_VolStatus_Network_Stopped(cm_NetbiosName
9162 /* Unregister the SMB name */
9163 for (l = 0; l < lana_list.length; l++) {
9164 lana = lana_list.lana[l];
9166 if (lana != LANA_INVALID) {
9167 smb_StopListener(ncbp, lana, TRUE);
9169 /* mark the adapter invalid */
9170 lana_list.lana[l] = LANA_INVALID; /* invalid lana */
9174 /* force a re-evaluation of the network adapters */
9175 lana_list.length = 0;
9176 smb_LANadapter = LANA_INVALID;
9179 lock_ReleaseMutex(&smb_StartedLock);
9182 void smb_Init(osi_log_t *logp, int useV3,
9192 EVENT_HANDLE retHandle;
9193 char eventName[MAX_PATH];
9194 int startListeners = 0;
9196 smb_TlsRequestSlot = TlsAlloc();
9198 smb_MBfunc = aMBfunc;
9202 /* Initialize smb_localZero */
9203 myTime.tm_isdst = -1; /* compute whether on DST or not */
9204 myTime.tm_year = 70;
9210 smb_localZero = mktime(&myTime);
9212 #ifndef USE_NUMERIC_TIME_CONV
9213 /* Initialize kludge-GMT */
9214 smb_CalculateNowTZ();
9215 #endif /* USE_NUMERIC_TIME_CONV */
9216 #ifdef AFS_FREELANCE_CLIENT
9217 /* Make sure the root.afs volume has the correct time */
9218 cm_noteLocalMountPointChange();
9221 /* initialize the remote debugging log */
9224 /* and the global lock */
9225 lock_InitializeRWLock(&smb_globalLock, "smb global lock");
9226 lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
9228 /* Raw I/O data structures */
9229 lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
9231 lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
9232 lock_InitializeMutex(&smb_StartedLock, "smb started lock");
9234 /* 4 Raw I/O buffers */
9235 smb_RawBufs = calloc(65536,1);
9236 *((char **)smb_RawBufs) = NULL;
9237 for (i=0; i<3; i++) {
9238 char *rawBuf = calloc(65536,1);
9239 *((char **)rawBuf) = smb_RawBufs;
9240 smb_RawBufs = rawBuf;
9243 /* global free lists */
9244 smb_ncbFreeListp = NULL;
9245 smb_packetFreeListp = NULL;
9247 lock_ObtainMutex(&smb_StartedLock);
9248 startListeners = smb_NetbiosInit(1);
9250 /* Initialize listener and server structures */
9252 memset(dead_sessions, 0, sizeof(dead_sessions));
9253 sprintf(eventName, "SessionEvents[0]");
9254 SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9255 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9256 afsi_log("Event Object Already Exists: %s", eventName);
9258 smb_NumServerThreads = nThreads;
9259 sprintf(eventName, "NCBavails[0]");
9260 NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9261 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9262 afsi_log("Event Object Already Exists: %s", eventName);
9263 sprintf(eventName, "NCBevents[0]");
9264 NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9265 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9266 afsi_log("Event Object Already Exists: %s", eventName);
9267 NCBreturns = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE *));
9268 sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
9269 retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9270 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9271 afsi_log("Event Object Already Exists: %s", eventName);
9272 for (i = 0; i < smb_NumServerThreads; i++) {
9273 NCBreturns[i] = malloc(NCB_MAX * sizeof(EVENT_HANDLE));
9274 NCBreturns[i][0] = retHandle;
9277 smb_ServerShutdown = malloc(smb_NumServerThreads * sizeof(EVENT_HANDLE));
9278 for (i = 0; i < smb_NumServerThreads; i++) {
9279 sprintf(eventName, "smb_ServerShutdown[%d]", i);
9280 smb_ServerShutdown[i] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
9281 if ( GetLastError() == ERROR_ALREADY_EXISTS )
9282 afsi_log("Event Object Already Exists: %s", eventName);
9283 InitNCBslot((int)(i+1));
9285 numNCBs = smb_NumServerThreads + 1;
9287 /* Initialize dispatch table */
9288 memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
9289 /* Prepare the table for unknown operations */
9290 for(i=0; i<= SMB_NOPCODES; i++) {
9291 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
9293 /* Fill in the ones we do know */
9294 smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
9295 smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
9296 smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
9297 smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
9298 smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
9299 smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
9300 smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
9301 smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
9302 smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
9303 smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
9304 smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
9305 smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
9306 smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
9307 smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
9308 smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
9309 smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
9310 smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
9311 smb_dispatchTable[0x11].procp = smb_SendCoreBadOp; /* process exit */
9312 smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
9313 smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
9314 /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
9315 smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9316 smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
9317 smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
9318 smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
9319 smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
9320 smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
9321 smb_dispatchTable[0x25].procp = smb_ReceiveV3Trans;
9322 smb_dispatchTable[0x25].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9323 smb_dispatchTable[0x26].procp = smb_ReceiveV3Trans;
9324 smb_dispatchTable[0x26].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9325 smb_dispatchTable[0x29].procp = smb_SendCoreBadOp; /* copy file */
9326 smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
9327 /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
9328 smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9329 smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
9330 smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
9331 smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
9332 smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
9333 smb_dispatchTable[0x2f].procp = smb_ReceiveV3WriteX;
9334 smb_dispatchTable[0x2f].flags |= SMB_DISPATCHFLAG_CHAINED;
9335 smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A; /* both are same */
9336 smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9337 smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
9338 smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9339 smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
9340 smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
9341 smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
9342 smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
9343 smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
9344 smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
9345 smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
9346 smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
9347 smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
9348 smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
9349 smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
9350 smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
9351 smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
9352 smb_dispatchTable[0x82].procp = smb_SendCoreBadOp; /* Find */
9353 smb_dispatchTable[0x83].procp = smb_SendCoreBadOp; /* Find Unique */
9354 smb_dispatchTable[0x84].procp = smb_SendCoreBadOp; /* Find Close */
9355 smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
9356 smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
9357 smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
9358 smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
9359 smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
9360 smb_dispatchTable[0xA5].procp = smb_ReceiveNTRename;
9361 smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp; /* Open Print File */
9362 smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp; /* Write Print File */
9363 smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp; /* Close Print File */
9364 smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp; /* Get Print Queue */
9365 smb_dispatchTable[0xD8].procp = smb_SendCoreBadOp; /* Read Bulk */
9366 smb_dispatchTable[0xD9].procp = smb_SendCoreBadOp; /* Write Bulk */
9367 smb_dispatchTable[0xDA].procp = smb_SendCoreBadOp; /* Write Bulk Data */
9369 /* setup tran 2 dispatch table */
9370 smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
9371 smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir; /* FindFirst */
9372 smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir; /* FindNext */
9373 smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
9374 smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
9375 smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
9376 smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
9377 smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
9378 smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
9379 smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
9380 smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
9381 smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
9382 smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
9383 smb_tran2DispatchTable[13].procp = smb_ReceiveTran2CreateDirectory;
9384 smb_tran2DispatchTable[14].procp = smb_ReceiveTran2SessionSetup;
9385 smb_tran2DispatchTable[15].procp = smb_ReceiveTran2QFSInfoFid;
9386 smb_tran2DispatchTable[16].procp = smb_ReceiveTran2GetDFSReferral;
9387 smb_tran2DispatchTable[17].procp = smb_ReceiveTran2ReportDFSInconsistency;
9389 /* setup the rap dispatch table */
9390 memset(smb_rapDispatchTable, 0, sizeof(smb_rapDispatchTable));
9391 smb_rapDispatchTable[0].procp = smb_ReceiveRAPNetShareEnum;
9392 smb_rapDispatchTable[1].procp = smb_ReceiveRAPNetShareGetInfo;
9393 smb_rapDispatchTable[63].procp = smb_ReceiveRAPNetWkstaGetInfo;
9394 smb_rapDispatchTable[13].procp = smb_ReceiveRAPNetServerGetInfo;
9398 /* if we are doing SMB authentication we have register outselves as a logon process */
9399 if (smb_authType != SMB_AUTH_NONE) {
9400 NTSTATUS nts = STATUS_UNSUCCESSFUL, ntsEx = STATUS_UNSUCCESSFUL;
9401 LSA_STRING afsProcessName;
9402 LSA_OPERATIONAL_MODE dummy; /*junk*/
9404 afsProcessName.Buffer = "OpenAFSClientDaemon";
9405 afsProcessName.Length = (USHORT)strlen(afsProcessName.Buffer);
9406 afsProcessName.MaximumLength = afsProcessName.Length + 1;
9408 nts = LsaRegisterLogonProcess(&afsProcessName, &smb_lsaHandle, &dummy);
9410 if (nts == STATUS_SUCCESS) {
9411 LSA_STRING packageName;
9412 /* we are registered. Find out the security package id */
9413 packageName.Buffer = MSV1_0_PACKAGE_NAME;
9414 packageName.Length = (USHORT)strlen(packageName.Buffer);
9415 packageName.MaximumLength = packageName.Length + 1;
9416 nts = LsaLookupAuthenticationPackage(smb_lsaHandle, &packageName , &smb_lsaSecPackage);
9417 if (nts == STATUS_SUCCESS) {
9419 * This code forces Windows to authenticate against the Logon Cache
9420 * first instead of attempting to authenticate against the Domain
9421 * Controller. When the Windows logon cache is enabled this improves
9422 * performance by removing the network access and works around a bug
9423 * seen at sites which are using a MIT Kerberos principal to login
9424 * to machines joined to a non-root domain in a multi-domain forest.
9425 * MsV1_0SetProcessOption was added in Windows XP.
9427 PVOID pResponse = NULL;
9428 ULONG cbResponse = 0;
9429 MSV1_0_SETPROCESSOPTION_REQUEST OptionsRequest;
9431 RtlZeroMemory(&OptionsRequest, sizeof(OptionsRequest));
9432 OptionsRequest.MessageType = (MSV1_0_PROTOCOL_MESSAGE_TYPE) MsV1_0SetProcessOption;
9433 OptionsRequest.ProcessOptions = MSV1_0_OPTION_TRY_CACHE_FIRST;
9434 OptionsRequest.DisableOptions = FALSE;
9436 nts = LsaCallAuthenticationPackage( smb_lsaHandle,
9439 sizeof(OptionsRequest),
9445 if (nts != STATUS_SUCCESS && ntsEx != STATUS_SUCCESS) {
9446 char message[AFSPATHMAX];
9447 sprintf(message,"MsV1_0SetProcessOption failure: nts 0x%x ntsEx 0x%x",
9449 OutputDebugString(message);
9452 OutputDebugString("MsV1_0SetProcessOption success");
9453 afsi_log("MsV1_0SetProcessOption success");
9455 /* END - code from Larry */
9457 smb_lsaLogonOrigin.Buffer = "OpenAFS";
9458 smb_lsaLogonOrigin.Length = (USHORT)strlen(smb_lsaLogonOrigin.Buffer);
9459 smb_lsaLogonOrigin.MaximumLength = smb_lsaLogonOrigin.Length + 1;
9461 afsi_log("Can't determine security package name for NTLM!! NTSTATUS=[%lX]",nts);
9463 /* something went wrong. We report the error and revert back to no authentication
9464 because we can't perform any auth requests without a successful lsa handle
9465 or sec package id. */
9466 afsi_log("Reverting to NO SMB AUTH");
9467 smb_authType = SMB_AUTH_NONE;
9470 afsi_log("Can't register logon process!! NTSTATUS=[%lX]",nts);
9472 /* something went wrong. We report the error and revert back to no authentication
9473 because we can't perform any auth requests without a successful lsa handle
9474 or sec package id. */
9475 afsi_log("Reverting to NO SMB AUTH");
9476 smb_authType = SMB_AUTH_NONE;
9480 /* Don't fallback to SMB_AUTH_NTLM. Apparently, allowing SPNEGO to be used each
9481 * time prevents the failure of authentication when logged into Windows with an
9482 * external Kerberos principal mapped to a local account.
9484 else if ( smb_authType == SMB_AUTH_EXTENDED) {
9485 /* Test to see if there is anything to negotiate. If SPNEGO is not going to be used
9486 * then the only option is NTLMSSP anyway; so just fallback.
9491 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
9492 if (secBlobLength == 0) {
9493 smb_authType = SMB_AUTH_NTLM;
9494 afsi_log("Reverting to SMB AUTH NTLM");
9503 /* Now get ourselves a domain name. */
9504 /* For now we are using the local computer name as the domain name.
9505 * It is actually the domain for local logins, and we are acting as
9506 * a local SMB server.
9508 bufsize = lengthof(smb_ServerDomainName) - 1;
9509 GetComputerNameW(smb_ServerDomainName, &bufsize);
9510 smb_ServerDomainNameLength = bufsize + 1; /* bufsize doesn't include terminator */
9511 afsi_log("Setting SMB server domain name to [%S]", smb_ServerDomainName);
9514 /* Start listeners, waiters, servers, and daemons */
9516 smb_StartListeners(1);
9518 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
9519 NULL, 0, &lpid, "smb_ClientWaiter");
9520 osi_assertx(phandle != NULL, "smb_ClientWaiter thread creation failure");
9521 thrd_CloseHandle(phandle);
9523 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
9524 NULL, 0, &lpid, "smb_ServerWaiter");
9525 osi_assertx(phandle != NULL, "smb_ServerWaiter thread creation failure");
9526 thrd_CloseHandle(phandle);
9528 for (i=0; i<smb_NumServerThreads; i++) {
9529 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
9530 (void *) i, 0, &lpid, "smb_Server");
9531 osi_assertx(phandle != NULL, "smb_Server thread creation failure");
9532 thrd_CloseHandle(phandle);
9535 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
9536 NULL, 0, &lpid, "smb_Daemon");
9537 osi_assertx(phandle != NULL, "smb_Daemon thread creation failure");
9538 thrd_CloseHandle(phandle);
9540 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
9541 NULL, 0, &lpid, "smb_WaitingLocksDaemon");
9542 osi_assertx(phandle != NULL, "smb_WaitingLocksDaemon thread creation failure");
9543 thrd_CloseHandle(phandle);
9545 lock_ReleaseMutex(&smb_StartedLock);
9549 void smb_Shutdown(void)
9556 /*fprintf(stderr, "Entering smb_Shutdown\n");*/
9558 /* setup the NCB system */
9561 /* Block new sessions by setting shutdown flag */
9562 smbShutdownFlag = 1;
9564 /* Hang up all sessions */
9565 memset((char *)ncbp, 0, sizeof(NCB));
9566 for (i = 1; i < numSessions; i++)
9568 if (dead_sessions[i])
9571 /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9572 ncbp->ncb_command = NCBHANGUP;
9573 ncbp->ncb_lana_num = lanas[i]; /*smb_LANadapter;*/
9574 ncbp->ncb_lsn = (UCHAR)LSNs[i];
9575 code = Netbios(ncbp);
9576 /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
9577 if (code == 0) code = ncbp->ncb_retcode;
9579 osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
9580 fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
9584 /* Trigger the shutdown of all SMB threads */
9585 for (i = 0; i < smb_NumServerThreads; i++)
9586 thrd_SetEvent(NCBreturns[i][0]);
9588 thrd_SetEvent(NCBevents[0]);
9589 thrd_SetEvent(SessionEvents[0]);
9590 thrd_SetEvent(NCBavails[0]);
9592 for (i = 0;i < smb_NumServerThreads; i++) {
9593 DWORD code = thrd_WaitForSingleObject_Event(smb_ServerShutdown[i], 500);
9594 if (code == WAIT_OBJECT_0) {
9597 afsi_log("smb_Shutdown thread [%d] did not stop; retry ...",i);
9598 thrd_SetEvent(NCBreturns[i--][0]);
9602 /* Delete Netbios name */
9603 memset((char *)ncbp, 0, sizeof(NCB));
9604 for (i = 0; i < lana_list.length; i++) {
9605 if (lana_list.lana[i] == LANA_INVALID) continue;
9606 ncbp->ncb_command = NCBDELNAME;
9607 ncbp->ncb_lana_num = lana_list.lana[i];
9608 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
9609 code = Netbios(ncbp);
9611 code = ncbp->ncb_retcode;
9613 fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
9614 ncbp->ncb_lana_num, code);
9619 /* Release the reference counts held by the VCs */
9620 lock_ObtainWrite(&smb_rctLock);
9621 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9626 if (vcp->magic != SMB_VC_MAGIC)
9627 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
9628 __FILE__, __LINE__);
9630 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9632 if (fidp->scp != NULL) {
9635 lock_ObtainMutex(&fidp->mx);
9636 if (fidp->scp != NULL) {
9639 lock_ObtainWrite(&scp->rw);
9640 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
9641 lock_ReleaseWrite(&scp->rw);
9642 osi_Log2(smb_logp,"smb_Shutdown fidp 0x%p scp 0x%p", fidp, scp);
9643 cm_ReleaseSCache(scp);
9645 lock_ReleaseMutex(&fidp->mx);
9649 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
9651 smb_ReleaseVCNoLock(tidp->vcp);
9653 cm_user_t *userp = tidp->userp;
9655 cm_ReleaseUser(userp);
9659 lock_ReleaseWrite(&smb_rctLock);
9661 TlsFree(smb_TlsRequestSlot);
9664 /* Get the UNC \\<servername>\<sharename> prefix. */
9665 char *smb_GetSharename()
9670 /* Make sure we have been properly initialized. */
9671 if (smb_localNamep == NULL)
9674 /* Allocate space for \\<servername>\<sharename>, plus the
9677 len = (strlen(smb_localNamep) + strlen("ALL") + 4) * sizeof(char);
9679 snprintf(name, len, "\\\\%s\\%s", smb_localNamep, "ALL");
9685 void smb_LogPacket(smb_packet_t *packet)
9689 unsigned length, paramlen, datalen, i, j;
9691 char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
9693 if (!packet) return;
9695 osi_Log0(smb_logp, "*** SMB packet dump ***");
9697 smbp = (smb_t *) packet->data;
9698 vp = (BYTE *) packet->data;
9700 paramlen = smbp->wct * 2;
9701 datalen = *((WORD *) (smbp->vdata + paramlen));
9702 length = sizeof(*smbp) + paramlen + 1 + datalen;
9704 for (i=0;i < length; i+=16)
9706 memset( buf, ' ', 80 );
9711 buf[strlen(buf)] = ' ';
9713 cp = (BYTE*) buf + 7;
9715 for (j=0;j < 16 && (i+j)<length; j++)
9717 *(cp++) = hex[vp[i+j] >> 4];
9718 *(cp++) = hex[vp[i+j] & 0xf];
9728 for (j=0;j < 16 && (i+j)<length;j++)
9730 *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
9741 osi_Log1( smb_logp, "%s", osi_LogSaveString(smb_logp, buf));
9744 osi_Log0(smb_logp, "*** End SMB packet dump ***");
9746 #endif /* LOG_PACKET */
9749 int smb_DumpVCP(FILE *outputFile, char *cookie, int lock)
9757 lock_ObtainRead(&smb_rctLock);
9759 sprintf(output, "begin dumping smb_vc_t\r\n");
9760 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9762 for (vcp = smb_allVCsp; vcp; vcp=vcp->nextp)
9766 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9767 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9768 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9770 sprintf(output, "begin dumping smb_fid_t\r\n");
9771 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9773 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9775 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",
9776 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9777 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
9778 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
9779 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9782 sprintf(output, "done dumping smb_fid_t\r\n");
9783 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9786 sprintf(output, "done dumping smb_vc_t\r\n");
9787 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9789 sprintf(output, "begin dumping DEAD smb_vc_t\r\n");
9790 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9792 for (vcp = smb_deadVCsp; vcp; vcp=vcp->nextp)
9796 sprintf(output, "%s vcp=0x%p, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\r\n",
9797 cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
9798 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9800 sprintf(output, "begin dumping smb_fid_t\r\n");
9801 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9803 for (fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q))
9805 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",
9806 cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp,
9807 fidp->NTopen_pathp ? fidp->NTopen_pathp : _C("NULL"),
9808 fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : _C("NULL"));
9809 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9812 sprintf(output, "done dumping smb_fid_t\r\n");
9813 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9816 sprintf(output, "done dumping DEAD smb_vc_t\r\n");
9817 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
9820 lock_ReleaseRead(&smb_rctLock);
9824 long smb_IsNetworkStarted(void)
9827 lock_ObtainWrite(&smb_globalLock);
9828 rc = (smb_ListenerState == SMB_LISTENER_STARTED && smbShutdownFlag == 0);
9829 lock_ReleaseWrite(&smb_globalLock);