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 /* This is a wrong. However, I suspect that there is an undercount
947 * and I don't want to release 1.4.1 in a state that will allow
948 * smb_vc_t objects to be deallocated while still in the
949 * smb_allVCsp list. The list is supposed to keep a reference
950 * to the smb_vc_t. Put it back.
955 } else if (vcp->flags & SMB_VCFLAG_ALREADYDEAD) {
956 /* The reference count is non-zero but the VC is dead.
957 * This implies that some FIDs, TIDs, etc on the VC have yet to
958 * be cleaned up. If we were not called by smb_CleanupDeadVC(),
959 * 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 if (!(vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS)) {
965 vcp->refCount++; /* put the refCount back */
966 lock_ReleaseWrite(&smb_rctLock);
967 smb_CleanupDeadVC(vcp);
968 lock_ObtainWrite(&smb_rctLock);
973 void smb_ReleaseVCNoLock(smb_vc_t *vcp)
975 osi_Log2(smb_logp,"smb_ReleaseVCNoLock vcp %x ref %d",vcp, vcp->refCount);
976 smb_ReleaseVCInternal(vcp);
979 void smb_ReleaseVC(smb_vc_t *vcp)
981 lock_ObtainWrite(&smb_rctLock);
982 osi_Log2(smb_logp,"smb_ReleaseVC vcp %x ref %d",vcp, vcp->refCount);
983 smb_ReleaseVCInternal(vcp);
984 lock_ReleaseWrite(&smb_rctLock);
987 void smb_HoldVCNoLock(smb_vc_t *vcp)
990 osi_Log2(smb_logp,"smb_HoldVCNoLock vcp %x ref %d",vcp, vcp->refCount);
993 void smb_HoldVC(smb_vc_t *vcp)
995 lock_ObtainWrite(&smb_rctLock);
997 osi_Log2(smb_logp,"smb_HoldVC vcp %x ref %d",vcp, vcp->refCount);
998 lock_ReleaseWrite(&smb_rctLock);
1001 void smb_CleanupDeadVC(smb_vc_t *vcp)
1003 smb_fid_t *fidpIter;
1004 smb_fid_t *fidpNext;
1006 smb_tid_t *tidpIter;
1007 smb_tid_t *tidpNext;
1009 smb_user_t *uidpIter;
1010 smb_user_t *uidpNext;
1012 afs_uint32 refCount = 0;
1014 lock_ObtainMutex(&vcp->mx);
1015 if (vcp->flags & SMB_VCFLAG_CLEAN_IN_PROGRESS) {
1016 lock_ReleaseMutex(&vcp->mx);
1017 osi_Log1(smb_logp, "Clean of dead vcp 0x%x in progress", vcp);
1020 vcp->flags |= SMB_VCFLAG_CLEAN_IN_PROGRESS;
1021 lock_ReleaseMutex(&vcp->mx);
1022 osi_Log1(smb_logp, "Cleaning up dead vcp 0x%x", vcp);
1024 lock_ObtainWrite(&smb_rctLock);
1025 /* remove VCP from smb_allVCsp */
1026 for (vcpp = &smb_allVCsp; *vcpp; vcpp = &((*vcpp)->nextp)) {
1027 if ((*vcpp)->magic != SMB_VC_MAGIC)
1028 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
1029 __FILE__, __LINE__);
1032 vcp->nextp = smb_deadVCsp;
1034 /* Hold onto the reference until we are done with this function */
1039 for (fidpIter = vcp->fidsp; fidpIter; fidpIter = fidpNext) {
1040 fidpNext = (smb_fid_t *) osi_QNext(&fidpIter->q);
1042 if (fidpIter->deleteOk)
1045 fid = fidpIter->fid;
1046 osi_Log2(smb_logp, " Cleanup FID %d (fidp=0x%x)", fid, fidpIter);
1048 smb_HoldFIDNoLock(fidpIter);
1049 lock_ReleaseWrite(&smb_rctLock);
1051 smb_CloseFID(vcp, fidpIter, NULL, 0);
1052 smb_ReleaseFID(fidpIter);
1054 lock_ObtainWrite(&smb_rctLock);
1055 fidpNext = vcp->fidsp;
1058 for (tidpIter = vcp->tidsp; tidpIter; tidpIter = tidpNext) {
1059 tidpNext = tidpIter->nextp;
1060 if (tidpIter->deleteOk)
1062 tidpIter->deleteOk = 1;
1064 tid = tidpIter->tid;
1065 osi_Log2(smb_logp, " Cleanup TID %d (tidp=0x%x)", tid, tidpIter);
1067 smb_HoldTIDNoLock(tidpIter);
1068 smb_ReleaseTID(tidpIter, TRUE);
1069 tidpNext = vcp->tidsp;
1072 for (uidpIter = vcp->usersp; uidpIter; uidpIter = uidpNext) {
1073 uidpNext = uidpIter->nextp;
1074 if (uidpIter->deleteOk)
1076 uidpIter->deleteOk = 1;
1078 /* do not add an additional reference count for the smb_user_t
1079 * as the smb_vc_t already is holding a reference */
1080 lock_ReleaseWrite(&smb_rctLock);
1082 smb_ReleaseUID(uidpIter);
1084 lock_ObtainWrite(&smb_rctLock);
1085 uidpNext = vcp->usersp;
1088 /* The vcp is now on the deadVCsp list. We intentionally drop the
1089 * reference so that the refcount can reach 0 and we can delete it */
1090 refCount = vcp->refCount;
1091 smb_ReleaseVCNoLock(vcp);
1094 * If the refCount == 1 going into the ReleaseVCNoLock call
1095 * the object will be freed and it won't be safe to clear
1099 lock_ObtainMutex(&vcp->mx);
1100 vcp->flags &= ~SMB_VCFLAG_CLEAN_IN_PROGRESS;
1101 lock_ReleaseMutex(&vcp->mx);
1104 lock_ReleaseWrite(&smb_rctLock);
1105 osi_Log1(smb_logp, "Finished cleaning up dead vcp 0x%x", vcp);
1108 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
1112 lock_ObtainWrite(&smb_rctLock);
1114 for (tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
1115 if (tidp->refCount == 0 && tidp->deleteOk) {
1117 smb_ReleaseTID(tidp, TRUE);
1121 if (tid == tidp->tid) {
1126 if (!tidp && (flags & SMB_FLAG_CREATE)) {
1127 tidp = malloc(sizeof(*tidp));
1128 memset(tidp, 0, sizeof(*tidp));
1129 tidp->nextp = vcp->tidsp;
1132 smb_HoldVCNoLock(vcp);
1134 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
1137 lock_ReleaseWrite(&smb_rctLock);
1141 void smb_HoldTIDNoLock(smb_tid_t *tidp)
1146 void smb_ReleaseTID(smb_tid_t *tidp, afs_uint32 locked)
1154 lock_ObtainWrite(&smb_rctLock);
1155 osi_assertx(tidp->refCount-- > 0, "smb_tid_t refCount 0");
1156 if (tidp->refCount == 0 && (tidp->deleteOk)) {
1157 ltpp = &tidp->vcp->tidsp;
1158 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
1162 osi_assertx(tp != NULL, "null smb_tid_t");
1164 lock_FinalizeMutex(&tidp->mx);
1165 userp = tidp->userp; /* remember to drop ref later */
1167 smb_ReleaseVCNoLock(tidp->vcp);
1171 lock_ReleaseWrite(&smb_rctLock);
1173 cm_ReleaseUser(userp);
1176 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
1178 smb_user_t *uidp = NULL;
1180 lock_ObtainWrite(&smb_rctLock);
1181 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1182 if (uid == uidp->userID) {
1184 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] found-uid[%d] name[%S]",
1186 ((uidp->unp)? osi_LogSaveClientString(smb_logp, uidp->unp->name):_C("")));
1190 if (!uidp && (flags & SMB_FLAG_CREATE)) {
1191 uidp = malloc(sizeof(*uidp));
1192 memset(uidp, 0, sizeof(*uidp));
1193 uidp->nextp = vcp->usersp;
1194 uidp->refCount = 2; /* one for the vcp and one for the caller */
1196 smb_HoldVCNoLock(vcp);
1198 lock_InitializeMutex(&uidp->mx, "user_t mutex");
1200 osi_Log3(smb_logp, "smb_FindUID vcp[0x%p] new-uid[%d] name[%S]",
1202 ((uidp->unp)?osi_LogSaveClientString(smb_logp,uidp->unp->name):_C("")));
1204 lock_ReleaseWrite(&smb_rctLock);
1208 smb_username_t *smb_FindUserByName(clientchar_t *usern, clientchar_t *machine,
1211 smb_username_t *unp= NULL;
1213 lock_ObtainWrite(&smb_rctLock);
1214 for(unp = usernamesp; unp; unp = unp->nextp) {
1215 if (cm_ClientStrCmpI(unp->name, usern) == 0 &&
1216 cm_ClientStrCmpI(unp->machine, machine) == 0) {
1221 if (!unp && (flags & SMB_FLAG_CREATE)) {
1222 unp = malloc(sizeof(*unp));
1223 memset(unp, 0, sizeof(*unp));
1225 unp->nextp = usernamesp;
1226 unp->name = cm_ClientStrDup(usern);
1227 unp->machine = cm_ClientStrDup(machine);
1229 lock_InitializeMutex(&unp->mx, "username_t mutex");
1230 if (flags & SMB_FLAG_AFSLOGON)
1231 unp->flags = SMB_USERNAMEFLAG_AFSLOGON;
1234 lock_ReleaseWrite(&smb_rctLock);
1238 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, clientchar_t *usern)
1240 smb_user_t *uidp= NULL;
1242 lock_ObtainWrite(&smb_rctLock);
1243 for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
1246 if (cm_stricmp_utf16(uidp->unp->name, usern) == 0) {
1248 osi_Log3(smb_logp,"smb_FindUserByNameThisSession vcp[0x%p] uid[%d] match-name[%S]",
1249 vcp,uidp->userID,osi_LogSaveClientString(smb_logp,usern));
1254 lock_ReleaseWrite(&smb_rctLock);
1258 void smb_ReleaseUsername(smb_username_t *unp)
1261 smb_username_t **lupp;
1262 cm_user_t *userp = NULL;
1263 time_t now = osi_Time();
1265 lock_ObtainWrite(&smb_rctLock);
1266 osi_assertx(unp->refCount-- > 0, "smb_username_t refCount 0");
1267 if (unp->refCount == 0 && !(unp->flags & SMB_USERNAMEFLAG_AFSLOGON) &&
1268 (unp->flags & SMB_USERNAMEFLAG_LOGOFF)) {
1270 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1274 osi_assertx(up != NULL, "null smb_username_t");
1276 up->nextp = NULL; /* do not remove this */
1277 lock_FinalizeMutex(&unp->mx);
1283 lock_ReleaseWrite(&smb_rctLock);
1285 cm_ReleaseUser(userp);
1288 void smb_HoldUIDNoLock(smb_user_t *uidp)
1293 void smb_ReleaseUID(smb_user_t *uidp)
1297 smb_username_t *unp = NULL;
1299 lock_ObtainWrite(&smb_rctLock);
1300 osi_assertx(uidp->refCount-- > 0, "smb_user_t refCount 0");
1301 if (uidp->refCount == 0) {
1302 lupp = &uidp->vcp->usersp;
1303 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
1307 osi_assertx(up != NULL, "null smb_user_t");
1309 lock_FinalizeMutex(&uidp->mx);
1311 smb_ReleaseVCNoLock(uidp->vcp);
1315 lock_ReleaseWrite(&smb_rctLock);
1319 cm_ReleaseUserVCRef(unp->userp);
1320 smb_ReleaseUsername(unp);
1324 cm_user_t *smb_GetUserFromUID(smb_user_t *uidp)
1326 cm_user_t *up = NULL;
1331 lock_ObtainMutex(&uidp->mx);
1333 up = uidp->unp->userp;
1336 lock_ReleaseMutex(&uidp->mx);
1342 /* retrieve a held reference to a user structure corresponding to an incoming
1344 * corresponding release function is cm_ReleaseUser.
1346 cm_user_t *smb_GetUserFromVCP(smb_vc_t *vcp, smb_packet_t *inp)
1349 cm_user_t *up = NULL;
1352 smbp = (smb_t *) inp;
1353 uidp = smb_FindUID(vcp, smbp->uid, 0);
1357 up = smb_GetUserFromUID(uidp);
1359 smb_ReleaseUID(uidp);
1364 * Return a pointer to a pathname extracted from a TID structure. The
1365 * TID structure is not held; assume it won't go away.
1367 long smb_LookupTIDPath(smb_vc_t *vcp, unsigned short tid, clientchar_t ** treepath)
1372 tidp = smb_FindTID(vcp, tid, 0);
1376 if (tidp->flags & SMB_TIDFLAG_IPC) {
1377 code = CM_ERROR_TIDIPC;
1378 /* tidp->pathname would be NULL, but that's fine */
1380 *treepath = tidp->pathname;
1381 smb_ReleaseTID(tidp, FALSE);
1386 /* check to see if we have a chained fid, that is, a fid that comes from an
1387 * OpenAndX message that ran earlier in this packet. In this case, the fid
1388 * field in a read, for example, request, isn't set, since the value is
1389 * supposed to be inherited from the openAndX call.
1391 int smb_ChainFID(int fid, smb_packet_t *inp)
1393 if (inp->fid == 0 || inp->inCount == 0)
1399 /* are we a priv'd user? What does this mean on NT? */
1400 int smb_SUser(cm_user_t *userp)
1405 /* find a file ID. If we pass in 0 we select an unused File ID.
1406 * If the SMB_FLAG_CREATE flag is set, we allocate a new
1407 * smb_fid_t data structure if desired File ID cannot be found.
1409 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
1414 if (fid == 0 && !(flags & SMB_FLAG_CREATE))
1417 lock_ObtainWrite(&smb_rctLock);
1418 /* figure out if we need to allocate a new file ID */
1421 fid = vcp->fidCounter;
1425 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1426 if (fidp->refCount == 0 && fidp->deleteOk) {
1428 lock_ReleaseWrite(&smb_rctLock);
1429 smb_ReleaseFID(fidp);
1430 lock_ObtainWrite(&smb_rctLock);
1433 if (fid == fidp->fid) {
1436 if (fid == 0xFFFF) {
1438 "New FID number wraps on vcp 0x%x", vcp);
1448 if (!fidp && (flags & SMB_FLAG_CREATE)) {
1449 char eventName[MAX_PATH];
1451 sprintf(eventName,"fid_t event vcp=%d fid=%d", vcp->vcID, fid);
1452 event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1453 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
1454 osi_Log1(smb_logp, "Event Object Already Exists: %s", osi_LogSaveString(smb_logp, eventName));
1455 thrd_CloseHandle(event);
1457 if (fid == 0xFFFF) {
1458 osi_Log1(smb_logp, "New FID wraps around for vcp 0x%x", vcp);
1464 fidp = malloc(sizeof(*fidp));
1465 memset(fidp, 0, sizeof(*fidp));
1466 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1469 smb_HoldVCNoLock(vcp);
1470 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1472 fidp->curr_chunk = fidp->prev_chunk = -2;
1473 fidp->raw_write_event = event;
1475 vcp->fidCounter = fid+1;
1476 if (vcp->fidCounter == 0xFFFF) {
1477 osi_Log1(smb_logp, "fidCounter wrapped around for vcp 0x%x",
1479 vcp->fidCounter = 1;
1484 lock_ReleaseWrite(&smb_rctLock);
1488 smb_fid_t *smb_FindFIDByScache(smb_vc_t *vcp, cm_scache_t * scp)
1490 smb_fid_t *fidp = NULL;
1496 lock_ObtainWrite(&smb_rctLock);
1497 for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
1498 if (scp == fidp->scp) {
1503 lock_ReleaseWrite(&smb_rctLock);
1507 void smb_HoldFIDNoLock(smb_fid_t *fidp)
1513 /* smb_ReleaseFID cannot be called while an cm_scache_t mutex lock is held */
1514 /* the sm_fid_t->mx and smb_rctLock must not be held */
1515 void smb_ReleaseFID(smb_fid_t *fidp)
1517 cm_scache_t *scp = NULL;
1518 cm_user_t *userp = NULL;
1519 smb_vc_t *vcp = NULL;
1520 smb_ioctl_t *ioctlp;
1522 lock_ObtainMutex(&fidp->mx);
1523 lock_ObtainWrite(&smb_rctLock);
1524 osi_assertx(fidp->refCount-- > 0, "smb_fid_t refCount 0");
1525 if (fidp->refCount == 0 && (fidp->deleteOk)) {
1528 scp = fidp->scp; /* release after lock is released */
1530 lock_ObtainWrite(&scp->rw);
1531 scp->flags &= ~CM_SCACHEFLAG_SMB_FID;
1532 lock_ReleaseWrite(&scp->rw);
1533 osi_Log2(smb_logp,"smb_ReleaseFID fidp 0x%p scp 0x%p", fidp, scp);
1536 userp = fidp->userp;
1540 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1541 thrd_CloseHandle(fidp->raw_write_event);
1543 /* and see if there is ioctl stuff to free */
1544 ioctlp = fidp->ioctlp;
1547 cm_FreeSpace(ioctlp->prefix);
1548 if (ioctlp->ioctl.inAllocp)
1549 free(ioctlp->ioctl.inAllocp);
1550 if (ioctlp->ioctl.outAllocp)
1551 free(ioctlp->ioctl.outAllocp);
1554 lock_ReleaseMutex(&fidp->mx);
1555 lock_FinalizeMutex(&fidp->mx);
1559 smb_ReleaseVCNoLock(vcp);
1561 lock_ReleaseMutex(&fidp->mx);
1563 lock_ReleaseWrite(&smb_rctLock);
1565 /* now release the scache structure */
1567 cm_ReleaseSCache(scp);
1570 cm_ReleaseUser(userp);
1574 * Case-insensitive search for one string in another;
1575 * used to find variable names in submount pathnames.
1577 static clientchar_t *smb_stristr(clientchar_t *str1, clientchar_t *str2)
1579 clientchar_t *cursor;
1581 for (cursor = str1; *cursor; cursor++)
1582 if (cm_ClientStrCmpI(cursor, str2) == 0)
1589 * Substitute a variable value for its name in a submount pathname. Variable
1590 * name has been identified by smb_stristr() and is in substr. Variable name
1591 * length (plus one) is in substr_size. Variable value is in newstr.
1593 static void smb_subst(clientchar_t *str1, int cchstr1, clientchar_t *substr,
1594 unsigned int substr_size, clientchar_t *newstr)
1596 clientchar_t temp[1024];
1598 cm_ClientStrCpy(temp, lengthof(temp), substr + substr_size - 1);
1599 cm_ClientStrCpy(substr, cchstr1 - (substr - str1), newstr);
1600 cm_ClientStrCat(str1, cchstr1, temp);
1603 clientchar_t VNUserName[] = _C("%USERNAME%");
1604 clientchar_t VNLCUserName[] = _C("%LCUSERNAME%");
1605 clientchar_t VNComputerName[] = _C("%COMPUTERNAME%");
1606 clientchar_t VNLCComputerName[] = _C("%LCCOMPUTERNAME%");
1608 typedef struct smb_findShare_rock {
1609 clientchar_t * shareName;
1610 clientchar_t * match;
1612 } smb_findShare_rock_t;
1614 #define SMB_FINDSHARE_EXACT_MATCH 1
1615 #define SMB_FINDSHARE_PARTIAL_MATCH 2
1617 long smb_FindShareProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
1621 smb_findShare_rock_t * vrock = (smb_findShare_rock_t *) rockp;
1622 normchar_t normName[MAX_PATH];
1624 cm_FsStringToNormString(dep->name, -1, normName, sizeof(normName)/sizeof(normName[0]));
1626 if (!cm_ClientStrCmpNI(normName, vrock->shareName, 12)) {
1627 if(!cm_ClientStrCmpI(normName, vrock->shareName))
1628 matchType = SMB_FINDSHARE_EXACT_MATCH;
1630 matchType = SMB_FINDSHARE_PARTIAL_MATCH;
1631 if(vrock->match) free(vrock->match);
1632 vrock->match = cm_FsStringToClientStringAlloc(dep->name, -1, NULL);
1633 vrock->matchType = matchType;
1635 if(matchType == SMB_FINDSHARE_EXACT_MATCH)
1636 return CM_ERROR_STOPNOW;
1642 /* find a shareName in the table of submounts */
1643 int smb_FindShare(smb_vc_t *vcp, smb_user_t *uidp,
1644 clientchar_t *shareName,
1645 clientchar_t **pathNamep)
1649 clientchar_t pathName[1024];
1652 clientchar_t *p, *q;
1653 fschar_t *cellname = NULL;
1656 DWORD allSubmount = 1;
1658 /* if allSubmounts == 0, only return the //mountRoot/all share
1659 * if in fact it has been been created in the subMounts table.
1660 * This is to allow sites that want to restrict access to the
1663 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1664 0, KEY_QUERY_VALUE, &parmKey);
1665 if (code == ERROR_SUCCESS) {
1666 cblen = sizeof(allSubmount);
1667 code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1668 (BYTE *) &allSubmount, &cblen);
1669 if (code != ERROR_SUCCESS) {
1672 RegCloseKey (parmKey);
1675 if (allSubmount && cm_ClientStrCmpI(shareName, _C("all")) == 0) {
1680 /* In case, the all share is disabled we need to still be able
1681 * to handle ioctl requests
1683 if (cm_ClientStrCmpI(shareName, _C("ioctl$")) == 0) {
1684 *pathNamep = cm_ClientStrDup(_C("/.__ioctl__"));
1688 if (cm_ClientStrCmpIA(shareName, _C("IPC$")) == 0 ||
1689 cm_ClientStrCmpIA(shareName, _C("srvsvc")) == 0 ||
1690 cm_ClientStrCmpIA(shareName, _C("wkssvc")) == 0 ||
1691 cm_ClientStrCmpIA(shareName, _C(SMB_IOCTL_FILENAME_NOSLASH)) == 0 ||
1692 cm_ClientStrCmpIA(shareName, _C("DESKTOP.INI")) == 0
1698 /* Check for volume references
1700 * They look like <cell>{%,#}<volume>
1702 if (cm_ClientStrChr(shareName, '%') != NULL ||
1703 cm_ClientStrChr(shareName, '#') != NULL) {
1704 clientchar_t pathstr[CELL_MAXNAMELEN + VL_MAXNAMELEN + 1 + CM_PREFIX_VOL_CCH];
1705 /* make room for '/@vol:' + mountchar + NULL terminator*/
1707 osi_Log1(smb_logp, "smb_FindShare found volume reference [%S]",
1708 osi_LogSaveClientString(smb_logp, shareName));
1710 cm_ClientStrPrintfN(pathstr, lengthof(pathstr),
1711 _C("/") _C(CM_PREFIX_VOL) _C("%s"), shareName);
1712 cchlen = (DWORD)(cm_ClientStrLen(pathstr) + 1);
1714 *pathNamep = malloc(cchlen * sizeof(clientchar_t));
1716 cm_ClientStrCpy(*pathNamep, cchlen, pathstr);
1717 cm_ClientStrLwr(*pathNamep);
1718 osi_Log1(smb_logp, " returning pathname [%S]",
1719 osi_LogSaveClientString(smb_logp, *pathNamep));
1727 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY "\\Submounts",
1728 0, KEY_QUERY_VALUE, &parmKey);
1729 if (code == ERROR_SUCCESS) {
1730 cblen = sizeof(pathName);
1731 code = RegQueryValueExW(parmKey, shareName, NULL, NULL,
1732 (BYTE *) pathName, &cblen);
1733 if (code != ERROR_SUCCESS)
1735 RegCloseKey (parmKey);
1739 cchlen = cblen / sizeof(clientchar_t);
1740 if (cchlen != 0 && cchlen != lengthof(pathName) - 1) {
1741 /* We can accept either unix or PC style AFS pathnames. Convert
1742 * Unix-style to PC style here for internal use.
1745 cchlen = lengthof(pathName);
1747 /* within this code block, we maintain, cchlen = writeable
1748 buffer length of p */
1750 if (cm_ClientStrCmpN(p, cm_mountRootC, cm_mountRootCLen) == 0) {
1751 p += cm_mountRootCLen; /* skip mount path */
1752 cchlen -= (p - pathName);
1757 if (*q == _C('/')) *q = _C('\\'); /* change to \ */
1763 clientchar_t temp[1024];
1765 if (var = smb_stristr(p, VNUserName)) {
1766 if (uidp && uidp->unp)
1767 smb_subst(p, cchlen, var, lengthof(VNUserName),uidp->unp->name);
1769 smb_subst(p, cchlen, var, lengthof(VNUserName), _C(" "));
1771 else if (var = smb_stristr(p, VNLCUserName))
1773 if (uidp && uidp->unp)
1774 cm_ClientStrCpy(temp, lengthof(temp), uidp->unp->name);
1776 cm_ClientStrCpy(temp, lengthof(temp), _C(" "));
1777 cm_ClientStrLwr(temp);
1778 smb_subst(p, cchlen, var, lengthof(VNLCUserName), temp);
1780 else if (var = smb_stristr(p, VNComputerName))
1782 sizeTemp = lengthof(temp);
1783 GetComputerNameW(temp, &sizeTemp);
1784 smb_subst(p, cchlen, var, lengthof(VNComputerName), temp);
1786 else if (var = smb_stristr(p, VNLCComputerName))
1788 sizeTemp = lengthof(temp);
1789 GetComputerName((LPTSTR)temp, &sizeTemp);
1790 cm_ClientStrLwr(temp);
1791 smb_subst(p, cchlen, var, lengthof(VNLCComputerName), temp);
1796 *pathNamep = cm_ClientStrDup(p);
1801 /* First lookup shareName in root.afs */
1803 smb_findShare_rock_t vrock;
1805 fschar_t ftemp[1024];
1806 clientchar_t * p = shareName;
1809 /* attempt to locate a partial match in root.afs. This is because
1810 when using the ANSI RAP calls, the share name is limited to 13 chars
1811 and hence is truncated. Of course we prefer exact matches. */
1813 thyper.HighPart = 0;
1816 vrock.shareName = cm_ClientStringToNormStringAlloc(shareName, -1, NULL);
1818 vrock.matchType = 0;
1820 cm_HoldSCache(cm_data.rootSCachep);
1821 code = cm_ApplyDir(cm_data.rootSCachep, smb_FindShareProc, &vrock, &thyper,
1822 (uidp? (uidp->unp ? uidp->unp->userp : NULL) : NULL), &req, NULL);
1823 cm_ReleaseSCache(cm_data.rootSCachep);
1825 free(vrock.shareName);
1826 vrock.shareName = NULL;
1828 if (vrock.matchType) {
1829 cm_ClientStrPrintfN(pathName, lengthof(pathName), _C("/%s/"), vrock.match);
1830 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1835 /* if we get here, there was no match for the share in root.afs */
1836 /* so try to create \\<netbiosName>\<cellname> */
1841 /* Get the full name for this cell */
1842 cellname = cm_ClientStringToFsStringAlloc(p, -1, NULL);
1843 code = cm_SearchCellFile(cellname, ftemp, 0, 0);
1844 #ifdef AFS_AFSDB_ENV
1845 if (code && cm_dnsEnabled) {
1847 code = cm_SearchCellByDNS(cellname, ftemp, &ttl, 0, 0);
1853 /* construct the path */
1855 clientchar_t temp[1024];
1857 cm_FsStringToClientString(ftemp, cm_FsStrLen(ftemp), temp, 1024);
1858 cm_ClientStrPrintfN(pathName, lengthof(pathName),
1859 rw ? _C("/.%S/") : _C("/%S/"), temp);
1860 *pathNamep = cm_ClientStrDup(cm_ClientStrLwr(pathName));
1869 /* Client-side offline caching policy types */
1870 #define CSC_POLICY_MANUAL 0
1871 #define CSC_POLICY_DOCUMENTS 1
1872 #define CSC_POLICY_PROGRAMS 2
1873 #define CSC_POLICY_DISABLE 3
1875 int smb_FindShareCSCPolicy(clientchar_t *shareName)
1878 clientchar_t policy[1024];
1881 int retval = CSC_POLICY_MANUAL;
1883 RegCreateKeyEx( HKEY_LOCAL_MACHINE,
1884 AFSREG_CLT_OPENAFS_SUBKEY "\\CSCPolicy",
1887 REG_OPTION_NON_VOLATILE,
1893 len = sizeof(policy);
1894 if ( RegQueryValueExW( hkCSCPolicy, shareName, 0, &dwType, (LPBYTE) policy, &len ) ||
1896 retval = cm_ClientStrCmpIA(_C("all"),shareName) ? CSC_POLICY_MANUAL : CSC_POLICY_DISABLE;
1898 else if (cm_ClientStrCmpIA(policy, _C("documents")) == 0)
1900 retval = CSC_POLICY_DOCUMENTS;
1902 else if (cm_ClientStrCmpIA(policy, _C("programs")) == 0)
1904 retval = CSC_POLICY_PROGRAMS;
1906 else if (cm_ClientStrCmpIA(policy, _C("disable")) == 0)
1908 retval = CSC_POLICY_DISABLE;
1911 RegCloseKey(hkCSCPolicy);
1915 /* find a dir search structure by cookie value, and return it held.
1916 * Must be called with smb_globalLock held.
1918 smb_dirSearch_t *smb_FindDirSearchNoLock(long cookie)
1920 smb_dirSearch_t *dsp;
1922 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1923 if (dsp->cookie == cookie) {
1924 if (dsp != smb_firstDirSearchp) {
1925 /* move to head of LRU queue, too, if we're not already there */
1926 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1927 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&dsp->q);
1928 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1929 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1930 if (!smb_lastDirSearchp)
1931 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1933 lock_ObtainMutex(&dsp->mx);
1935 lock_ReleaseMutex(&dsp->mx);
1941 osi_Log1(smb_logp,"smb_FindDirSearch(%d) == NULL",cookie);
1942 for (dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1943 osi_Log1(smb_logp,"... valid id: %d", dsp->cookie);
1949 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1951 lock_ObtainWrite(&smb_globalLock);
1952 lock_ObtainMutex(&dsp->mx);
1953 osi_Log3(smb_logp,"smb_DeleteDirSearch cookie %d dsp 0x%p scp 0x%p",
1954 dsp->cookie, dsp, dsp->scp);
1955 dsp->flags |= SMB_DIRSEARCH_DELETE;
1956 if (dsp->scp != NULL) {
1957 lock_ObtainWrite(&dsp->scp->rw);
1958 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1959 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1960 dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1961 dsp->scp->bulkStatProgress = hzero;
1963 lock_ReleaseWrite(&dsp->scp->rw);
1965 lock_ReleaseMutex(&dsp->mx);
1966 lock_ReleaseWrite(&smb_globalLock);
1969 /* Must be called with the smb_globalLock held */
1970 void smb_ReleaseDirSearchNoLock(smb_dirSearch_t *dsp)
1972 cm_scache_t *scp = NULL;
1974 lock_ObtainMutex(&dsp->mx);
1975 osi_assertx(dsp->refCount-- > 0, "cm_scache_t refCount 0");
1976 if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1977 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1978 smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1979 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1980 lock_ReleaseMutex(&dsp->mx);
1981 lock_FinalizeMutex(&dsp->mx);
1983 osi_Log3(smb_logp,"smb_ReleaseDirSearch cookie %d dsp 0x%p scp 0x%p",
1984 dsp->cookie, dsp, scp);
1987 lock_ReleaseMutex(&dsp->mx);
1989 /* do this now to avoid spurious locking hierarchy creation */
1991 cm_ReleaseSCache(scp);
1994 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1996 lock_ObtainWrite(&smb_globalLock);
1997 smb_ReleaseDirSearchNoLock(dsp);
1998 lock_ReleaseWrite(&smb_globalLock);
2001 /* find a dir search structure by cookie value, and return it held */
2002 smb_dirSearch_t *smb_FindDirSearch(long cookie)
2004 smb_dirSearch_t *dsp;
2006 lock_ObtainWrite(&smb_globalLock);
2007 dsp = smb_FindDirSearchNoLock(cookie);
2008 lock_ReleaseWrite(&smb_globalLock);
2012 /* GC some dir search entries, in the address space expected by the specific protocol.
2013 * Must be called with smb_globalLock held; release the lock temporarily.
2015 #define SMB_DIRSEARCH_GCMAX 10 /* how many at once */
2016 void smb_GCDirSearches(int isV3)
2018 smb_dirSearch_t *prevp;
2019 smb_dirSearch_t *tp;
2020 smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
2024 victimCount = 0; /* how many have we got so far */
2025 for (tp = smb_lastDirSearchp; tp; tp=prevp) {
2026 /* we'll move tp from queue, so
2029 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);
2030 /* if no one is using this guy, and we're either in the new protocol,
2031 * or we're in the old one and this is a small enough ID to be useful
2032 * to the old protocol, GC this guy.
2034 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
2035 /* hold and delete */
2036 lock_ObtainMutex(&tp->mx);
2037 tp->flags |= SMB_DIRSEARCH_DELETE;
2038 lock_ReleaseMutex(&tp->mx);
2039 victimsp[victimCount++] = tp;
2043 /* don't do more than this */
2044 if (victimCount >= SMB_DIRSEARCH_GCMAX)
2048 /* now release them */
2049 for (i = 0; i < victimCount; i++) {
2050 smb_ReleaseDirSearchNoLock(victimsp[i]);
2054 /* function for allocating a dir search entry. We need these to remember enough context
2055 * since we don't get passed the path from call to call during a directory search.
2057 * Returns a held dir search structure, and bumps the reference count on the vnode,
2058 * since it saves a pointer to the vnode.
2060 smb_dirSearch_t *smb_NewDirSearch(int isV3)
2062 smb_dirSearch_t *dsp;
2068 lock_ObtainWrite(&smb_globalLock);
2071 /* what's the biggest ID allowed in this version of the protocol */
2072 /* TODO: do we really want a non v3 dir search request to wrap
2073 smb_dirSearchCounter? */
2074 maxAllowed = isV3 ? 65535 : 255;
2075 if (smb_dirSearchCounter > maxAllowed)
2076 smb_dirSearchCounter = 1;
2078 start = smb_dirSearchCounter;
2081 /* twice so we have enough tries to find guys we GC after one pass;
2082 * 10 extra is just in case I mis-counted.
2084 if (++counter > 2*maxAllowed+10)
2085 osi_panic("afsd: dir search cookie leak", __FILE__, __LINE__);
2087 if (smb_dirSearchCounter > maxAllowed) {
2088 smb_dirSearchCounter = 1;
2090 if (smb_dirSearchCounter == start) {
2092 smb_GCDirSearches(isV3);
2095 dsp = smb_FindDirSearchNoLock(smb_dirSearchCounter);
2097 /* don't need to watch for refcount zero and deleted, since
2098 * we haven't dropped the global lock.
2100 lock_ObtainMutex(&dsp->mx);
2102 lock_ReleaseMutex(&dsp->mx);
2103 ++smb_dirSearchCounter;
2107 dsp = malloc(sizeof(*dsp));
2108 memset(dsp, 0, sizeof(*dsp));
2109 dsp->cookie = smb_dirSearchCounter;
2110 ++smb_dirSearchCounter;
2112 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
2113 dsp->lastTime = osi_Time();
2114 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
2115 if (!smb_lastDirSearchp)
2116 smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
2118 osi_Log2(smb_logp,"smb_NewDirSearch cookie %d dsp 0x%p",
2122 lock_ReleaseWrite(&smb_globalLock);
2126 static smb_packet_t *GetPacket(void)
2130 lock_ObtainWrite(&smb_globalLock);
2131 tbp = smb_packetFreeListp;
2133 smb_packetFreeListp = tbp->nextp;
2134 lock_ReleaseWrite(&smb_globalLock);
2136 tbp = calloc(sizeof(*tbp),1);
2137 tbp->magic = SMB_PACKETMAGIC;
2140 tbp->resumeCode = 0;
2146 tbp->ncb_length = 0;
2149 tbp->stringsp = NULL;
2151 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2156 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
2160 memcpy(tbp, pkt, sizeof(smb_packet_t));
2161 tbp->wctp = tbp->data + (unsigned int)(pkt->wctp - pkt->data);
2162 tbp->stringsp = NULL;
2164 smb_HoldVC(tbp->vcp);
2168 static NCB *GetNCB(void)
2173 lock_ObtainWrite(&smb_globalLock);
2174 tbp = smb_ncbFreeListp;
2176 smb_ncbFreeListp = tbp->nextp;
2177 lock_ReleaseWrite(&smb_globalLock);
2179 tbp = calloc(sizeof(*tbp),1);
2180 tbp->magic = SMB_NCBMAGIC;
2183 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2185 memset(&tbp->ncb, 0, sizeof(NCB));
2190 static void FreeSMBStrings(smb_packet_t * pkt)
2195 for (s = pkt->stringsp; s; s = ns) {
2199 pkt->stringsp = NULL;
2202 void smb_FreePacket(smb_packet_t *tbp)
2204 smb_vc_t * vcp = NULL;
2205 osi_assertx(tbp->magic == SMB_PACKETMAGIC, "invalid smb_packet_t magic");
2207 lock_ObtainWrite(&smb_globalLock);
2208 tbp->nextp = smb_packetFreeListp;
2209 smb_packetFreeListp = tbp;
2210 tbp->magic = SMB_PACKETMAGIC;
2214 tbp->resumeCode = 0;
2220 tbp->ncb_length = 0;
2222 FreeSMBStrings(tbp);
2223 lock_ReleaseWrite(&smb_globalLock);
2229 static void FreeNCB(NCB *bufferp)
2233 tbp = (smb_ncb_t *) bufferp;
2234 osi_assertx(tbp->magic == SMB_NCBMAGIC, "invalid smb_packet_t magic");
2236 lock_ObtainWrite(&smb_globalLock);
2237 tbp->nextp = smb_ncbFreeListp;
2238 smb_ncbFreeListp = tbp;
2239 lock_ReleaseWrite(&smb_globalLock);
2242 /* get a ptr to the data part of a packet, and its count */
2243 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
2247 unsigned char *afterParmsp;
2249 parmBytes = *smbp->wctp << 1;
2250 afterParmsp = smbp->wctp + parmBytes + 1;
2252 dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
2253 if (nbytesp) *nbytesp = dataBytes;
2255 /* don't forget to skip the data byte count, since it follows
2256 * the parameters; that's where the "2" comes from below.
2258 return (unsigned char *) (afterParmsp + 2);
2261 /* must set all the returned parameters before playing around with the
2262 * data region, since the data region is located past the end of the
2263 * variable number of parameters.
2265 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
2267 unsigned char *afterParmsp;
2269 afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
2271 *afterParmsp++ = dsize & 0xff;
2272 *afterParmsp = (dsize>>8) & 0xff;
2275 /* return the parm'th parameter in the smbp packet */
2276 unsigned short smb_GetSMBParm(smb_packet_t *smbp, int parm)
2279 unsigned char *parmDatap;
2281 parmCount = *smbp->wctp;
2283 if (parm >= parmCount) {
2286 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2287 parm, parmCount, smbp->ncb_length);
2288 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2289 parm, parmCount, smbp->ncb_length);
2290 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2291 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2292 osi_panic(s, __FILE__, __LINE__);
2294 parmDatap = smbp->wctp + (2*parm) + 1;
2296 return parmDatap[0] + (parmDatap[1] << 8);
2299 /* return the parm'th parameter in the smbp packet */
2300 unsigned char smb_GetSMBParmByte(smb_packet_t *smbp, int parm)
2303 unsigned char *parmDatap;
2305 parmCount = *smbp->wctp;
2307 if (parm >= parmCount) {
2310 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2311 parm, parmCount, smbp->ncb_length);
2312 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2313 parm, parmCount, smbp->ncb_length);
2314 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2315 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2316 osi_panic(s, __FILE__, __LINE__);
2318 parmDatap = smbp->wctp + (2*parm) + 1;
2320 return parmDatap[0];
2323 /* return the parm'th parameter in the smbp packet */
2324 unsigned int smb_GetSMBParmLong(smb_packet_t *smbp, int parm)
2327 unsigned char *parmDatap;
2329 parmCount = *smbp->wctp;
2331 if (parm + 1 >= parmCount) {
2334 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
2335 parm, parmCount, smbp->ncb_length);
2336 osi_Log3(smb_logp,"Bad SMB param %d out of %d, ncb len %d",
2337 parm, parmCount, smbp->ncb_length);
2338 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM,
2339 __FILE__, __LINE__, parm, parmCount, smbp->ncb_length);
2340 osi_panic(s, __FILE__, __LINE__);
2342 parmDatap = smbp->wctp + (2*parm) + 1;
2344 return parmDatap[0] + (parmDatap[1] << 8) + (parmDatap[2] << 16) + (parmDatap[3] << 24);
2347 /* return the parm'th parameter in the smbp packet */
2348 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
2351 unsigned char *parmDatap;
2353 parmCount = *smbp->wctp;
2355 if (parm * 2 + offset >= parmCount * 2) {
2358 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
2359 parm, offset, parmCount, smbp->ncb_length);
2360 LogEvent(EVENTLOG_ERROR_TYPE, MSG_BAD_SMB_PARAM_WITH_OFFSET,
2361 __FILE__, __LINE__, parm, offset, parmCount, smbp->ncb_length);
2362 osi_Log4(smb_logp, "Bad SMB param %d offset %d out of %d, ncb len %d",
2363 parm, offset, parmCount, smbp->ncb_length);
2364 osi_panic(s, __FILE__, __LINE__);
2366 parmDatap = smbp->wctp + (2*parm) + 1 + offset;
2368 return parmDatap[0] + (parmDatap[1] << 8);
2371 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
2373 unsigned char *parmDatap;
2375 /* make sure we have enough slots */
2376 if (*smbp->wctp <= slot)
2377 *smbp->wctp = slot+1;
2379 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2380 *parmDatap++ = parmValue & 0xff;
2381 *parmDatap = (parmValue>>8) & 0xff;
2384 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
2386 unsigned char *parmDatap;
2388 /* make sure we have enough slots */
2389 if (*smbp->wctp <= slot)
2390 *smbp->wctp = slot+2;
2392 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2393 *parmDatap++ = parmValue & 0xff;
2394 *parmDatap++ = (parmValue>>8) & 0xff;
2395 *parmDatap++ = (parmValue>>16) & 0xff;
2396 *parmDatap = (parmValue>>24) & 0xff;
2399 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
2401 unsigned char *parmDatap;
2404 /* make sure we have enough slots */
2405 if (*smbp->wctp <= slot)
2406 *smbp->wctp = slot+4;
2408 parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
2410 *parmDatap++ = *parmValuep++;
2413 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
2415 unsigned char *parmDatap;
2417 /* make sure we have enough slots */
2418 if (*smbp->wctp <= slot) {
2419 if (smbp->oddByte) {
2421 *smbp->wctp = slot+1;
2426 parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
2427 *parmDatap++ = parmValue & 0xff;
2432 void smb_StripLastComponent(clientchar_t *outPathp, clientchar_t **lastComponentp,
2433 clientchar_t *inPathp)
2435 clientchar_t *lastSlashp;
2437 lastSlashp = cm_ClientStrRChr(inPathp, '\\');
2439 *lastComponentp = lastSlashp;
2442 if (inPathp == lastSlashp)
2444 *outPathp++ = *inPathp++;
2453 clientchar_t *smb_ParseASCIIBlock(smb_packet_t * pktp, unsigned char *inp,
2454 char **chainpp, int flags)
2462 if (!WANTS_UNICODE(pktp))
2463 flags |= SMB_STRF_FORCEASCII;
2466 cb = sizeof(pktp->data) - (inp - pktp->data);
2467 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2468 #ifdef DEBUG_UNICODE
2471 cb = sizeof(pktp->data);
2473 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2476 clientchar_t *smb_ParseString(smb_packet_t * pktp, unsigned char * inp,
2477 char ** chainpp, int flags)
2482 if (!WANTS_UNICODE(pktp))
2483 flags |= SMB_STRF_FORCEASCII;
2486 cb = sizeof(pktp->data) - (inp - pktp->data);
2487 if (inp < pktp->data || inp >= pktp->data + sizeof(pktp->data)) {
2488 #ifdef DEBUG_UNICODE
2491 cb = sizeof(pktp->data);
2493 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2496 clientchar_t *smb_ParseStringCb(smb_packet_t * pktp, unsigned char * inp,
2497 size_t cb, char ** chainpp, int flags)
2500 if (!WANTS_UNICODE(pktp))
2501 flags |= SMB_STRF_FORCEASCII;
2504 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2507 clientchar_t *smb_ParseStringCch(smb_packet_t * pktp, unsigned char * inp,
2508 size_t cch, char ** chainpp, int flags)
2513 if (!WANTS_UNICODE(pktp))
2514 flags |= SMB_STRF_FORCEASCII;
2516 cb = cch * sizeof(wchar_t);
2519 return smb_ParseStringBuf(pktp->data, &pktp->stringsp, inp, &cb, chainpp, flags);
2523 smb_ParseStringBuf(const unsigned char * bufbase,
2524 cm_space_t ** stringspp,
2525 unsigned char *inp, size_t *pcb_max,
2526 char **chainpp, int flags)
2529 if (!(flags & SMB_STRF_FORCEASCII)) {
2531 cm_space_t * spacep;
2534 if (bufbase && ((inp - bufbase) % 2) != 0) {
2535 inp++; /* unicode strings are always word aligned */
2539 if (FAILED(StringCchLengthW((const wchar_t *) inp, *pcb_max / sizeof(wchar_t),
2541 cch_src = *pcb_max / sizeof(wchar_t);
2545 *pcb_max -= (cch_src + 1) * sizeof(wchar_t);
2552 spacep = cm_GetSpace();
2553 spacep->nextp = *stringspp;
2554 *stringspp = spacep;
2558 *chainpp = inp + sizeof(wchar_t);
2561 *(spacep->wdata) = 0;
2562 return spacep->wdata;
2565 StringCchCopyNW(spacep->wdata,
2566 lengthof(spacep->wdata),
2567 (const clientchar_t *) inp, cch_src);
2570 *chainpp = inp + (cch_src + null_terms)*sizeof(wchar_t);
2572 return spacep->wdata;
2576 cm_space_t * spacep;
2579 /* Not using Unicode */
2581 *chainpp = inp + strlen(inp) + 1;
2584 spacep = cm_GetSpace();
2585 spacep->nextp = *stringspp;
2586 *stringspp = spacep;
2588 cchdest = lengthof(spacep->wdata);
2589 cm_Utf8ToUtf16(inp, *pcb_max, spacep->wdata, cchdest);
2591 return spacep->wdata;
2597 unsigned char * smb_UnparseString(smb_packet_t * pktp, unsigned char * outp,
2599 size_t * plen, int flags)
2605 /* we are only calculating the required size */
2612 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2614 StringCbLengthW(str, SMB_STRINGBUFSIZE * sizeof(wchar_t), plen);
2615 if (!(flags & SMB_STRF_IGNORENULL))
2616 *plen += sizeof(wchar_t);
2618 return (unsigned char *) 1; /* return TRUE if we are using unicode */
2628 cch_str = cm_ClientStrLen(str);
2629 cch_dest = cm_ClientStringToUtf8(str, cch_str, NULL, 0);
2632 *plen = ((flags & SMB_STRF_IGNORENULL)? cch_dest: cch_dest+1);
2640 /* if outp != NULL ... */
2642 /* Number of bytes left in the buffer.
2644 If outp lies inside the packet data buffer, we assume that the
2645 buffer is the packet data buffer. Otherwise we assume that the
2646 buffer is sizeof(packet->data).
2649 if (outp >= pktp->data && outp < pktp->data + sizeof(pktp->data)) {
2650 align = ((outp - pktp->data) % 2);
2651 buffersize = (pktp->data + sizeof(pktp->data)) - ((char *) outp);
2653 align = (((size_t) outp) % 2);
2654 buffersize = sizeof(pktp->data);
2659 if (WANTS_UNICODE(pktp) && !(flags & SMB_STRF_FORCEASCII)) {
2665 if (*str == _C('\0')) {
2667 if (buffersize < sizeof(wchar_t))
2670 *((wchar_t *) outp) = L'\0';
2671 if (plen && !(flags & SMB_STRF_IGNORENULL))
2672 *plen += sizeof(wchar_t);
2673 return outp + sizeof(wchar_t);
2676 nchars = cm_ClientStringToUtf16(str, -1, (wchar_t *) outp, buffersize / sizeof(wchar_t));
2678 osi_Log2(smb_logp, "UnparseString: Can't convert string to Unicode [%S], GLE=%d",
2679 osi_LogSaveClientString(smb_logp, str),
2685 *plen += sizeof(wchar_t) * ((flags & SMB_STRF_IGNORENULL)? nchars - 1: nchars);
2687 return outp + sizeof(wchar_t) * nchars;
2695 cch_dest = cm_ClientStringToUtf8(str, -1, outp, buffersize);
2698 *plen += ((flags & SMB_STRF_IGNORENULL)? cch_dest - 1: cch_dest);
2700 return outp + cch_dest;
2704 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
2710 tlen = inp[0] + (inp[1]<<8);
2711 inp += 2; /* skip length field */
2714 *chainpp = inp + tlen;
2723 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2727 if (*inp++ != 0x1) return NULL;
2728 tlen = inp[0] + (inp[1]<<8);
2729 inp += 2; /* skip length field */
2732 *chainpp = inp + tlen;
2735 if (lengthp) *lengthp = tlen;
2740 /* format a packet as a response */
2741 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
2746 outp = (smb_t *) op;
2748 /* zero the basic structure through the smb_wct field, and zero the data
2749 * size field, assuming that wct stays zero; otherwise, you have to
2750 * explicitly set the data size field, too.
2752 inSmbp = (smb_t *) inp;
2753 memset(outp, 0, sizeof(smb_t)+2);
2759 outp->com = inSmbp->com;
2760 outp->tid = inSmbp->tid;
2761 outp->pid = inSmbp->pid;
2762 outp->uid = inSmbp->uid;
2763 outp->mid = inSmbp->mid;
2764 outp->res[0] = inSmbp->res[0];
2765 outp->res[1] = inSmbp->res[1];
2766 op->inCom = inSmbp->com;
2768 outp->reb = SMB_FLAGS_SERVER_TO_CLIENT;
2769 #ifdef SEND_CANONICAL_PATHNAMES
2770 outp->reb |= SMB_FLAGS_CANONICAL_PATHNAMES;
2772 outp->flg2 = SMB_FLAGS2_KNOWS_LONG_NAMES;
2774 if ((vcp->flags & SMB_VCFLAG_USEUNICODE) == SMB_VCFLAG_USEUNICODE)
2775 outp->flg2 |= SMB_FLAGS2_UNICODE;
2778 /* copy fields in generic packet area */
2779 op->wctp = &outp->wct;
2782 /* send a (probably response) packet; vcp tells us to whom to send it.
2783 * we compute the length by looking at wct and bcc fields.
2785 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
2799 memset((char *)ncbp, 0, sizeof(NCB));
2801 extra = 2 * (*inp->wctp); /* space used by parms, in bytes */
2802 tp = inp->wctp + 1+ extra; /* points to count of data bytes */
2803 extra += tp[0] + (tp[1]<<8);
2804 extra += (unsigned int)(inp->wctp - inp->data); /* distance to last wct field */
2805 extra += 3; /* wct and length fields */
2807 ncbp->ncb_length = extra; /* bytes to send */
2808 ncbp->ncb_lsn = (unsigned char) vcp->lsn; /* vc to use */
2809 ncbp->ncb_lana_num = vcp->lana;
2810 ncbp->ncb_command = NCBSEND; /* op means send data */
2811 ncbp->ncb_buffer = (char *) inp;/* packet */
2812 code = Netbios(ncbp);
2815 const char * s = ncb_error_string(code);
2816 osi_Log2(smb_logp, "SendPacket failure code %d \"%s\"", code, s);
2817 LogEvent(EVENTLOG_WARNING_TYPE, MSG_SMB_SEND_PACKET_FAILURE, s);
2819 lock_ObtainMutex(&vcp->mx);
2820 if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
2821 osi_Log2(smb_logp, "marking dead vcp 0x%x, user struct 0x%x",
2823 vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2824 lock_ReleaseMutex(&vcp->mx);
2825 lock_ObtainWrite(&smb_globalLock);
2826 dead_sessions[vcp->session] = TRUE;
2827 lock_ReleaseWrite(&smb_globalLock);
2828 smb_CleanupDeadVC(vcp);
2830 lock_ReleaseMutex(&vcp->mx);
2838 void smb_MapNTError(long code, unsigned long *NTStatusp)
2840 unsigned long NTStatus;
2842 /* map CM_ERROR_* errors to NT 32-bit status codes */
2843 /* NT Status codes are listed in ntstatus.h not winerror.h */
2844 if (code == CM_ERROR_NOSUCHCELL) {
2845 NTStatus = 0xC000000FL; /* No such file */
2847 else if (code == CM_ERROR_NOSUCHVOLUME) {
2848 NTStatus = 0xC000000FL; /* No such file */
2850 else if (code == CM_ERROR_TIMEDOUT) {
2852 NTStatus = 0xC00000CFL; /* Sharing Paused */
2854 NTStatus = 0x00000102L; /* Timeout */
2857 else if (code == CM_ERROR_RETRY) {
2858 NTStatus = 0xC000022DL; /* Retry */
2860 else if (code == CM_ERROR_NOACCESS) {
2861 NTStatus = 0xC0000022L; /* Access denied */
2863 else if (code == CM_ERROR_READONLY) {
2864 NTStatus = 0xC00000A2L; /* Write protected */
2866 else if (code == CM_ERROR_NOSUCHFILE ||
2867 code == CM_ERROR_BPLUS_NOMATCH) {
2868 NTStatus = 0xC000000FL; /* No such file */
2870 else if (code == CM_ERROR_NOSUCHPATH) {
2871 NTStatus = 0xC000003AL; /* Object path not found */
2873 else if (code == CM_ERROR_TOOBIG) {
2874 NTStatus = 0xC000007BL; /* Invalid image format */
2876 else if (code == CM_ERROR_INVAL) {
2877 NTStatus = 0xC000000DL; /* Invalid parameter */
2879 else if (code == CM_ERROR_BADFD) {
2880 NTStatus = 0xC0000008L; /* Invalid handle */
2882 else if (code == CM_ERROR_BADFDOP) {
2883 NTStatus = 0xC0000022L; /* Access denied */
2885 else if (code == CM_ERROR_EXISTS) {
2886 NTStatus = 0xC0000035L; /* Object name collision */
2888 else if (code == CM_ERROR_NOTEMPTY) {
2889 NTStatus = 0xC0000101L; /* Directory not empty */
2891 else if (code == CM_ERROR_CROSSDEVLINK) {
2892 NTStatus = 0xC00000D4L; /* Not same device */
2894 else if (code == CM_ERROR_NOTDIR) {
2895 NTStatus = 0xC0000103L; /* Not a directory */
2897 else if (code == CM_ERROR_ISDIR) {
2898 NTStatus = 0xC00000BAL; /* File is a directory */
2900 else if (code == CM_ERROR_BADOP) {
2902 /* I have no idea where this comes from */
2903 NTStatus = 0xC09820FFL; /* SMB no support */
2905 NTStatus = 0xC00000BBL; /* Not supported */
2906 #endif /* COMMENT */
2908 else if (code == CM_ERROR_BADSHARENAME) {
2909 NTStatus = 0xC00000CCL; /* Bad network name */
2911 else if (code == CM_ERROR_NOIPC) {
2913 NTStatus = 0xC0000022L; /* Access Denied */
2915 NTStatus = 0xC000013DL; /* Remote Resources */
2918 else if (code == CM_ERROR_CLOCKSKEW) {
2919 NTStatus = 0xC0000133L; /* Time difference at DC */
2921 else if (code == CM_ERROR_BADTID) {
2922 NTStatus = 0xC0982005L; /* SMB bad TID */
2924 else if (code == CM_ERROR_USESTD) {
2925 NTStatus = 0xC09820FBL; /* SMB use standard */
2927 else if (code == CM_ERROR_QUOTA) {
2928 NTStatus = 0xC0000044L; /* Quota exceeded */
2930 else if (code == CM_ERROR_SPACE) {
2931 NTStatus = 0xC000007FL; /* Disk full */
2933 else if (code == CM_ERROR_ATSYS) {
2934 NTStatus = 0xC0000033L; /* Object name invalid */
2936 else if (code == CM_ERROR_BADNTFILENAME) {
2937 NTStatus = 0xC0000033L; /* Object name invalid */
2939 else if (code == CM_ERROR_WOULDBLOCK) {
2940 NTStatus = 0xC0000055L; /* Lock not granted */
2942 else if (code == CM_ERROR_SHARING_VIOLATION) {
2943 NTStatus = 0xC0000043L; /* Sharing violation */
2945 else if (code == CM_ERROR_LOCK_CONFLICT) {
2946 NTStatus = 0xC0000054L; /* Lock conflict */
2948 else if (code == CM_ERROR_PARTIALWRITE) {
2949 NTStatus = 0xC000007FL; /* Disk full */
2951 else if (code == CM_ERROR_BUFFERTOOSMALL) {
2952 NTStatus = 0xC0000023L; /* Buffer too small */
2954 else if (code == CM_ERROR_AMBIGUOUS_FILENAME) {
2955 NTStatus = 0xC0000035L; /* Object name collision */
2957 else if (code == CM_ERROR_BADPASSWORD) {
2958 NTStatus = 0xC000006DL; /* unknown username or bad password */
2960 else if (code == CM_ERROR_BADLOGONTYPE) {
2961 NTStatus = 0xC000015BL; /* logon type not granted */
2963 else if (code == CM_ERROR_GSSCONTINUE) {
2964 NTStatus = 0xC0000016L; /* more processing required */
2966 else if (code == CM_ERROR_TOO_MANY_SYMLINKS) {
2968 NTStatus = 0xC0000280L; /* reparse point not resolved */
2970 NTStatus = 0xC0000022L; /* Access Denied */
2973 else if (code == CM_ERROR_PATH_NOT_COVERED) {
2974 NTStatus = 0xC0000257L; /* Path Not Covered */
2976 else if (code == CM_ERROR_ALLBUSY) {
2977 NTStatus = 0xC000022DL; /* Retry */
2979 else if (code == CM_ERROR_ALLOFFLINE || code == CM_ERROR_ALLDOWN) {
2980 NTStatus = 0xC00000BEL; /* Bad Network Path */
2982 else if (code >= ERROR_TABLE_BASE_RXK && code < ERROR_TABLE_BASE_RXK + 256) {
2983 NTStatus = 0xC0000322L; /* No Kerberos key */
2985 else if (code == CM_ERROR_BAD_LEVEL) {
2986 NTStatus = 0xC0000148L; /* Invalid Level */
2988 else if (code == CM_ERROR_RANGE_NOT_LOCKED) {
2989 NTStatus = 0xC000007EL; /* Range Not Locked */
2991 else if (code == CM_ERROR_NOSUCHDEVICE) {
2992 NTStatus = 0xC000000EL; /* No Such Device */
2994 else if (code == CM_ERROR_LOCK_NOT_GRANTED) {
2995 NTStatus = 0xC0000055L; /* Lock Not Granted */
2997 NTStatus = 0xC0982001L; /* SMB non-specific error */
3000 *NTStatusp = NTStatus;
3001 osi_Log2(smb_logp, "SMB SEND code %lX as NT %lX", code, NTStatus);
3004 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
3005 unsigned char *classp)
3007 unsigned char class;
3008 unsigned short error;
3010 /* map CM_ERROR_* errors to SMB errors */
3011 if (code == CM_ERROR_NOSUCHCELL) {
3013 error = 3; /* bad path */
3015 else if (code == CM_ERROR_NOSUCHVOLUME) {
3017 error = 3; /* bad path */
3019 else if (code == CM_ERROR_TIMEDOUT) {
3021 error = 81; /* server is paused */
3023 else if (code == CM_ERROR_RETRY) {
3024 class = 2; /* shouldn't happen */
3027 else if (code == CM_ERROR_NOACCESS) {
3029 error = 4; /* bad access */
3031 else if (code == CM_ERROR_READONLY) {
3033 error = 19; /* read only */
3035 else if (code == CM_ERROR_NOSUCHFILE ||
3036 code == CM_ERROR_BPLUS_NOMATCH) {
3038 error = 2; /* ENOENT! */
3040 else if (code == CM_ERROR_NOSUCHPATH) {
3042 error = 3; /* Bad path */
3044 else if (code == CM_ERROR_TOOBIG) {
3046 error = 11; /* bad format */
3048 else if (code == CM_ERROR_INVAL) {
3049 class = 2; /* server non-specific error code */
3052 else if (code == CM_ERROR_BADFD) {
3054 error = 6; /* invalid file handle */
3056 else if (code == CM_ERROR_BADFDOP) {
3057 class = 1; /* invalid op on FD */
3060 else if (code == CM_ERROR_EXISTS) {
3062 error = 80; /* file already exists */
3064 else if (code == CM_ERROR_NOTEMPTY) {
3066 error = 5; /* delete directory not empty */
3068 else if (code == CM_ERROR_CROSSDEVLINK) {
3070 error = 17; /* EXDEV */
3072 else if (code == CM_ERROR_NOTDIR) {
3073 class = 1; /* bad path */
3076 else if (code == CM_ERROR_ISDIR) {
3077 class = 1; /* access denied; DOS doesn't have a good match */
3080 else if (code == CM_ERROR_BADOP) {
3084 else if (code == CM_ERROR_BADSHARENAME) {
3088 else if (code == CM_ERROR_NOIPC) {
3090 error = 4; /* bad access */
3092 else if (code == CM_ERROR_CLOCKSKEW) {
3093 class = 1; /* invalid function */
3096 else if (code == CM_ERROR_BADTID) {
3100 else if (code == CM_ERROR_USESTD) {
3104 else if (code == CM_ERROR_REMOTECONN) {
3108 else if (code == CM_ERROR_QUOTA) {
3109 if (vcp->flags & SMB_VCFLAG_USEV3) {
3111 error = 39; /* disk full */
3115 error = 5; /* access denied */
3118 else if (code == CM_ERROR_SPACE) {
3119 if (vcp->flags & SMB_VCFLAG_USEV3) {
3121 error = 39; /* disk full */
3125 error = 5; /* access denied */
3128 else if (code == CM_ERROR_PARTIALWRITE) {
3130 error = 39; /* disk full */
3132 else if (code == CM_ERROR_ATSYS) {
3134 error = 2; /* ENOENT */
3136 else if (code == CM_ERROR_WOULDBLOCK) {
3138 error = 33; /* lock conflict */
3140 else if (code == CM_ERROR_LOCK_CONFLICT) {
3142 error = 33; /* lock conflict */
3144 else if (code == CM_ERROR_SHARING_VIOLATION) {
3146 error = 33; /* lock conflict */
3148 else if (code == CM_ERROR_NOFILES) {
3150 error = 18; /* no files in search */
3152 else if (code == CM_ERROR_RENAME_IDENTICAL) {
3154 error = 183; /* Samba uses this */
3156 else if (code == CM_ERROR_BADPASSWORD || code == CM_ERROR_BADLOGONTYPE) {
3157 /* we don't have a good way of reporting CM_ERROR_BADLOGONTYPE */
3159 error = 2; /* bad password */
3161 else if (code == CM_ERROR_PATH_NOT_COVERED) {
3163 error = 3; /* bad path */
3172 osi_Log3(smb_logp, "SMB SEND code %lX as SMB %d: %d", code, class, error);
3175 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3177 osi_Log0(smb_logp,"SendCoreBadOp - NOT_SUPPORTED");
3178 return CM_ERROR_BADOP;
3182 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3184 unsigned short EchoCount, i;
3185 char *data, *outdata;
3188 EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
3190 for (i=1; i<=EchoCount; i++) {
3191 data = smb_GetSMBData(inp, &dataSize);
3192 smb_SetSMBParm(outp, 0, i);
3193 smb_SetSMBDataLength(outp, dataSize);
3194 outdata = smb_GetSMBData(outp, NULL);
3195 memcpy(outdata, data, dataSize);
3196 smb_SendPacket(vcp, outp);
3202 /* SMB_COM_READ_RAW */
3203 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3206 long count, minCount, finalCount;
3210 smb_t *smbp = (smb_t*) inp;
3212 cm_user_t *userp = NULL;
3215 char *rawBuf = NULL;
3220 fd = smb_GetSMBParm(inp, 0);
3221 count = smb_GetSMBParm(inp, 3);
3222 minCount = smb_GetSMBParm(inp, 4);
3223 offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3225 if (*inp->wctp == 10) {
3226 /* we were sent a request with 64-bit file offsets */
3227 #ifdef AFS_LARGEFILES
3228 offset.HighPart = smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16);
3230 if (LargeIntegerLessThanZero(offset)) {
3231 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received negative 64-bit offset");
3235 if ((smb_GetSMBParm(inp, 8) | (smb_GetSMBParm(inp, 9) << 16)) != 0) {
3236 osi_Log0(smb_logp, "smb_ReceiveCoreReadRaw received 64-bit file offset. Dropping request.");
3239 offset.HighPart = 0;
3243 /* we were sent a request with 32-bit file offsets */
3244 offset.HighPart = 0;
3247 osi_Log4(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x:%08x, size 0x%x",
3248 fd, offset.HighPart, offset.LowPart, count);
3250 fidp = smb_FindFID(vcp, fd, 0);
3254 if (fidp->scp && (fidp->scp->flags & CM_SCACHEFLAG_DELETED)) {
3255 smb_CloseFID(vcp, fidp, NULL, 0);
3256 code = CM_ERROR_NOSUCHFILE;
3263 LARGE_INTEGER LOffset, LLength;
3266 key = cm_GenerateKey(vcp->vcID, pid, fd);
3268 LOffset.HighPart = offset.HighPart;
3269 LOffset.LowPart = offset.LowPart;
3270 LLength.HighPart = 0;
3271 LLength.LowPart = count;
3273 lock_ObtainWrite(&fidp->scp->rw);
3274 code = cm_LockCheckRead(fidp->scp, LOffset, LLength, key);
3275 lock_ReleaseWrite(&fidp->scp->rw);
3281 lock_ObtainMutex(&smb_RawBufLock);
3283 /* Get a raw buf, from head of list */
3284 rawBuf = smb_RawBufs;
3285 smb_RawBufs = *(char **)smb_RawBufs;
3287 lock_ReleaseMutex(&smb_RawBufLock);
3291 lock_ObtainMutex(&fidp->mx);
3292 if (fidp->flags & SMB_FID_IOCTL)
3294 lock_ReleaseMutex(&fidp->mx);
3295 rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
3297 /* Give back raw buffer */
3298 lock_ObtainMutex(&smb_RawBufLock);
3299 *((char **) rawBuf) = smb_RawBufs;
3301 smb_RawBufs = rawBuf;
3302 lock_ReleaseMutex(&smb_RawBufLock);
3305 lock_ReleaseMutex(&fidp->mx);
3306 smb_ReleaseFID(fidp);
3309 lock_ReleaseMutex(&fidp->mx);
3311 userp = smb_GetUserFromVCP(vcp, inp);
3313 code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
3319 cm_ReleaseUser(userp);
3322 smb_ReleaseFID(fidp);
3326 memset((char *)ncbp, 0, sizeof(NCB));
3328 ncbp->ncb_length = (unsigned short) finalCount;
3329 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
3330 ncbp->ncb_lana_num = vcp->lana;
3331 ncbp->ncb_command = NCBSEND;
3332 ncbp->ncb_buffer = rawBuf;
3334 code = Netbios(ncbp);
3336 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
3339 /* Give back raw buffer */
3340 lock_ObtainMutex(&smb_RawBufLock);
3341 *((char **) rawBuf) = smb_RawBufs;
3343 smb_RawBufs = rawBuf;
3344 lock_ReleaseMutex(&smb_RawBufLock);
3350 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3352 osi_Log1(smb_logp, "SMB receive core lock record (not implemented); %d + 1 ongoing ops",
3357 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3359 osi_Log1(smb_logp, "SMB receive core unlock record (not implemented); %d + 1 ongoing ops",
3364 /* SMB_COM_NEGOTIATE */
3365 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3372 int VistaProtoIndex;
3373 int protoIndex; /* index we're using */
3378 char protocol_array[10][1024]; /* protocol signature of the client */
3379 int caps; /* capabilities */
3382 TIME_ZONE_INFORMATION tzi;
3384 osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
3387 namep = smb_GetSMBData(inp, &dbytes);
3390 coreProtoIndex = -1; /* not found */
3393 VistaProtoIndex = -1;
3394 while(namex < dbytes) {
3395 osi_Log1(smb_logp, "Protocol %s",
3396 osi_LogSaveString(smb_logp, namep+1));
3397 strcpy(protocol_array[tcounter], namep+1);
3399 /* namep points at the first protocol, or really, a 0x02
3400 * byte preceding the null-terminated ASCII name.
3402 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
3403 coreProtoIndex = tcounter;
3405 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
3406 v3ProtoIndex = tcounter;
3408 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
3409 NTProtoIndex = tcounter;
3411 else if (smb_useV3 && strcmp("SMB 2.001", namep+1) == 0) {
3412 VistaProtoIndex = tcounter;
3415 /* compute size of protocol entry */
3416 entryLength = (int)strlen(namep+1);
3417 entryLength += 2; /* 0x02 bytes and null termination */
3419 /* advance over this protocol entry */
3420 namex += entryLength;
3421 namep += entryLength;
3422 tcounter++; /* which proto entry we're looking at */
3425 lock_ObtainMutex(&vcp->mx);
3427 if (VistaProtoIndex != -1) {
3428 protoIndex = VistaProtoIndex;
3429 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3432 if (NTProtoIndex != -1) {
3433 protoIndex = NTProtoIndex;
3434 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
3436 else if (v3ProtoIndex != -1) {
3437 protoIndex = v3ProtoIndex;
3438 vcp->flags |= SMB_VCFLAG_USEV3;
3440 else if (coreProtoIndex != -1) {
3441 protoIndex = coreProtoIndex;
3442 vcp->flags |= SMB_VCFLAG_USECORE;
3444 else protoIndex = -1;
3445 lock_ReleaseMutex(&vcp->mx);
3447 if (protoIndex == -1)
3448 return CM_ERROR_INVAL;
3449 else if (VistaProtoIndex != 1 || NTProtoIndex != -1) {
3450 smb_SetSMBParm(outp, 0, protoIndex);
3451 if (smb_authType != SMB_AUTH_NONE) {
3452 smb_SetSMBParmByte(outp, 1,
3453 NEGOTIATE_SECURITY_USER_LEVEL |
3454 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3456 smb_SetSMBParmByte(outp, 1, 0); /* share level auth with plaintext password. */
3458 smb_SetSMBParm(outp, 1, smb_maxMpxRequests); /* max multiplexed requests */
3459 smb_SetSMBParm(outp, 2, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3460 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
3461 smb_SetSMBParmLong(outp, 5, SMB_MAXRAWSIZE); /* raw buffer size */
3462 /* The session key is not a well documented field however most clients
3463 * will echo back the session key to the server. Currently we are using
3464 * the same value for all sessions. We should generate a random value
3465 * and store it into the vcp
3467 smb_SetSMBParm(outp, 7, 1); /* next 2: session key */
3468 smb_SetSMBParm(outp, 8, 1);
3470 * Tried changing the capabilities to support for W2K - defect 117695
3471 * Maybe something else needs to be changed here?
3475 smb_SetSMBParmLong(outp, 9, 0x43fd);
3477 smb_SetSMBParmLong(outp, 9, 0x251);
3480 * 32-bit error codes *
3486 caps = NTNEGOTIATE_CAPABILITY_NTSTATUS |
3488 NTNEGOTIATE_CAPABILITY_DFS |
3490 #ifdef AFS_LARGEFILES
3491 NTNEGOTIATE_CAPABILITY_LARGEFILES |
3493 NTNEGOTIATE_CAPABILITY_NTFIND |
3494 NTNEGOTIATE_CAPABILITY_RAWMODE |
3495 NTNEGOTIATE_CAPABILITY_NTSMB;
3497 if ( smb_authType == SMB_AUTH_EXTENDED )
3498 caps |= NTNEGOTIATE_CAPABILITY_EXTENDED_SECURITY;
3501 if ( smb_UseUnicode ) {
3502 caps |= NTNEGOTIATE_CAPABILITY_UNICODE;
3506 smb_SetSMBParmLong(outp, 9, caps);
3508 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3509 smb_SetSMBParmLong(outp, 11, LOWORD(dosTime));/* server time */
3510 smb_SetSMBParmLong(outp, 13, HIWORD(dosTime));/* server date */
3512 GetTimeZoneInformation(&tzi);
3513 smb_SetSMBParm(outp, 15, (unsigned short) tzi.Bias); /* server tzone */
3515 if (smb_authType == SMB_AUTH_NTLM) {
3516 smb_SetSMBParmByte(outp, 16, MSV1_0_CHALLENGE_LENGTH);/* Encryption key length */
3517 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength);
3518 /* paste in encryption key */
3519 datap = smb_GetSMBData(outp, NULL);
3520 memcpy(datap,vcp->encKey,MSV1_0_CHALLENGE_LENGTH);
3521 /* and the faux domain name */
3522 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3523 datap + MSV1_0_CHALLENGE_LENGTH,
3524 sizeof(outp->data)/sizeof(char) - (datap - outp->data));
3525 } else if ( smb_authType == SMB_AUTH_EXTENDED ) {
3529 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3531 smb_NegotiateExtendedSecurity(&secBlob, &secBlobLength);
3533 smb_SetSMBDataLength(outp, secBlobLength + sizeof(smb_ServerGUID));
3535 datap = smb_GetSMBData(outp, NULL);
3536 memcpy(datap, &smb_ServerGUID, sizeof(smb_ServerGUID));
3539 datap += sizeof(smb_ServerGUID);
3540 memcpy(datap, secBlob, secBlobLength);
3544 smb_SetSMBParmByte(outp, 16, 0); /* Encryption key length */
3545 smb_SetSMBDataLength(outp, 0); /* Perhaps we should specify 8 bytes anyway */
3548 else if (v3ProtoIndex != -1) {
3549 smb_SetSMBParm(outp, 0, protoIndex);
3551 /* NOTE: Extended authentication cannot be negotiated with v3
3552 * therefore we fail over to NTLM
3554 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3555 smb_SetSMBParm(outp, 1,
3556 NEGOTIATE_SECURITY_USER_LEVEL |
3557 NEGOTIATE_SECURITY_CHALLENGE_RESPONSE); /* user level security, challenge response */
3559 smb_SetSMBParm(outp, 1, 0); /* share level auth with clear password */
3561 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
3562 smb_SetSMBParm(outp, 3, smb_maxMpxRequests); /* max multiplexed requests */
3563 smb_SetSMBParm(outp, 4, smb_maxVCPerServer); /* max VCs per consumer/server connection */
3564 smb_SetSMBParm(outp, 5, 0); /* no support of block mode for read or write */
3565 smb_SetSMBParm(outp, 6, 1); /* next 2: session key */
3566 smb_SetSMBParm(outp, 7, 1);
3568 smb_SearchTimeFromUnixTime(&dosTime, unixTime);
3569 smb_SetSMBParm(outp, 8, LOWORD(dosTime)); /* server time */
3570 smb_SetSMBParm(outp, 9, HIWORD(dosTime)); /* server date */
3572 GetTimeZoneInformation(&tzi);
3573 smb_SetSMBParm(outp, 10, (unsigned short) tzi.Bias); /* server tzone */
3575 /* NOTE: Extended authentication cannot be negotiated with v3
3576 * therefore we fail over to NTLM
3578 if (smb_authType == SMB_AUTH_NTLM || smb_authType == SMB_AUTH_EXTENDED) {
3579 smb_SetSMBParm(outp, 11, MSV1_0_CHALLENGE_LENGTH); /* encryption key length */
3580 smb_SetSMBParm(outp, 12, 0); /* resvd */
3581 smb_SetSMBDataLength(outp, MSV1_0_CHALLENGE_LENGTH + smb_ServerDomainNameLength); /* perhaps should specify 8 bytes anyway */
3582 datap = smb_GetSMBData(outp, NULL);
3583 /* paste in a new encryption key */
3584 memcpy(datap, vcp->encKey, MSV1_0_CHALLENGE_LENGTH);
3585 /* and the faux domain name */
3586 cm_ClientStringToUtf8(smb_ServerDomainName, -1,
3587 datap + MSV1_0_CHALLENGE_LENGTH,
3588 sizeof(outp->data)/sizeof(char) - (datap - outp->data));
3590 smb_SetSMBParm(outp, 11, 0); /* encryption key length */
3591 smb_SetSMBParm(outp, 12, 0); /* resvd */
3592 smb_SetSMBDataLength(outp, 0);
3595 else if (coreProtoIndex != -1) { /* not really supported anymore */
3596 smb_SetSMBParm(outp, 0, protoIndex);
3597 smb_SetSMBDataLength(outp, 0);
3602 void smb_CheckVCs(void)
3604 smb_vc_t * vcp, *nextp;
3605 smb_packet_t * outp = GetPacket();
3608 lock_ObtainWrite(&smb_rctLock);
3609 for ( vcp=smb_allVCsp, nextp=NULL; vcp; vcp = nextp )
3611 if (vcp->magic != SMB_VC_MAGIC)
3612 osi_panic("afsd: invalid smb_vc_t detected in smb_allVCsp",
3613 __FILE__, __LINE__);
3617 if (vcp->flags & SMB_VCFLAG_ALREADYDEAD)
3620 smb_HoldVCNoLock(vcp);
3622 smb_HoldVCNoLock(nextp);
3623 smb_FormatResponsePacket(vcp, NULL, outp);
3624 smbp = (smb_t *)outp;
3625 outp->inCom = smbp->com = 0x2b /* Echo */;
3633 smb_SetSMBParm(outp, 0, 0);
3634 smb_SetSMBDataLength(outp, 0);
3635 lock_ReleaseWrite(&smb_rctLock);
3637 smb_SendPacket(vcp, outp);
3639 lock_ObtainWrite(&smb_rctLock);
3640 smb_ReleaseVCNoLock(vcp);
3642 smb_ReleaseVCNoLock(nextp);
3644 lock_ReleaseWrite(&smb_rctLock);
3645 smb_FreePacket(outp);
3648 void smb_Daemon(void *parmp)
3650 afs_uint32 count = 0;
3651 smb_username_t **unpp;
3654 while(smbShutdownFlag == 0) {
3658 if (smbShutdownFlag == 1)
3661 if ((count % 72) == 0) { /* every five minutes */
3663 time_t old_localZero = smb_localZero;
3665 /* Initialize smb_localZero */
3666 myTime.tm_isdst = -1; /* compute whether on DST or not */
3667 myTime.tm_year = 70;
3673 smb_localZero = mktime(&myTime);
3675 #ifndef USE_NUMERIC_TIME_CONV
3676 smb_CalculateNowTZ();
3677 #endif /* USE_NUMERIC_TIME_CONV */
3678 #ifdef AFS_FREELANCE
3679 if ( smb_localZero != old_localZero )
3680 cm_noteLocalMountPointChange();
3686 /* GC smb_username_t objects that will no longer be used */
3688 lock_ObtainWrite(&smb_rctLock);
3689 for ( unpp=&usernamesp; *unpp; ) {
3691 smb_username_t *unp;
3693 lock_ObtainMutex(&(*unpp)->mx);
3694 if ( (*unpp)->refCount > 0 ||
3695 ((*unpp)->flags & SMB_USERNAMEFLAG_AFSLOGON) ||
3696 !((*unpp)->flags & SMB_USERNAMEFLAG_LOGOFF))
3698 else if (!smb_LogoffTokenTransfer ||
3699 ((*unpp)->last_logoff_t + smb_LogoffTransferTimeout < now))
3701 lock_ReleaseMutex(&(*unpp)->mx);
3709 lock_FinalizeMutex(&unp->mx);
3715 cm_ReleaseUser(userp);
3717 unpp = &(*unpp)->nextp;
3720 lock_ReleaseWrite(&smb_rctLock);
3722 /* XXX GC dir search entries */
<